Как обновить поле модели на основе другой модели в Django?

У меня есть две модели в Django.

Один для продуктов, а другой - для рейтингов.

Модель продукта:

class Product(models.Model):
    ...
    product_name = models.CharField(max_length=264, blank=False, verbose_name='Product Name')
    product_slug = models.SlugField(blank=True)
   
    avg_rating = models.IntegerField(blank=True, null=True, verbose_name='Average Rating', help_text='Do not Edit!')
    total_rating_count = models.IntegerField(blank=True, null=True, verbose_name='Total Rating', help_text='Do not Edit!')

    def save(self, *args, **kwargs):
        ...
        super(Product, self).save(*args, **kwargs)

    def __str__(self):
        return self.product_name

Рейтинговая модель:

class Rating(models.Model):
    product = models.ForeignKey(Product, on_delete=models.CASCADE, related_name='product_ratings')
    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='user_rating')
    product_rating = models.IntegerField(verbose_name='Rating', blank=False)
    product_comment = models.TextField(verbose_name='Comment', blank=False)

Я хочу сделать так: когда пользователь оценивает продукт, я хочу обновить avg_rating и total_rating_count в модели Product.

Как я могу это сделать? Спасибо.

Повторяя слова Виллема, я бы удалил эти поля и вычислил их следующим образом:

from django.db.models import Avg

class Product(models.Model):
    ...
    product_name = models.CharField(max_length=264, blank=False, verbose_name='Product Name')
    product_slug = models.SlugField(blank=True)

    @property
    def avg_rating(self):
        return self.product_ratings.all().aggregate(Avg('product_rating'))['product_rating__avg']

    @property
    def total_rating_count(self):
        return self.product_ratings.all().count()

Затем вы можете получить доступ к этой информации, как к любому другому атрибуту:

product = Product.objects.first()
product.avg_rating

Я бы рассмотрел возможность использования cached_property по соображениям производительности.

Вернуться на верх