我有以下型号:
class Pizza(models.Model):
toppings = models.ManyToManyField(Topping)
has_toppings = models.BooleanField(default=False)
def check_if_there_are_toppings(self):
if len(self.toppings.all()) > 0:
self.has_toppings = True
@receiver(m2m_changed, sender=Pizza.toppings.through)
def toppings_changed(sender, instance, **kwargs):
instance.check_if_there_are_toppings()
instance.save()
我想做的是只要has_toppings
长度大于0时更新toppings
字段。这样做的正确方法是什么?感谢您的帮助。
答案 0 :(得分:1)
您可以通过调用以下命令来简单地检查浇头的数量:
is_empty = instance.toppings.all().count() == 0
is_empty
将具有False
,如果浇头超过0,则True
,如果没有浇头。
希望,它会有所帮助。
答案 1 :(得分:1)
我认为这样做可能不是一个好主意。多对多关系如何变化可能有很多原因。覆盖所有这些将非常困难,甚至不可能。例如,Topping
对象本身可以被删除,并因此触发使用浇头的所有多对多关系的更改。此外,Django ORM具有诸如.bulk_create(..)
[Django-doc]和.update(..)
[Django-doc]之类的某些功能,可以绕过Django的信号机制,因此可以使数据库处于不一致的状态。因此,仅删除has_toppings
字段可能更有意义:
class Pizza(models.Model):
toppings = models.ManyToManyField(Topping)
# no has_toppings
仅注释您的Pizza
查询集可能更有意义。例如:
from django.db.models import Exists, OuterRef
Pizza.objects.annotate(
has_toppings=Exists(
Pizza.toppings.through.objects.filter(pizza_id=OuterRef('pk'))
)
)
这将生成如下查询:
SELECT pizza.id,
EXISTS(
SELECT U0.id, U0.pizza_id, U0.topping_id
FROM pizza_toppings U0
WHERE U0.pizza_id = pizza.id
) AS has_toppings
FROM pizza
您可以通过设置管理员来访问Pizza.objects
时使用此查询集:
from django.db.models import Exists, OuterRef
class PizzaManager(models.Manager):
def get_queryset(self):
return Pizza.objects.annotate(
has_toppings=Exists(
Pizza.toppings.through.objects.filter(pizza_id=OuterRef('pk'))
)
)
class Topping(models.Model):
pass
class Pizza(models.Model):
toppings = models.ManyToManyField(Topping)
objects = PizzaManager()
因此,我们现在可以例如检索具有以下内容的所有Pizza
:
Pizza.objects.filter(has_toppings=True)