2017-10-16 96 views
0

我相對較新的Django,所以我不知道如果我問的可能。Django:查詢和計算裏面CreateView

我正在構建一個功能的網站,爲用戶評分和寫評論。我有用戶模型(具有平均評級字段)和評論模型(字段爲author,user_profile,gradereview)。我正在使用CreateView進行評論。

我努力做到以下幾點:

  1. 要查詢來獲取該人的所有以前的等級(從Reviews模型)。

  2. 進行計算(和所有以前的成績,通過等級的數量增加了新的,所有的鴻溝(包括新等級))

  3. 保存新的平均檔次UserProfile模型

  4. 儲存檢閱到Reviews模型

  5. 重定向用戶對當前細節視圖

Models.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) 

views.py我設法讓用戶的成績查詢,但不知道從哪裏新的平均品位做計算(如果這是可能的內部基於類 - 視圖):

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) 

URL模式:

[... 
    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

可以計算出新的平均一旦你叫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` 
    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模型來存儲它。存儲該計算值可能是不成熟的優化。除非用戶有大量評論(數十萬+取決於數據庫規範),否則評註可能表現不錯。 –

+0

謝謝,這就是我一直在尋找和它的作品。我遇到了一些問題,因爲我給了模型並查看了相同的名稱。 我知道註釋方法並在之前使用它,但現在我希望能夠使用order_by()方法對數據進行排序,並且無法再使用它。 –

+0

您*可以*在註釋字段上訂購。是的,我會避免在模型和視圖中使用相同的名稱。建議在模型名稱中使用單數(例如'Review'而不是'Reviews'(我在這種情況下意識到'Review'是您的實際型號名稱的翻譯) – Alasdair

0

我覺得這裏最好的解決辦法是使用django signals

至於導致你分開視圖和域邏輯和每一個變化(不僅在視圖中進行更改)

此外,如果你的計算將採取後您的計算將應用很多時候你可以很容易地在異步作業中移動這個功能(例如celery

+0

謝謝,我明白使用信號有好處,但現在它們超過了我的知識水平,我一定會閱讀它們,並希望在未來的項目中使用它們。 –

+1

「現在比從未好」 - (c)Python的禪)) –

1

對於你想做的事情Django有你可以聽的信號。

作爲一個例子,您可以有一個函數,用於偵聽保存的UserProfile何時清除與該配置文件相關的緩存鍵。

在您定義模型後,通常會在您的應用程序或models.py文件中將這些功能添加到signals.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 

這裏有一個信號接收器的一個例子,pre_save發生在保存對象之前,所以你可以運行在這一點上Calcs(計算);

@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

謝謝!當我搜索如何解決這個問題時,我發現了Django信號。不幸的是,這超出了我的知識水平,所以我想到了這個解決方案。我肯定會更多地瞭解信號,並希望在未來的項目中使用它們。 –