Django:CreateView内部的查询和计算
Django: Queries and calculations inside CreateView
我对 Django 比较陌生,所以我不确定我问的问题是否可行。
我正在建立一个网站,该网站具有对用户进行评分和撰写评论的功能。我有用户模型(具有平均评分字段)和评论模型(具有 author
、user_profile
、grade
和 review
字段)。我正在使用 CreateView
进行评论。
我正在尝试执行以下操作:
进行查询以获取该人以前的所有成绩(来自 Reviews
模型)。
进行计算(将所有以前的成绩相加,加上新成绩和所有除以成绩数(包括新成绩))
将新的平均成绩保存到 UserProfile
模型
将评论保存到 Reviews
模型
将用户重定向到当前详细信息视图
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-Based-View 中是可能的) :
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")
...
]
您可以在调用 super()
之后计算新的平均值,然后再 return 响应。
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
来计算平均值。
我认为最好的解决方案是使用 django signals
因此,您将视图和域逻辑分开,您的计算将在每次更改后应用(不仅是视图的更改)
此外,如果您的计算会花费大量时间,您可以轻松地将此功能移动到异步作业中(例如 celery)
对于您想做的事情,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
我对 Django 比较陌生,所以我不确定我问的问题是否可行。
我正在建立一个网站,该网站具有对用户进行评分和撰写评论的功能。我有用户模型(具有平均评分字段)和评论模型(具有 author
、user_profile
、grade
和 review
字段)。我正在使用 CreateView
进行评论。
我正在尝试执行以下操作:
进行查询以获取该人以前的所有成绩(来自
Reviews
模型)。进行计算(将所有以前的成绩相加,加上新成绩和所有除以成绩数(包括新成绩))
将新的平均成绩保存到
UserProfile
模型将评论保存到
Reviews
模型将用户重定向到当前详细信息视图
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-Based-View 中是可能的) :
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")
...
]
您可以在调用 super()
之后计算新的平均值,然后再 return 响应。
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
来计算平均值。
我认为最好的解决方案是使用 django signals
因此,您将视图和域逻辑分开,您的计算将在每次更改后应用(不仅是视图的更改)
此外,如果您的计算会花费大量时间,您可以轻松地将此功能移动到异步作业中(例如 celery)
对于您想做的事情,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