0

我对 Django 比较陌生,所以我不确定我要问的是否可行。

我正在建立一个网站,该网站具有对用户进行评分和撰写评论的功能。我有用户模型(具有平均评分字段)和评论模型(具有、 和author字段user_profile)。我用来做评论。gradereviewCreateView

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

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

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

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

  4. 将评论保存到Reviews模型

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

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

3 回答 3

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在需要时使用它们来计算平均值。

于 2017-10-16T11:44:00.863 回答
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

于 2017-10-16T11:46:25.463 回答
0

我认为这里最好的解决方案是使用django 信号

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

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

于 2017-10-16T11:44:41.573 回答