Как сделать автообновление категории по количеству товаров в модели django
У меня есть модель категории с заголовком и подсчетом, и у меня также есть другая модель под названием Products, которая имеет категорию в качестве одного из своих внешних ключей. Как я могу автоматически обновить поле category count по количеству продуктов, относящихся к той же категории?
class Category(models.Model):
title = models.CharField(max_length = 20)
count = models.IntegerFIeld()
class Product(models.Model):
title = models.CharField(max_length = 20)
category = models.ForeignKey(Category, on_delete = models.CASCADE)
Вы можете либо переопределить метод сохранения, либо написать сигнал для автоматического обновления поля, т.е.:
class Category(models.Model):
def save(self, *args, **kwargs):
self.count = self.product_set.count()
super().save(*args, **kwargs)
или с помощью сигналов:
from django.dispatch import receiver
@receiver(post_save, sender=Category)
def category_post_save(sender, instance, *args, **kwargs):
instance.count = instance.product_set.count()
instance.save()
Но я бы посоветовал вам использовать расчетное property
:
class Category(models.Model):
...
@property
def count(self):
return self.product_set.count()
Если вы хотите сохранить поле count
, я рекомендую вам использовать signals. На модели post_signal
Productpre_signal
следует использовать и (для получения предыдущей категории из запроса).
Вот сигналы:
@receiver(signals.pre_save, sender=Product)
def product_pre_save_signal(sender, instance, *args, **kwargs):
if instance.id:
previous_instance = Product.objects.get(id=instance.id)
if previous_instance.category != instance.category:
instance.previous_category = previous_instance.category
@receiver(signals.post_save, sender=Product)
def product_post_save_signal(sender, instance, created, *args, **kwargs):
if not created:
if hasattr(instance, "previous_category"):
if instance.previous_category:
instance.previous_category.count -= 1
instance.previous_category.save()
if instance.category:
instance.category.count += 1
instance.category.save()
else:
if instance.category:
instance.category.count += 1
instance.category.save()
Другая рекомендация для этой ситуации - сделать поле доступным только для чтения (добавить editable=False
к объявлению поля), чтобы никто не мог редактировать его из админки Django или сериализатора.
Но Я настоятельно рекомендую убрать поле, потому что трудно синхронизировать это поле с таблицей Product, поэтому вычисляйте значение каждый раз.
У вас может быть практически любой запрос, связанный с полем count
над Категорией или Продуктом, так что не беспокойтесь:)