【发布时间】:2020-12-08 19:33:18
【问题描述】:
阅读django docs on order_by 后,有一条注释/警告(如果我理解正确的话)说:
- 如果您使用多值字段对查询集进行排序,则该查询集中具有多个相关项的每个元素都将多次添加到由
order_by创建的结果查询集中。
我尝试用一个基本示例对此进行测试:
最小可重现示例
class Pizza(models.Model):
name = models.CharField(max_length=100)
toppings = models.ManyToManyField('Topping', through='PizzaToppings')
class PizzaToppings(models.Model):
pizza = models.ForeignKey('Pizza', on_delete=models.CASCADE, related_name="pizza_toppings")
topping = models.ForeignKey('Topping', on_delete=models.CASCADE, related_name="pizzas_with_topping")
amount = models.IntegerField()
class Meta:
ordering = ["amount",]
class Topping(models.Model):
ingredient = models.CharField(max_length=100)
然后
>>> p1 = Pizza.objects.create(name="Cheese and Tomato")
>>> p2 = Pizza.objects.create(name="Pepperoni")
>>> cheese = Topping.objects.create(ingredient="Cheese")
>>> tomato = Topping.objects.create(ingredient="Tomato puree")
>>> p1.toppings.add(cheese, through_defaults={"amount":4})
>>> p1.toppings.add(tomato, through_defaults={"amount":3})
>>> p2.toppings.add(cheese, through_defaults={"amount":2})
>>> p2.toppings.add(tomato, through_defaults={"amount":1})
到目前为止,一切正常。但这就是事情变得令人困惑的地方:
>>> q1 = Topping.objects.all()
<QuerySet [<Topping: Topping object (1)>, <Topping: Topping object (2)>]>
>>> q2 = p1.toppings.all()
<QuerySet [<Topping: Topping object (1)>, <Topping: Topping object (2)>]>
>>> q1.order_by("pizzas_with_topping")
<QuerySet [<Topping: Topping object (2)>, <Topping: Topping object (1)>, <Topping: Topping object (2)>, <Topping: Topping object (1)>]>
>>> q2.order_by("pizzas_with_topping")
<QuerySet [<Topping: Topping object (2)>, <Topping: Topping object (1)>]>
问题
从上面可以看出,查询集在它们包含的元素方面是相同的。但是,当订购一个q1 时,我们会得到文档中描述的行为。在q2 中,我们没有这种行为。这大概是因为 django 正在做一些聪明的事情,因为查询集关注的是与 p1 相关的浇头。
问题
实际上在“幕后”发生了什么来强制执行这种行为?查询集是相同的(如果我理解正确的话),那么为什么 order_by 对两个查询集的行为不同。
【问题讨论】:
-
如果您按顺序订购,则为
q1创建一个JOIN,这将因此加入PizzaToppings。对于后者,querset is 由于过滤已经加入,因此您消除了 JOIN 中的某些行。
标签: django many-to-many manytomanyfield