在django中使用q实现复杂查询
django Q 的使用方法
django的Q对象将SQL表达式封装在Python对象中,该对象可用于与数据库相关的操作。使用Q对象,我们可以使用更少和更简单的代码进行复杂查询。
例如,此Q对象会过滤问题是否与“what”相关:
from django.db.models import Q
Q(question__startswith='What')
Q对象有助于复杂查询,因为它们可以使用逻辑运算符和(&),或( | ),否定(〜)进行组合。 |
下面使用django教程中Polls民意调查中使用的简单模型,并添加一些实例来展示Q的用法:
# ==> in models.py
from django.db import models
import datetime
class Poll(models.Model):
question = models.CharField(max_length=200)
pub_date = models.DateTimeField('date published')
# ==> add some instances from the shell
>>> p = Poll(question='what shall I make for dinner', pub_date=datetime.date.today())
>>> p.save()
>>> p = Poll(question='what is your favourite meal?', pub_date=datetime.datetime(2009, 7, 19, 0, 0)) #one year ago
>>> p.save()
>>> p = Poll(question='how do you make omelettes?', pub_date=datetime.date.today())
>>> p.save()
Q对象能用来做什么
简而言之,您可能想要使用Q的主要原因是因为需要执行复杂查询,例如同时涉及OR和AND语句。
想象一下,您想要检索所有问题包含“dinner”或“meal”字样的民意调查。通常的“过滤器”选项可让您执行以下操作:
>>>Poll.objects.filter(question__contains='dinner').filter(question__contains='meal')
[]
结果不是我们想要的。我们刚刚得到AND语句的连接(所有约束都需要满足),而我们想要一个OR(至少需要满足一个约束)。
这是Q对象变得有用的地方:
>>> from django.db.models import Q
# a simple query
>>> Poll.objects.filter(Q(question__contains='dinner'))
[<Poll: what shall I make for dinner>]
# two constraints linked by AND
>>> Poll.objects.filter(Q(question__contains='dinner') & Q(question__contains='meal'))
[]
# two constraints linked by OR - that's it!
>>> Poll.objects.filter(Q(question__contains='dinner') | Q(question__contains='meal'))
[<Poll: what shall I make for dinner>, <Poll: what is your favourite meal?>]
还可以创建复杂查询:
# eg (A OR B) AND C:
>>> Poll.objects.filter((Q(question__contains='dinner') | Q(question__contains='meal')) & Q(pub_date=datetime.date.today()))
[<Poll: what shall I make for dinner>]
创建动态查询
动态地构建上述查询,这是Q对象可以节省大量时间的另一个地方
例如,在构建搜索引擎或分面浏览器时,界面允许用户以增量方式累积搜索过滤器。 处理这种情况的一种方法是创建Q对象列表,然后使用python的operator和reduce方法将它们组合在一起:
>>> import operator
# create a list of Q objects
>>> mylist = [Q(question__contains='dinner'), Q(question__contains='meal')]
# OR
>>> Poll.objects.filter(reduce(operator.or_, mylist))
[<Poll: what shall I make for dinner>, <Poll: what is your favourite meal?>]
# AND
>>> Poll.objects.filter(reduce(operator.and_, mylist))
[]
动态构建查询,可能不会事先知道哪些是必须使用的过滤器。相反,必须以编程方式从表示模型查询的字符串列表中生成Q对象列表:
# string representation of our queries
>>> predicates = [('question__contains', 'dinner'), ('question__contains', 'meal')]
# create the list of Q objects and run the queries as above..
>>> q_list = [Q(x) for x in predicates]
>>> Poll.objects.filter(reduce(operator.or_, q_list))
[<Poll: what shall I make for dinner>, <Poll: what is your favourite meal?>]
>>> Poll.objects.filter(reduce(operator.and_, q_list))
[]
# now let's append another filter to the query-strings..
>>> predicates.append(('pub_date', datetime.date.today()))
>>> predicates
[('question__contains', 'dinner'), ('question__contains', 'meal'), ('pub_date', datetime.date(2010, 7, 19))]
# .. and the results will change too
>>> q_list = [Q(x) for x in predicates]
>>> Poll.objects.filter(reduce(operator.or_, q_list))
[<Poll: what shall I make for dinner>, <Poll: what is your favourite meal?>, <Poll: how do you make omelettes?>]
>>> Poll.objects.filter(reduce(operator.and_, q_list))
[]
查询扩展和Q对象
使用查询扩展语法通常可以执行以下操作:
>>> mydict = {'question__contains': 'omelette', 'pub_date' : datetime.date.today()}
>>> Poll.objects.filter(**mydict)
[<Poll: how do you make omelettes?>]
基本上是对从一些字符串值动态构建的AND语句进行排序。
django ORM的一个非常酷的功能是可以在使用Q对象时继续这样做。换句话说,可以将所有“普通”内容委托给查询扩展机制,而只需在需要更复杂的查询(如OR语句)时使用Q对象。 例如(记得把字典放在第二位):
# OR plus query expansion
>>> Poll.objects.filter(reduce(operator.or_, q_list), **mydict)
[<Poll: how do you make omelettes?>]
# AND plus query expansion
>>> Poll.objects.filter(reduce(operator.and_, q_list), **mydict)
[]
在第一种情况下,我们只有一个结果,因为尽管q_list上的OR约束本身会匹配更多的东西,** mydict会被一系列由AND连接的约束分解,从而制作[Poll:how do you make omelettes?]唯一的匹配对象。 在第二种情况下,根本没有结果,因为我们要求一个同时满足所有约束(不存在)的Poll实例!
参考: