zoukankan      html  css  js  c++  java
  • Django中Q查询及Q()对象

    问题

    一般我们在Django程序中查询数据库操作都是在QuerySet里进行进行,例如下面代码:

    >>> q1 = Entry.objects.filter(headline__startswith="What")
    >>> q2 = q1.exclude(pub_date__gte=datetime.date.today())
    >>> q3 = q1.filter(pub_date__gte=datetime.date.today())
     
    

    或者将其组合起来,例如:

    >>>q1 = Entry.objects.filter(headline_startswith="What").exclude(pub_date_gte=datetime.date.today())
     
    

    随着我们的程序越来越复杂,查询的条件也跟着复杂起来,这样简单的通过一个filter()来进行查询的条件将导致我们的查询越来越长。

    Q()对象就是为了将这些条件组合起来。

    当我们在查询的条件中需要组合条件时(例如两个条件“且”或者“或”)时。我们可以使用Q()查询对象。例如下面的代码

    fromdjango.db.modelsimports Q
    q=Q(question_startswith="What")
     
    

    这样就生成了一个Q()对象,我们可以使用符号&或者|将多个Q()对象组合起来传递给filter(),exclude(),get()等函数当多个Q()对象组合起来时,Django会自动生成一个新的Q()。例如下面代码就将两个条件组合成了一个

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

    使用上述代码可以使用SQL语句这么理解:

    WHEREquestionLIKE 'Who%' ORquestionLIKE 'What%'
     
    

    我们可以在Q()对象的前面使用字符“~”来代表意义“非”,例如下面代码:

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

    对应SQL语句可以理解为:

    WHEREquestionlike "Who%" ORyear(pub_date) !=2005
     
    

    这样我们可以使用 “&”或者“|”还有括号来对条件进行分组从而组合成更加复杂的查询逻辑。

    也可以传递多个Q()对象给查询函数,例如下面代码:

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

    多个Q()对象之间的关系Django会自动理解成“且(and)”关系。如上面代码使用SQL语句理解将会是:

    SELECT * fromnewsWHEREquestionLIKE 'Who%'  AND (pub_date = '2005-05-02' ORpub_date = '2005-05-06')
     
    

    Q()对象可以结合关键字参数一起传递给查询函数,不过需要注意的是要将Q()对象放在关键字参数的前面,看下面代码

    #正确的做法
    News.objects.get(
        Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)),
        question__startswith='Who')
     
    #错误的做法,代码将关键字参数放在了Q()对象的前面。
    News.objects.get(
        question__startswith='Who',
        Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)))
     

    使用Q 对象进行复杂的查询

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

    Q 对象 (django.db.models.Q) 对象用于封装一组关键字参数。这些关键字参数就是上文“字段查询” 中所提及的那些。

    例如,下面的Q 对象封装一个LIKE 查询:

    from django.db.models import Q
    Q(question__startswith='What')
    

    Q 对象可以使用&| 操作符组合起来。当一个操作符在两个Q 对象上使用时,它产生一个新的Q 对象。

    例如,下面的语句产生一个Q 对象,表示两个"question__startswith" 查询的“OR” :

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

    它等同于下面的SQL WHERE 子句:

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

    你可以组合&|  操作符以及使用括号进行分组来编写任意复杂的Q 对象。同时,Q 对象可以使用~ 操作符取反,这允许组合正常的查询和取反(NOT) 查询:

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

    每个接受关键字参数的查询函数(例如filter()exclude()get())都可以传递一个或多个Q 对象作为位置(不带名的)参数。如果一个查询函数有多个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 对象和关键字参数。所有提供给查询函数的参数(关键字参数或Q 对象)都将"AND”在一起。但是,如果出现Q 对象,它必须位于所有关键字参数的前面。例如:

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

    ... 是一个合法的查询,等同于前面的例子;但是:

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

    ... 是不合法的。

    另见

    Django 单元测试中的OR 查询示例演示了几种Q 的用法。

    Django的Q对象实现的源码中:

     

     

    [python] view plain copy
     
    1. # 位于/django/db/models/query_utils.py  
    2.   
    3. class Q(tree.Node):  
    4.     """ 
    5.     Encapsulates filters as objects that can then be combined logically (using 
    6.     & and |). 
    7.     """  
    8.     # Connection types  
    9.     AND = 'AND'  
    10.     OR = 'OR'  
    11.     default = AND  
    12.   
    13.     def __init__(self, *args, **kwargs):  
    14.         super(Q, self).__init__(children=list(args) + kwargs.items())  
    15.   
    16.     def _combine(self, other, conn):  
    17.         if not isinstance(other, Q):  
    18.             raise TypeError(other)  
    19.         obj = type(self)()  
    20.         obj.add(self, conn)  
    21.         obj.add(other, conn)  
    22.         return obj  
    23.   
    24.     def __or__(self, other):  
    25.         return self._combine(other, self.OR)  
    26.   
    27.     def __and__(self, other):  
    28.         return self._combine(other, self.AND)  
    29.   
    30.     def __invert__(self):  
    31.         obj = type(self)()  
    32.         obj.add(selfself.AND)  
    33.         obj.negate()  
    34.         return obj  

     

    传Q对象,构造搜索条件

    首先还是需要导入模块:

    from django.db.models import Q

    传入条件进行查询:

    q1 = Q()
    q1.connector = 'OR'
    q1.children.append(('id', 1))
    q1.children.append(('id', 2))
    q1.children.append(('id', 3))
        
    models.Tb1.objects.filter(q1)

    合并条件进行查询:

    con = Q()
    
    q1 = Q()
    q1.connector = 'OR'
    q1.children.append(('id', 1))
    q1.children.append(('id', 2))
    q1.children.append(('id', 3))
    
    q2 = Q()
    q2.connector = 'OR'
    q2.children.append(('status', '在线'))
    
    con.add(q1, 'AND')
    con.add(q2, 'AND')
    
    models.Tb1.objects.filter(con)

     

  • 相关阅读:
    抽象代数学习笔记
    WC2021 游记
    简单的数学题
    前缀和公式
    杜教筛
    [模板]BZOJ4756线段树合并
    SPOJ 694
    bzoj1367 可并堆
    莫比乌斯反演(理论)
    es6 Set数据结构
  • 原文地址:https://www.cnblogs.com/huchong/p/8027962.html
Copyright © 2011-2022 走看看