1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
|
"""
19. OR lookups
To perform an OR lookup, or a lookup that combines ANDs and ORs, combine
``QuerySet`` objects using ``&`` and ``|`` operators.
Alternatively, use positional arguments, and pass one or more expressions of
clauses using the variable ``django.db.models.Q`` (or any object with an
``add_to_query`` method).
"""
from django.db import models
class Article(models.Model):
headline = models.CharField(max_length=50)
pub_date = models.DateTimeField()
class Meta:
ordering = ('pub_date',)
def __unicode__(self):
return self.headline
__test__ = {'API_TESTS':"""
>>> from datetime import datetime
>>> from django.db.models import Q
>>> a1 = Article(headline='Hello', pub_date=datetime(2005, 11, 27))
>>> a1.save()
>>> a2 = Article(headline='Goodbye', pub_date=datetime(2005, 11, 28))
>>> a2.save()
>>> a3 = Article(headline='Hello and goodbye', pub_date=datetime(2005, 11, 29))
>>> a3.save()
>>> Article.objects.filter(headline__startswith='Hello') | Article.objects.filter(headline__startswith='Goodbye')
[<Article: Hello>, <Article: Goodbye>, <Article: Hello and goodbye>]
>>> Article.objects.filter(Q(headline__startswith='Hello') | Q(headline__startswith='Goodbye'))
[<Article: Hello>, <Article: Goodbye>, <Article: Hello and goodbye>]
>>> Article.objects.filter(Q(headline__startswith='Hello') & Q(headline__startswith='Goodbye'))
[]
# You can shorten this syntax with code like the following,
# which is especially useful if building the query in stages:
>>> articles = Article.objects.all()
>>> articles.filter(headline__startswith='Hello') & articles.filter(headline__startswith='Goodbye')
[]
>>> articles.filter(headline__startswith='Hello') & articles.filter(headline__contains='bye')
[<Article: Hello and goodbye>]
>>> Article.objects.filter(Q(headline__contains='bye'), headline__startswith='Hello')
[<Article: Hello and goodbye>]
>>> Article.objects.filter(headline__contains='Hello') | Article.objects.filter(headline__contains='bye')
[<Article: Hello>, <Article: Goodbye>, <Article: Hello and goodbye>]
>>> Article.objects.filter(headline__iexact='Hello') | Article.objects.filter(headline__contains='ood')
[<Article: Hello>, <Article: Goodbye>, <Article: Hello and goodbye>]
>>> Article.objects.filter(Q(pk=1) | Q(pk=2))
[<Article: Hello>, <Article: Goodbye>]
>>> Article.objects.filter(Q(pk=1) | Q(pk=2) | Q(pk=3))
[<Article: Hello>, <Article: Goodbye>, <Article: Hello and goodbye>]
# You could also use "in" to accomplish the same as above.
>>> Article.objects.filter(pk__in=[1,2,3])
[<Article: Hello>, <Article: Goodbye>, <Article: Hello and goodbye>]
>>> Article.objects.filter(pk__in=(1,2,3))
[<Article: Hello>, <Article: Goodbye>, <Article: Hello and goodbye>]
>>> Article.objects.filter(pk__in=[1,2,3,4])
[<Article: Hello>, <Article: Goodbye>, <Article: Hello and goodbye>]
# Passing "in" an empty list returns no results ...
>>> Article.objects.filter(pk__in=[])
[]
# ... but can return results if we OR it with another query.
>>> Article.objects.filter(Q(pk__in=[]) | Q(headline__icontains='goodbye'))
[<Article: Goodbye>, <Article: Hello and goodbye>]
# Q arg objects are ANDed
>>> Article.objects.filter(Q(headline__startswith='Hello'), Q(headline__contains='bye'))
[<Article: Hello and goodbye>]
# Q arg AND order is irrelevant
>>> Article.objects.filter(Q(headline__contains='bye'), headline__startswith='Hello')
[<Article: Hello and goodbye>]
# Q objects can be negated
>>> Article.objects.filter(Q(pk=1) | ~Q(pk=2))
[<Article: Hello>, <Article: Hello and goodbye>]
>>> Article.objects.filter(~Q(pk=1) & ~Q(pk=2))
[<Article: Hello and goodbye>]
# This allows for more complex queries than filter() and exclude() alone would
# allow
>>> Article.objects.filter(Q(pk=1) & (~Q(pk=2) | Q(pk=3)))
[<Article: Hello>]
# Try some arg queries with operations other than filter.
>>> Article.objects.get(Q(headline__startswith='Hello'), Q(headline__contains='bye'))
<Article: Hello and goodbye>
>>> Article.objects.filter(Q(headline__startswith='Hello') | Q(headline__contains='bye')).count()
3
>>> dicts = list(Article.objects.filter(Q(headline__startswith='Hello'), Q(headline__contains='bye')).values())
>>> [sorted(d.items()) for d in dicts]
[[('headline', u'Hello and goodbye'), ('id', 3), ('pub_date', datetime.datetime(2005, 11, 29, 0, 0))]]
>>> Article.objects.filter(Q(headline__startswith='Hello')).in_bulk([1,2])
{1: <Article: Hello>}
# Demonstrating exclude with a Q object
>>> Article.objects.exclude(Q(headline__startswith='Hello'))
[<Article: Goodbye>]
# The 'complex_filter' method supports framework features such as
# 'limit_choices_to' which normally take a single dictionary of lookup arguments
# but need to support arbitrary queries via Q objects too.
>>> Article.objects.complex_filter({'pk': 1})
[<Article: Hello>]
>>> Article.objects.complex_filter(Q(pk=1) | Q(pk=2))
[<Article: Hello>, <Article: Goodbye>]
"""}
|