【问题标题】:How do I do an OR filter in a Django query?如何在 Django 查询中进行 OR 过滤?
【发布时间】:2010-10-18 21:27:45
【问题描述】:

我希望能够列出用户添加的项目(他们被列为创建者)或项目已被批准。

所以我基本上需要选择:

item.creator = owner or item.moderated = False

我将如何在 Django 中执行此操作? (最好使用过滤器或查询集)。

【问题讨论】:

    标签: django django-queryset


    【解决方案1】:

    Q 对象允许进行复杂的查找。示例:

    from django.db.models import Q
    
    Item.objects.filter(Q(creator=owner) | Q(moderated=False))
    

    【讨论】:

    • 如何以编程方式完成?因此,例如能够拥有for f in filters: Item.objects.filter(Q(creator=f1) | Q(creator=f2) | ...)
    • @AlexisK 使用 reduce(lambda q, f: q | Q(creator=f), filters, Q()) 之类的东西来创建大 Q 对象。
    • @alexis:例如,您也可以使用Item.objects.filter(creator__in=creators)
    • 如果你想知道(像我一样)| 被用作 OR 运算符的来源,它实际上是集合联合运算符。它也被用作(不在此处)按位或:stackoverflow.com/questions/5988665/pipe-character-in-python
    【解决方案2】:

    您可以使用 |运算符直接组合查询集而不需要 Q 对象:

    result = Item.objects.filter(item.creator = owner) | Item.objects.filter(item.moderated = False)
    

    (编辑 - 我最初不确定这是否会导致额外的查询,但 @spookylukey 指出惰性查询集评估会解决这个问题)

    【讨论】:

    • 要找出在给定请求上执行了哪些查询,您可以使用调试工具栏 Django 应用程序。它由真棒和胜利组成。
    • 执行“从 django.db 导入连接”并使用“connection.queries”。这需要 DEBUG=True。顺便说一句,你应该知道 QuerySets are lazy 并且这只会命中数据库一次。
    • 能否将 exclude 用于否定比较?
    • 这会导致结果查询集中出现重复吗?
    • 更具体地说,查询集只有在您尝试对其进行索引时才会访问数据库,否则您只是在构建查询。
    【解决方案3】:

    你想让过滤器动态化,那么你必须像使用 Lambda 一样

    from django.db.models import Q
    
    brands = ['ABC','DEF' , 'GHI']
    
    queryset = Product.objects.filter(reduce(lambda x, y: x | y, [Q(brand=item) for item in brands]))
    

    reduce(lambda x, y: x | y, [Q(brand=item) for item in brands]) 等价于

    Q(brand=brands[0]) | Q(brand=brands[1]) | Q(brand=brands[2]) | .....
    

    【讨论】:

    • 对我来说完美的答案!对于 python3,请事先执行from functools import reduce
    • 为什么不使用operator.or_ 而不是lambda x, y: x | y
    【解决方案4】:

    类似于旧答案,但更简单,没有 lambda...

    使用OR过滤这两个条件:

    Item.objects.filter(Q(field_a=123) | Q(field_b__in=(3, 4, 5, ))
    

    以编程方式获得相同的结果:

    filter_kwargs = {
        'field_a': 123,
        'field_b__in': (3, 4, 5, ),
    }
    list_of_Q = [Q(**{key: val}) for key, val in filter_kwargs.items()]
    Item.objects.filter(reduce(operator.or_, list_of_Q))
    

    operator 在标准库中:import operator
    来自文档字符串:

    or_(a, b) -- 同a | b.

    对于 Python3,reduce 不再是内置函数,但仍在标准库中:from functools import reduce


    附言

    不要忘记确保 list_of_Q 不为空 - reduce() 会在空列表中阻塞,它至少需要一个元素。

    【讨论】:

      【解决方案5】:

      【讨论】:

        【解决方案6】:

        值得注意的是,可以添加Q表达式。

        例如:

        from django.db.models import Q
        
        query = Q(first_name='mark')
        query.add(Q(email='mark@test.com'), Q.OR)
        query.add(Q(last_name='doe'), Q.AND)
        
        queryset = User.objects.filter(query)
        

        这会以如下查询结束:

        (first_name = 'mark' or email = 'mark@test.com') and last_name = 'doe'
        

        这样就不需要处理操作符、reduce等

        【讨论】:

        • 但是写query |= Q(email='mark@test.com')比较容易?
        • @Alex78191,不同的人有不同的编码风格偏好,但除此之外,这种用法允许将运算符(Q.ORQ.AND)作为参数提供给可能需要的函数处理这两种情况。
        【解决方案7】:
        Item.objects.filter(field_name__startswith='yourkeyword')
        

        【讨论】:

        • 请在您的答案中添加一些解释,以便其他人可以从中学习
        【解决方案8】:

        有多种方法。

        1.直接使用管道 |运算符。

        from django.db.models import Q
        
        Items.objects.filter(Q(field1=value) | Q(field2=value))
        
        

        2。使用__or__ 方法。

        Items.objects.filter(Q(field1=value).__or__(field2=value))
        

        3.通过更改默认操作。 (注意重置默认行为)

        Q.default = Q.OR # Not recommended (Q.AND is default behaviour)
        Items.objects.filter(Q(field1=value, field2=value))
        Q.default = Q.AND # Reset after use.
        

        4.通过使用Q 类参数_connector

        logic = Q(field1=value, field2=value, field3=value, _connector=Q.OR)
        Item.objects.filter(logic)
        

        Q 实施快照

        class Q(tree.Node):
            """
            Encapsulate filters as objects that can then be combined logically (using
            `&` and `|`).
            """
            # Connection types
            AND = 'AND'
            OR = 'OR'
            default = AND
            conditional = True
        
            def __init__(self, *args, _connector=None, _negated=False, **kwargs):
                super().__init__(children=[*args, *sorted(kwargs.items())], connector=_connector, negated=_negated)
        
            def _combine(self, other, conn):
                if not(isinstance(other, Q) or getattr(other, 'conditional', False) is True):
                    raise TypeError(other)
        
                if not self:
                    return other.copy() if hasattr(other, 'copy') else copy.copy(other)
                elif isinstance(other, Q) and not other:
                    _, args, kwargs = self.deconstruct()
                    return type(self)(*args, **kwargs)
        
                obj = type(self)()
                obj.connector = conn
                obj.add(self, conn)
                obj.add(other, conn)
                return obj
        
            def __or__(self, other):
                return self._combine(other, self.OR)
        
            def __and__(self, other):
                return self._combine(other, self.AND)
            .............
        

        参考。 Q implementation

        【讨论】:

        • 对选项 +1 的非常好的概述
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2010-10-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-05-02
        相关资源
        最近更新 更多