猿问

Django过滤查询集__in为列表中的* every *项

Django过滤查询集__in为列表中的* every *项

假设我有以下型号

class Photo(models.Model):
    tags = models.ManyToManyField(Tag)class Tag(models.Model):
    name = models.CharField(max_length=50)

在视图中,我有一个列表,其中包含名为categories的活动过滤器。我想过滤具有类别中所有标签的Photo对象。

我试过了:

Photo.objects.filter(tags__name__in=categories)

但这匹配类别中的任何项目,而不是所有项目。

因此,如果类别是['假日','夏天'],我希望照片有假日和夏季标签。

这可以实现吗?


阿晨1998
浏览 1590回答 3
3回答

千万里不及你

摘要:正如jpic和sgallen在评论中所建议的那样,一个选项是.filter()为每个类别添加。每个附加项都会filter添加更多联接,这对于一小组类别来说应该不是问题。有聚合&nbsp;方法。对于大量类别,此查询将更短并且可能更快。您还可以选择使用自定义查询。一些例子测试设置:class&nbsp;Photo(models.Model): &nbsp;&nbsp;&nbsp;&nbsp;tags&nbsp;=&nbsp;models.ManyToManyField('Tag')class&nbsp;Tag(models.Model): &nbsp;&nbsp;&nbsp;&nbsp;name&nbsp;=&nbsp;models.CharField(max_length=50) &nbsp;&nbsp;&nbsp;&nbsp;def&nbsp;__unicode__(self): &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;self.nameIn&nbsp;[2]:&nbsp;t1&nbsp;=&nbsp;Tag.objects.create(name='holiday')In&nbsp;[3]:&nbsp;t2&nbsp;=&nbsp;Tag.objects.create(name='summer')In&nbsp;[4]:&nbsp;p&nbsp;=&nbsp;Photo.objects.create()In&nbsp;[5]:&nbsp;p.tags.add(t1)In&nbsp;[6]:&nbsp;p.tags.add(t2)In&nbsp;[7]:&nbsp;p.tags.all()Out[7]:&nbsp;[<Tag:&nbsp;holiday>,&nbsp;<Tag:&nbsp;summer>]使用链式过滤器方法:In&nbsp;[8]:&nbsp;Photo.objects.filter(tags=t1).filter(tags=t2)Out[8]:&nbsp;[<Photo:&nbsp;Photo&nbsp;object>]结果查询:In&nbsp;[17]:&nbsp;print&nbsp;Photo.objects.filter(tags=t1).filter(tags=t2).query SELECT&nbsp;"test_photo"."id"FROM&nbsp;"test_photo"INNER&nbsp;JOIN&nbsp;"test_photo_tags"&nbsp;ON&nbsp;("test_photo"."id"&nbsp;=&nbsp;"test_photo_tags"."photo_id")INNER&nbsp;JOIN&nbsp;"test_photo_tags"&nbsp;T4&nbsp;ON&nbsp;("test_photo"."id"&nbsp;=&nbsp;T4."photo_id")WHERE&nbsp;("test_photo_tags"."tag_id"&nbsp;=&nbsp;3&nbsp;&nbsp;AND&nbsp;T4."tag_id"&nbsp;=&nbsp;4&nbsp;)请注意,每个都会为查询filter添加更多内容JOINS。使用注释&nbsp;方法:In&nbsp;[29]:&nbsp;from&nbsp;django.db.models&nbsp;import&nbsp;CountIn&nbsp;[30]:&nbsp;Photo.objects.filter(tags__in=[t1,&nbsp;t2]).annotate(num_tags=Count('tags')).filter(num_tags=2)Out[30]:&nbsp;[<Photo:&nbsp;Photo&nbsp;object>]结果查询:In&nbsp;[32]:&nbsp;print&nbsp;Photo.objects.filter(tags__in=[t1,&nbsp;t2]).annotate(num_tags=Count('tags')).filter(num_tags=2).query SELECT&nbsp;"test_photo"."id",&nbsp;COUNT("test_photo_tags"."tag_id")&nbsp;AS&nbsp;"num_tags"FROM&nbsp;"test_photo"LEFT&nbsp;OUTER&nbsp;JOIN&nbsp;"test_photo_tags"&nbsp;ON&nbsp;("test_photo"."id"&nbsp;=&nbsp;"test_photo_tags"."photo_id")WHERE&nbsp;("test_photo_tags"."tag_id"&nbsp;IN&nbsp;(3,&nbsp;4))GROUP&nbsp;BY&nbsp;"test_photo"."id",&nbsp;"test_photo"."id"HAVING&nbsp;COUNT("test_photo_tags"."tag_id")&nbsp;=&nbsp;2ANDed&nbsp;Q对象不起作用:In&nbsp;[9]:&nbsp;from&nbsp;django.db.models&nbsp;import&nbsp;QIn&nbsp;[10]:&nbsp;Photo.objects.filter(Q(tags__name='holiday')&nbsp;&&nbsp;Q(tags__name='summer'))Out[10]:&nbsp;[]In&nbsp;[11]:&nbsp;from&nbsp;operator&nbsp;import&nbsp;and_In&nbsp;[12]:&nbsp;Photo.objects.filter(reduce(and_,&nbsp;[Q(tags__name='holiday'),&nbsp;Q(tags__name='summer')]))Out[12]:&nbsp;[]结果查询:In&nbsp;[25]:&nbsp;print&nbsp;Photo.objects.filter(Q(tags__name='holiday')&nbsp;&&nbsp;Q(tags__name='summer')).query SELECT&nbsp;"test_photo"."id"FROM&nbsp;"test_photo"INNER&nbsp;JOIN&nbsp;"test_photo_tags"&nbsp;ON&nbsp;("test_photo"."id"&nbsp;=&nbsp;"test_photo_tags"."photo_id")INNER&nbsp;JOIN&nbsp;"test_tag"&nbsp;ON&nbsp;("test_photo_tags"."tag_id"&nbsp;=&nbsp;"test_tag"."id")WHERE&nbsp;("test_tag"."name"&nbsp;=&nbsp;holiday&nbsp;&nbsp;AND&nbsp;"test_tag"."name"&nbsp;=&nbsp;summer&nbsp;)

holdtom

另一种有效的方法,虽然只有PostgreSQL,但它正在使用django.contrib.postgres.fields.ArrayField:从docs复制的示例:>>> Post.objects.create(name='First post', tags=['thoughts', 'django'])>>> Post.objects.create(name='Second post', tags=['thoughts'])>>> Post.objects.create(name='Third post', tags=['tutorial', 'django'])>>> Post.objects.filter(tags__contains=['thoughts'])<QuerySet [<Post: First post>, <Post: Second post>]>>>> Post.objects.filter(tags__contains=['django'])<QuerySet [<Post: First post>, <Post: Third post>]>>>> Post.objects.filter(tags__contains=['django', 'thoughts'])<QuerySet [<Post: First post>]>ArrayField有一些更强大的功能,如重叠和索引转换。

浮云间

这也可以通过使用Django ORM和一些Python魔法的动态查询生成来完成:)from&nbsp;operator&nbsp;import&nbsp;and_from&nbsp;django.db.models&nbsp;import&nbsp;Q categories&nbsp;=&nbsp;['holiday',&nbsp;'summer']res&nbsp;=&nbsp;Photo.filter(reduce(and_,&nbsp;[Q(tags__name=c)&nbsp;for&nbsp;c&nbsp;in&nbsp;categories]))我们的想法是为每个类别生成适当的Q对象,然后使用AND运算符将它们组合到一个QuerySet中。例如,你的例子就等于res&nbsp;=&nbsp;Photo.filter(Q(tags__name='holiday')&nbsp;&&nbsp;Q(tags__name='summer'))
随时随地看视频慕课网APP
我要回答