如何在Django中实现对ManyToMany关系的动态AND组合查询

问题描述 投票:0回答:2

我有两个简单的模型。让我们说标签和帖子。它们看起来像这样(简化):

class Tag(models.Model):
    name = models.CharField(max_length=255, blank=False, unique=True)

class Post(models.Model):
    title = models.CharField(max_length=255, blank=False, default='')
    tags = models.ManyToManyField(Tag)

因此,每个标签可以分配到n个帖子,反之亦然。

我正在尝试获取所有帖子的列表,其中分配了任何给定标签,或者分配了所有给定标签。

所以基本上我想要OR或AND组合。

OR非常简单。在我看来我做(假设“标签”是标签对象的列表)

queryset = Post.objects.filter(tags__in=tags)

但我无法弄清楚如何为AND组合做到这一点。我要么得到任何东西,要么与OR一样。我尝试了很多不同的东西,但在我的场景中没有任何效果,我有一个动态的标签列表来过滤。

我最有希望的方法看起来像这样:

filter = [Q(tags=tag) for tag in tags if tag.enabled == True]
qs = Post.objects.all()
qs = qs.filter(reduce(operator.__and__, filter))

这仍然返回一个空列表。是的,我100%确定我有Post记录,并为其分配了两个请求的标签。

我究竟做错了什么?

python django
2个回答
1
投票

好的,答案是,像往常一样,相对简单:

qs = Post.objects.all()
for tag in tags:
    qs = qs.filter(tags=tag)

0
投票

为了实现所需的过滤器,我们可以这样做:

wanted_tags = [tag_1, tag_2, tag_3,...]

# To keep it as lean as possible, we first minimise our search space by filtering solely the posts with the amount of tags in the first place:
preprocessed_posts = Post.objects.annotate(c=Count('tags')).filter(c=len(wanted_tags))

# Now comes the somewhat pythonic part, which is simple but feels kinda hacky:
for tag in wanted_tags:
    preprocessed_posts.filter(tags=tag)

# now preprocessed_posts contains the wanted entities
wanted_posts = preprocessed_posts
© www.soinside.com 2019 - 2024. All rights reserved.