2017-10-16 16 views
0

나는 비교적 장고를 처음 사용하기 때문에 가능한지 묻는다면 확실하지 않습니다.Django : CreateView 내부의 쿼리 및 계산

나는 사용자를 평가하고 리뷰를 작성하는 기능이있는 웹 사이트를 구축 중입니다. 나는 사용자를위한 모델 (평균 등급 필드가 있음)과 리뷰 모델 (author, user_profile, gradereview)을 가지고 있습니다. 리뷰 작성에 CreateView을 사용하고 있습니다.

나는 다음을 수행하려고 :

  1. 이 (Reviews 모델에서) 그 사람의 모든 이전의 성적을 얻기 위해 쿼리를 만들려면.

  2. 계산

  3. 저장 새 평균 등급 모델

  4. 저장 검토 UserProfile에 (() 새 학년을 포함한 모든 이전의 성적을 합산 등급의 수에 의해 새로운 하나 모든 것을 나누기를 추가) 확인 현재 상세보기로

  5. 리디렉션 사용자 모델 Reviews

Models.py

views.py에서
class UserProfile(models.Model): 
    ... 
    avg_grade = models.FloatField(blank=True, null=True) 
    ... 

class Reviews(models.Model): 
    user_profile = models.ForeignKey(UserProfile, on_delete=models.CASCADE) 
    grade = models.PositiveIntegerField() 
    review = models.CharField(max_length=256, null=True, blank=True) 
    author = models.CharField(max_length=256) 

나는 새로운 평균 등급에 대한 계산을 할 경우 확실하지 해당 사용자의 등급의 쿼리를 만들기 위해 관리하지만, (이 안에 가능한 경우 클래스 기반-보기)

class CreateReview(LoginRequiredMixin, CreateView): 
    form_class = Forma_recenzije 
    success_url = reverse_lazy('detail') 
    template_name = 'accounts/recenzija.html' 

    def get_queryset(self): 
     u = UserProfile.objects.get(id=int(self.kwargs['pk'])) 
     return Reviews.objects.filter(user_profile=u) 

    def form_valid(self, form): 
     form.instance.author = self.request.user 
     form.instance.user_profile = UserProfile.objects.get(id=int(self.kwargs['pk'])) 
     return super(CreateReview, self).form_valid(form) 

urlpatterns : 당신이 super()이라고 일단 당신이 반환하기 전에

[... 
    url(r'^dadilje/(?P<pk>[-\w]+)/$', views.DadiljaDetailView.as_view(), name="detail"), 
    url(r'^dadilje/(?P<pk>[-\w]+)/recenzija$', views. CreateReview.as_view(), name="recenzije") 
... 
] 

답변

1

당신은, 새로운 평균을 계산할 수 있습니다 응답.

def form_valid(self, form): 
    form.instance.author = self.request.user 
    user_profile = UserProfile.objects.get(id=int(self.kwargs['pk'])) 
    form.instance.user_profile = user_profile` 
    response = super(CreateReview, self).form_valid(form) 
    avg_grade = Review.objects.filter(user_profile=user_profile).aggregate(Avg('grade'))['grade__avg'] 
    user_profile.avg_grade = avg_grade 
    user_profile.save() 
    return response 

또는, super()를 호출하면 열심히 무슨 일이 일어나고 있는지 볼 수 있습니다 것을 발견하면, 당신은 명시 적으로 양식을 구할 수 대신 리디렉션 : 당신이를 저장할 필요가 없을 수도 있습니다

def form_valid(self, form): 
    form.instance.author = self.request.user 
    user_profile = UserProfile.objects.get(id=int(self.kwargs['pk'])) 
    form.instance.user_profile = user_profile` 
    review = form.save() 
    avg_grade = Review.objects.filter(user_profile=user_profile).aggregate(Avg('grade'))['grade__avg'] 
    user_profile.avg_grade = avg_grade 
    user_profile.save() 
    return HttpResponseRedirect(self.success_url) 

주 사용자 프로필의 avg_grade - annotate을 사용하여 필요할 때 평균을 계산할 수 있습니다.

+0

UserProfile 모델을 저장하는 대신 annotate를 사용하여 제안하는 방법에 대해 투표했습니다. 계산 된 값을 저장하는 것은 조숙 한 최적화 일 수 있습니다. 사용자가 매우 많은 수의 리뷰 (DB 스펙에 따라 수십만 + 이상)를 갖지 않는 한, 주석이 충분히 잘 수행 될 것입니다. –

+0

고마워, 그게 내가 찾고 있던거야. 내가 모델을주고 같은 이름을 보았 기 때문에 나는 그것을 작동시키는 데 몇 가지 문제점을 가지고 있었다. 주석 접근 방식을 알고 이전에 사용했지만 이제는 order_by() 메서드를 사용하여 해당 데이터를 정렬 할 수 있기를 원하며 더 이상 사용할 수 없게됩니다. –

+0

주석이 달린 필드에서 주문할 수 있습니다. 예, 모델 및보기에 동일한 이름을 사용하지 마십시오. 단 하나의 모델명 (예 :'Review' 대신에'Review')을 사용하는 것이 좋습니다. (이 경우'Review'는 실제 모델 이름의 번역입니다.) – Alasdair

0

여기 가장 좋은 방법은 당신이보기 및 도메인 로직을 분리하여 계산이 변경 될 때마다 (보기에서뿐만 아니라 변경) 귀하의 계산이 걸릴 것입니다 경우에도

후 적용 결과 django signals

로를 사용하여 생각 많은 시간 동안 비동기 작업에서이 기능을 쉽게 옮길 수 있습니다 (예 : celery)

+0

고맙습니다. 신호를 사용하는 것이 bennefits를 가지고 있음을 이해합니다. 그러나 지금은 내 지식 수준 이상입니다. 나는 그들에 대해 확실히 읽고 잘하면 내 미래의 프로젝트에서 그들을 사용합니다. –

+1

"이제는 결코 좋지 않습니다."- (c) Python의 Zen)) –

1

Django는 듣고 싶은 신호를 가지고 있습니다.

예를 들어 UserProfile이 저장된 시간을 수신하여 해당 프로필과 관련된 캐시 키를 지우는 기능을 가질 수 있습니다.

이러한 기능은 일반적으로 앱 내에 signals.py에 추가되거나 모델을 정의한 후에는 models.py 개의 파일에 추가됩니다.

신호가 모델 뒤에로드되어야하므로 signals.py을 사용하는 경향이 있습니다. apps.py; 여기

class MyAppConfig(AppConfig): 
    """App config for the members app. """ 
    name = 'my app' 
    verbose_name = _("My App") 

    def ready(self): 
     """ Import signals once the app is ready """ 
     # pylint: disable=W0612 
     import myapp.signals # noqa 

는이 시점에서 당신의 CALCS를 실행할 수 있도록 pre_save은 객체가 저장되기 직전에 발생, 신호 수신기의 예;

@receiver(pre_save, sender=UserProfile) 
def userprofile_pre_save(sender, instance, **kwargs): 
    """ 
    Calc avg score 
    """ 
    reviews = Reviews.objects.filter(user_profile=instance).aggregate(Avg('grade')) 

    instance.avg_grade = reviews['grade_avg'] 

수신자가 Review 변경을 원할 수도 있지만 위의 예는 쉬운 예입니다 !!

django를 처음 접한다면 약간 복잡 할 수도 있지만 이것을 읽으십시오. https://simpleisbetterthancomplex.com/tutorial/2016/07/28/how-to-create-django-signals.html

+0

고마워! 내가이 문제를 해결하는 방법을 찾을 때 나는 장고 신호에 대해 알았다. 불행히도, 이것은 내 지식 수준 이상이므로이 솔루션을 생각해 봅니다. 나는 신호에 대해 더 많은 것을 배우고 미래의 프로젝트에서 그것들을 사용하기를 희망한다. –