![](/img/trans.png)
[英]Django: How to update the field of another model during object creation
[英]Django - How to update a field for a model on another model's creation?
我有兩個模型,一個產品模型和一個評級模型。 我想要完成的是,每次創建“評級”時,通過API POST到使用DRF創建的端點,我都想計算和更新關聯產品中的average_rating
字段。
class Product(models.Model):
name = models.CharField(max_length=100)
...
average_rating = models.DecimalField(max_digits=3, decimal_places=2)
def __str__(self):
return self.name
class Rating(models.Model):
rating = models.IntegerField()
product = models.ForeignKey('Product', related_name='ratings')
def __str__(self):
return "{}".format(self.rating)
做這個的最好方式是什么? 我是否使用post_save
(創建后發布?)信號?
做這個的最好方式是什么? 我是否使用post_save(創建后發布?)信號?
我想這里的問題不在於如何從技術上做到這一點,而更多的是如何使它健壯 。 畢竟,創建重要的評分不僅是重要的:如果人們更改了評分或刪除了評分,那么平均評分也需要更新。 甚至有可能使用級聯定義ForeignKey
,然后刪除與Rating
相關的內容可能會導致刪除多個Rating
,從而更新了幾個Product
。 因此,使平均同步變得相當困難。 尤其是如果您允許其他程序操縱數據庫。
因此,計算平均評分可能會更好。 例如,使用匯總:
from django.db.models import Avg
class Product(models.Model):
name = models.CharField(max_length=100)
@property
def average_rating(self):
return self.ratings.aggregate(average_rating=Avg('rating'))['average_rating']
def __str__(self):
return self.name
或者,如果要在QuerySet
加載多個Product
,則可以執行.annotate(..)
來批量計算平均評分:
Product.objects.annotate(
average_rating=Avg('rating__rating')
)
在這里, Product
的屬性average_rating
是相關評分的平均評分。
如果收視率的數量巨大,則可能需要花費大量時間來計算平均值。 在這種情況下,我建議添加一個字段,並使用定期任務來更新評分。 例如:
from django.db.models import Avg, OuterRef, Subquery
class Product(models.Model):
name = models.CharField(max_length=100)
avg_rating=models.DecimalField(
max_digits=3,
decimal_places=2,
null=True,
default=None
)
@property
def average_rating(self):
return self.avg_rating or self.ratings.aggregate(average_rating=Avg('rating'))['average_rating']
@classmethod
def update_averages(cls):
subq = cls.objects.filter(
id=OuterRef('id')
).annotate(
avg=Avg('rating__rating')
).values('avg')[:1]
cls.objects.update(
avg_rating=Subquery(subq)
)
def __str__(self):
return self.name
然后,您可以定期調用Product.update_averages()
來更新所有產品的平均評分。 如果您創建,更新或刪除評級,則可以將相關產品的avg_rating
字段設置為None
以強制重新計算,例如使用post_save
等。但是請注意,信號可以post_save
(例如與.update(..)
一個查詢集的,或者通過bulk_create(..)
因此,它仍然是一個好主意,定期同步的平均評分。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.