• django---ORM之Q查询


    filter 等方法中的关键字参数查询都是一起进行“AND” 的。 如果你需要执行更复杂的查询(例如OR 语句),你可以使用Q对象

    调用Q

    from django.db.models import Q

    Q 对象可以使用c&(AND)|(OR)操作符组合起来。

    当一个操作符在两个Q 对象上使用时,它产生一个新的Q 对象。

    Q(question__startswith='Who') | Q(question__startswith='What')

    等同于SQL语句

    WHERE question LIKE 'Who%' OR question LIKE 'What%'

    如果一个查询函数有多个Q 对象参数(逗号隔开的),这些参数的逻辑关系为“AND"。示例:

    Poll.objects.get(
        Q(question__startswith='Who'),
        Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6))
    )
    
    #等同于下列SQL语句:
    SELECT * from polls WHERE question LIKE 'Who%'
        AND (pub_date = '2005-05-02' OR pub_date = '2005-05-06')

    Q 对象可以使用~ 操作符取反,这允许组合正常的查询和取反(NOT) 查询:

    Q(question__startswith='Who') | ~Q(pub_date__year=2005)

    查询函数可以混合使用Q对象和关键字参数。所有提供给查询函数的参数(关键字参数或Q 对象)都将"AND”在一起。但是,如果出现Q 对象,它必须位于所有关键字参数的前面。例如

    Poll.objects.get(
        Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)),
        question__startswith='Who')

    #下列是不合法的查询条件
    Poll.objects.get(
        question__startswith='Who',
        Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)))
     

    Q对象实例化使用:

            # 获取搜索条件
            condition_dict = json.loads(request.GET.get('condition'))
            '''
            {'sn__contains': ['1', '2', '3', '1'], 'hostname__contains': ['c1', 'c2', 'c3']}
            '''
    
            from django.db.models import Q
            #产生第一个Q对象
            con = Q()
            for k,v in condition_dict.items():
                #产生第二个Q对象
                temp = Q()
                temp.connector = 'OR'  # Connection types  AND = 'AND' OR = 'OR'  default = AND
                
                for item in v:
                    temp.children.append((k,item)) #children是Q父类Node的属性,默认是个列表
    
                con.add(temp,'AND') # add 是父类Node的方法,
    
            print(con)
            '''
            (AND: (OR: ('sn__contains', '1'), ('sn__contains', '1')), ('hostname__contains', 'c3'))
            '''
            models.Server.objects.filter(con)
    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    # Created by Mona on 2017/10/24
    
    import copy
    
    from django.utils.encoding import force_str, force_text
    
    class Node(object):
        """
        A single internal node in the tree graph. A Node should be viewed as a
        connection (the root) with the children being either leaf nodes or other
        Node instances.
        """
        # Standard connector type. Clients usually won't use this at all and
        # subclasses will usually override the value.
        default = 'DEFAULT'
    
        def __init__(self, children=None, connector=None, negated=False):
            """
            Constructs a new Node. If no connector is given, the default will be
            used.
            """
            self.children = children[:] if children else []
            self.connector = connector or self.default
            self.negated = negated
    
        # We need this because of django.db.models.query_utils.Q. Q. __init__() is
        # problematic, but it is a natural Node subclass in all other respects.
        @classmethod
        def _new_instance(cls, children=None, connector=None, negated=False):
            """
            This is called to create a new instance of this class when we need new
            Nodes (or subclasses) in the internal code in this class. Normally, it
            just shadows __init__(). However, subclasses with an __init__ signature
            that is not an extension of Node.__init__ might need to implement this
            method to allow a Node to create a new instance of them (if they have
            any extra setting up to do).
            """
            obj = Node(children, connector, negated)
            obj.__class__ = cls
            return obj
    
        def __str__(self):
            template = '(NOT (%s: %s))' if self.negated else '(%s: %s)'
            return force_str(template % (self.connector, ', '.join(force_text(c) for c in self.children)))
    
        def __repr__(self):
            return str("<%s: %s>") % (self.__class__.__name__, self)
    
        def __deepcopy__(self, memodict):
            """
            Utility method used by copy.deepcopy().
            """
            obj = Node(connector=self.connector, negated=self.negated)
            obj.__class__ = self.__class__
            obj.children = copy.deepcopy(self.children, memodict)
            return obj
    
        def __len__(self):
            """
            The size of a node if the number of children it has.
            """
            return len(self.children)
    
        def __bool__(self):
            """
            For truth value testing.
            """
            return bool(self.children)
    
        def __nonzero__(self):      # Python 2 compatibility
            return type(self).__bool__(self)
    
        def __contains__(self, other):
            """
            Returns True is 'other' is a direct child of this instance.
            """
            return other in self.children
    
        def add(self, data, conn_type, squash=True):
            """
            Combines this tree and the data represented by data using the
            connector conn_type. The combine is done by squashing the node other
            away if possible.
    
            This tree (self) will never be pushed to a child node of the
            combined tree, nor will the connector or negated properties change.
    
            The function returns a node which can be used in place of data
            regardless if the node other got squashed or not.
    
            If `squash` is False the data is prepared and added as a child to
            this tree without further logic.
            """
            if data in self.children:
                return data
            if not squash:
                self.children.append(data)
                return data
            if self.connector == conn_type:
                # We can reuse self.children to append or squash the node other.
                if (isinstance(data, Node) and not data.negated and
                        (data.connector == conn_type or len(data) == 1)):
                    # We can squash the other node's children directly into this
                    # node. We are just doing (AB)(CD) == (ABCD) here, with the
                    # addition that if the length of the other node is 1 the
                    # connector doesn't matter. However, for the len(self) == 1
                    # case we don't want to do the squashing, as it would alter
                    # self.connector.
                    self.children.extend(data.children)
                    return self
                else:
                    # We could use perhaps additional logic here to see if some
                    # children could be used for pushdown here.
                    self.children.append(data)
                    return data
            else:
                obj = self._new_instance(self.children, self.connector,
                                         self.negated)
                self.connector = conn_type
                self.children = [obj, data]
                return data
    
        def negate(self):
            """
            Negate the sense of the root connector.
            """
            self.negated = not self.negated
    
    class Q(Node):
        """
        Encapsulates filters as objects that can then be combined logically (using
        `&` and `|`).
        """
        # Connection types
        AND = 'AND'
        OR = 'OR'
        default = AND
    
        def __init__(self, *args, **kwargs):
            super(Q, self).__init__(children=list(args) + list(kwargs.items()))
    
        def _combine(self, other, conn):
            if not isinstance(other, Q):
                raise TypeError(other)
            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)
    
        def __invert__(self):
            obj = type(self)()
            obj.add(self, self.AND)
            obj.negate()
            return obj
    
        def resolve_expression(self, query=None, allow_joins=True, reuse=None, summarize=False, for_save=False):
            # We must promote any new joins to left outer joins so that when Q is
            # used as an expression, rows aren't filtered due to joins.
            clause, joins = query._add_q(self, reuse, allow_joins=allow_joins, split_subq=False)
            query.promote_joins(joins)
            return clause
    Q源码参考
  • 相关阅读:
    code review
    自我封闭
    怎么验证?
    DRUPAL点滴
    CRLF CSRF XSS
    各种element/format 在manage display 下的选项
    html list <==> unformatted list
    ctrl + d 在phpstorm 和 eclipse 中的不同含义
    常量和变量的区别
    JSON和php里的数据序列化
  • 原文地址:https://www.cnblogs.com/mona524/p/7725501.html
Copyright © 2020-2023  润新知