Django:CreateView中的查询和计算

时间:2017-10-16 11:32:41

标签: python django calculation create-view

我对Django比较新,所以我不确定我能问的是什么。

我正在建立一个网站,其功能可以评估用户并撰写评论。我有用户模型(具有平均评分字段)和评论模型(包含authoruser_profilegradereview字段。我正在使用CreateView进行评论。

我正在尝试执行以下操作:

  1. 进行查询以获取该人的所有以前成绩(来自Reviews模型)。

  2. 进行计算(将所有以前的成绩相加,添加新成绩以及所有除以成绩的数量(包括新成绩))

  3. 将新的平均成绩保存到UserProfile型号

  4. 将评论保存到Reviews模型

  5. 将用户重定向到当前详细信息视图

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

    urlpatterns的:

    [...
        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")
    ...
    ]
    

3 个答案:

答案 0 :(得分: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在需要时计算平均值。

答案 1 :(得分: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

以下是信号接收器的示例,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

答案 2 :(得分:0)

我认为这里的最佳解决方案是使用django signals

结果你分开了视图和域逻辑,你的计算将在每次更改后应用(不仅仅是视图中的更改)

此外,如果您的计算需要花费大量时间,您可以轻松地在异步作业中移动此功能(例如celery