我有许多可以是一种或多种类型的元素。
class Type(models.Model):
name = models.CharField(max_length=128, unique=True)
class Element(models.Model):
name = models.CharField(max_length=128, unique=True)
type = models.ManyToManyField('Type')
假设我有3种类型和3种元素:
In [3]: Type.objects.all()
Out[3]: [<Type: His Type>, <Type: My Type>, <Type: Your Type>]
In [4]: [(e,e.type.all()) for e in Element.objects.all()]
Out[4]:
[(<Element: First Element>, [<Type: My Type>]),
(<Element: Second Element>, [<Type: Your Type>]),
(<Element: Third Element>,
[<Type: My Type>, <Type: Your Type>, <Type: His Type>])]
我正在尝试使用仅属于“My Type”类型的元素的查询集
我的想法是获取此类型的元素,并检查它们只是一种类型。
但由于某种原因,它认为“第三元素”只有一种类型
In [5]: my_type=Type.objects.get(name='My Type')
In [6]: my_type.element_set.annotate(num_types=Count('type')).filter(num_types__exact=1)
Out[6]: [<Element: First Element>, <Element: Third Element>]
In [7]: [(e,e.num_types) for e in my_type.element_set.annotate(num_types=Count('type'))]
Out[7]: [(<Element: First Element>, 1), (<Element: Third Element>, 1)]
当它有三种类型时
In [8]: Element.objects.get(name='Third Element').type.count()
Out[8]: 3
我做错了什么?
答案 0 :(得分:0)
鉴于这是标准的多对多,您可以调用'my_type.element_set.all()',它应该为您提供该类型的Element实例。您也可以采用其他方式(使用模型名称的复数版本,而不是'_set')来获取类似的元素类型:'my_element.types.all()'。
要获得计数,只需执行'my_type.element_set.count()'。
答案 1 :(得分:0)
Django在幕后执行的SQL查询将您限制为仅包含type_element_type.element_id = 1
的行。因此,带注释的计数仅适用于那些,因此每个都有1个。
上面的查询[7]变成了这个SQL(如this所示):
SELECT "type_element"."id", "type_element"."name", COUNT("type_element_type"."type_id")
AS "num_types" FROM "type_element" LEFT OUTER JOIN "type_element_type"
ON ("type_element"."id" = "type_element_type"."element_id")
WHERE "type_element_type"."type_id" = 1
GROUP BY "type_element"."id", "type_element"."name"
和sqlite3:
sqlite> SELECT * FROM "type_element" LEFT OUTER JOIN "type_element_type" ON ("type_element"."id" = "type_element_type"."element_id") WHERE "type_element_type"."type_id" = 1;
1|First Element|1|1|1
3|Third Element|3|3|1
答案 2 :(得分:0)
我结束了
Element.objects.filter(pk__in=my_type.element_set.values_list('pk', flat=True)).annotate(num_types=Count('type')).filter(num_types=1)
这样,当我从my_type.element_set
如果您想知道所涉及的SQL:
在my_type.element_set.annotate(num_types=Count('type')).filter(num_types__exact=1)
它确实:
SELECT `senalesweb_element`.`id`, `senalesweb_element`.`name`, COUNT(`senalesweb_element_type`.`type_id`) AS `num_types` FROM `senalesweb_element` LEFT OUTER JOIN `senalesweb_element_type` ON (`senalesweb_element`.`id` = `senalesweb_element_type`.`element_id`) WHERE (`senalesweb_element_type`.`type_id` = 1 ) GROUP BY `senalesweb_element`.`id` HAVING COUNT(`senalesweb_element_type`.`type_id`) = 1 ORDER BY NULL LIMIT 21
在Element.objects.filter(pk__in=my_type.element_set.values_list('pk', flat=True)).annotate(num_types=Count('type')).filter(num_types=1)
中,它确实:
SELECT `senalesweb_element`.`id`, `senalesweb_element`.`name`, COUNT(`senalesweb_element_type`.`type_id`) AS `num_types` FROM `senalesweb_element` LEFT OUTER JOIN `senalesweb_element_type` ON (`senalesweb_element`.`id` = `senalesweb_element_type`.`element_id`) WHERE (`senalesweb_element`.`id` IN (SELECT U0.`id` FROM `senalesweb_element` U0 INNER JOIN `senalesweb_element_type` U1 ON (U0.`id` = U1.`element_id`) WHERE U1.`type_id` = 1 )) GROUP BY `senalesweb_element`.`id` HAVING COUNT(`senalesweb_element_type`.`type_id`) = 1 ORDER BY NULL LIMIT 21