【问题标题】:django filter on many to many - set__id__in not doing exactdjango 过滤多对多 - set__id__in 不准确
【发布时间】:2014-07-17 00:31:25
【问题描述】:

我有模型:

ModelA, Conversation  

class ModelA:
     conversations = models.ManyToManyField(Conversation)  

我想检索与 id 为 1、2、3 对话的 ModelA 的记录(比如说)。

我试过这个:

ModelA.objects.filter(conversations__id__in=[1,2,3])  

但这并不是在做精确过滤。如果记录 A 只有一个 id 为 1 的对话,记录 B 只有一个 id 为 2 的对话,记录 C 有 3 个 id 为 1,2,3 的对话,然后上面的代码返回所有 3 条记录。但是,我只想检索记录 C,因为只有具有所有对话 1、2、3 的记录。

我需要确切的或可能的子集。我的意思是,如果我搜索 [1,2] 则记录 A,B 不应该出现,但记录 C 可以出现([1,2] 是 [1,2,3] 的子集)

如果不清楚请告诉我。

【问题讨论】:

    标签: django


    【解决方案1】:

    参考Query using contains each value in list,您可以在这里使用in 字段查找来做同样的事情:

    from django.db.models import Q
    ModelA.objects.filter(reduce(operator.and_, (Q(conversations__id=x) for x in [1,2,3])))
    
    # the above is equivalent to:
    ModelA.objects.filter(Q(conversations__id=1) &
                          Q(conversations__id=2) &
                          Q(conversations__id=3))
    

    【讨论】:

    • 如果只有一个值,我认为没有必要使用__in 查找。此外 - 这可能是一个无效的查询。Q(conversation__id=1) & ...) 应该足够了。
    • @yedpodtrzitko 是的,将代码更改为使用conversation__id=x。此外,尽管reduce() 可能会产生一些开销,但它允许传入动态生成的列表([1,2,3] 只是一个示例)。因此,像reduce(operator.and_, (Q(conversations__id=x) for x in id_list) 这样的东西现在是可能的。
    【解决方案2】:

    您需要链接查询以找到至少具有 1、2 和 3 的查询。

    ModelA.objects.filter(conversations=1).filter(conversations=2).filter(conversations=3)
    

    我很久以前就回答过这样一个问题,但仍然相关: How to do many-to-many Django query to find book with 2 given authors?

    至于您的最后一条评论,[1] 是 [1, 2] 的子集,所以我不太确定您尝试过滤的逻辑是什么。一个子集,但是是 2 个元素的最小子集?

    【讨论】:

    • 它不是关于 2 个元素,当我搜索 1,2 时,这两个元素都存在于 1,2,3 中。这就是我所说的子集。当然,如果你觉得它没有意义,那就离开吧。
    猜你喜欢
    • 1970-01-01
    • 2020-05-27
    • 2011-01-14
    • 1970-01-01
    • 2016-06-19
    • 2018-06-07
    • 2012-09-26
    • 2015-07-18
    • 2020-06-18
    相关资源
    最近更新 更多