【问题标题】:Django Filter ManyToManyField QuerysetDjango过滤ManyToManyField查询集
【发布时间】:2016-07-19 00:49:43
【问题描述】:

我有一个有点棘手的问题(我想)

我有一个名为 Post(models.Model) 的模型:具有称为共享的多对多关系

class Post(models.Model):
    account = models.ForeignKey(Account, related_name="account")
    shares = models.ManyToManyField(Account, related_name="shares_account", through='Share')
    ...

class Share(models.Model):
    post = models.ForeignKey(Post)
    account = models.ForeignKey(Account)

    new = models.BooleanField(default=True)
    ...

现在我需要一种方法来过滤具有确切“x”份额的帖子......例如。我有一个 ID 为“222”的帖子,此帖子与帐户 ID 12、13、16 共享。现在我想过滤与帐户 ID 12、13 和 16 共享的所有帖子。

我该怎么做? 我的糟糕尝试是这样的:: ;)

posts = Post.objects.filter(reduce(and_, [Q(shares=aid) for aid in account_ids]))

【问题讨论】:

  • 您需要与“x”个帐户共享的那些帖子(即计数等于 x),或者您想要那些专门与包含帐户 ID 12 的帐户共享的帖子,仅 13 和 16 或 12,13,16 及更多,但必须包含 12,13 和 16。?
  • 哦 .. 抱歉 ... 只有 12,3 和 16 的帐户 ..,如果有更多,它将是另一个组 .. .. 所以总是确切的一些份额跨度>

标签: django filter many-to-many


【解决方案1】:

我想这应该适合你。

   Post.objects.annotate(cc=Count('shares')).filter(cc=3).filter(Q(shares__id=12) & Q(shares__id=13) & Q(shares__id=16))

看到这个 -> Django ManyToMany filtering by set size or member in the set

【讨论】:

  • 不能让它工作..这里是简单的版本.. >>> Post.objects.filter(Q(shares__id=13) & Q(shares__id=12)) [] > >> [s.id for s in Post.objects.get(id=2308).shares.all()] [13, 12]
  • 返回 [] ...但如果我调用共享 12,13 的帖子 .. 那么它会显示一个带有 ID 的列表
  • 但我想如果您不包含计数过滤器,那么您的结果将包含那些将与帐户 ID 12、13、16 等共享的帖子,因为您查询正在过滤那些帖子与 12,13 和 16 共享。它不会在任何地方过滤掉那些只有这三个帐户的帖子。
  • 我的意思是显然你可以得到与 12,13 和 16 共享的所有帖子的列表,然后遍历它们,然后仅将那些与恰好三个帐户共享的帖子存储在另一个列表中,但它不是做你想要实现的最有效的方式。
  • OP 不应该寻找 12、13、 16 的共享 ID?为什么单个对象会有 3 个不同的 ID?
【解决方案2】:

这是用reduce实现它的方法

post_qs = Post.objects.all()
post_qs = reduce(lambda posts, share: posts.filter(shares=share), account_ids, post_qs)

我可能会以这种方式使其更可重用:

class PostQuerySet(models.QuerySet):

    def having_shares(self, share_ids):
        return reduce(lambda posts, share: posts.filter(shares=share), share_ids, self)

class Post(models.Model):
    ...

    objects = PostQuerySet.as_manager(


#usage
posts = Post.objects.all().having_shares(share_ids)

【讨论】:

    猜你喜欢
    • 2014-06-12
    • 2010-11-30
    • 1970-01-01
    • 1970-01-01
    • 2020-08-22
    • 2019-04-15
    • 2011-09-29
    相关资源
    最近更新 更多