nax*_*n35 8 python django many-to-many django-orm django-queryset
有没有办法查询具有多对多字段的子集或超集包含?
假设每个人都有他们想要看到的鸟类列表,每个鸟类都有一个鸟类列表.对于给定的Person实例,我如何进行查询以查找哪些Aviaries拥有该人员列表中的每只鸟?同样,对于给定的Person实例,我如何找到哪个Aviary 在该人员列表中只有鸟类(但不一定是所有鸟类).
这是我的Django 1.5型号:
class Bird(models.Model):
name = models.CharField(max_length=255, unique=True)
class Aviary(models.Model):
name = models.CharField(max_length=255, unique=True)
birds = models.ManyToManyField(Bird)
class Person(models.Model):
name = models.CharField(max_length=255, unique=True)
birds_to_see = models.ManyToManyField(Bird)
Run Code Online (Sandbox Code Playgroud)
我知道如何找到至少有一个人的鸟类的鸟舍,但我不知道我会如何适应这里.(例如,参见: django queryset for many-to-many field)
如果有一个查询可以满足我的需求,我也有兴趣知道是否/为什么更加"手动"这样做更可取.例如,我可以遍历鸟舍,提取每个鸟舍的鸟类列表,并查看该人的bird_to_see是鸟舍鸟类列表的子集或超集:
def find_aviaries(self):
person_birds = set(self.birds_to_see.all())
found_aviaries = []
for aviary in Aviary.objects.all():
aviary_birds = set(aviary.birds.all())
if person_birds.issubset(aviary_birds):
found_aviaries.append(aviary)
return found_aviaries
Run Code Online (Sandbox Code Playgroud)
任何帮助表示赞赏!
对于Django >= 2.0存在一个很好的解决方案。可以通过匹配鸟的数量来注释鸟舍,并过滤与至少一只鸟或所需数量匹配的鸟舍。
from django.db.models import Count
...
person_birds = set(self.birds_to_see.all())
aviaries = (
Aviary.objects
.annotate(bird_match_count=Count('birds', filter=Q(birds__in=person_birds)))
.filter(bird_match_count__gt=0)
)
Run Code Online (Sandbox Code Playgroud)
然后,在Python中过滤新查询集bird_match_count=len(person_birds)或过滤原始查询集或按bird_match_count对其进行排序就很简单了。
Django < 2.0 需要引用中介模型AviaryBirds并且会更加冗长。
通过读取SQL验证:
>>> print(aviaries.query)
SELECT aviary.id, aviary.name,
COUNT(CASE WHEN aviary_birds.bird_id IN (1,..) THEN aviary_birds.bird_id ELSE NULL END)
AS bird_match_count
FROM aviary LEFT OUTER JOIN aviary_birds ON (aviary.id = aviary_birds.aviary_id)
GROUP BY aviary.id, aviary.name
HAVING
COUNT(CASE WHEN (aviary_birds.bird_id IN (1,..)) THEN aviary_birds.bird_id ELSE NULL END)
> 0
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
452 次 |
| 最近记录: |