|
1 """ |
|
2 7. The lookup API |
|
3 |
|
4 This demonstrates features of the database API. |
|
5 """ |
|
6 |
|
7 from django.db import models |
|
8 |
|
9 class Article(models.Model): |
|
10 headline = models.CharField(maxlength=100) |
|
11 pub_date = models.DateTimeField() |
|
12 class Meta: |
|
13 ordering = ('-pub_date', 'headline') |
|
14 |
|
15 def __str__(self): |
|
16 return self.headline |
|
17 |
|
18 __test__ = {'API_TESTS':r""" |
|
19 # Create a couple of Articles. |
|
20 >>> from datetime import datetime |
|
21 >>> a1 = Article(headline='Article 1', pub_date=datetime(2005, 7, 26)) |
|
22 >>> a1.save() |
|
23 >>> a2 = Article(headline='Article 2', pub_date=datetime(2005, 7, 27)) |
|
24 >>> a2.save() |
|
25 >>> a3 = Article(headline='Article 3', pub_date=datetime(2005, 7, 27)) |
|
26 >>> a3.save() |
|
27 >>> a4 = Article(headline='Article 4', pub_date=datetime(2005, 7, 28)) |
|
28 >>> a4.save() |
|
29 >>> a5 = Article(headline='Article 5', pub_date=datetime(2005, 8, 1, 9, 0)) |
|
30 >>> a5.save() |
|
31 >>> a6 = Article(headline='Article 6', pub_date=datetime(2005, 8, 1, 8, 0)) |
|
32 >>> a6.save() |
|
33 >>> a7 = Article(headline='Article 7', pub_date=datetime(2005, 7, 27)) |
|
34 >>> a7.save() |
|
35 |
|
36 # Each QuerySet gets iterator(), which is a generator that "lazily" returns |
|
37 # results using database-level iteration. |
|
38 >>> for a in Article.objects.iterator(): |
|
39 ... print a.headline |
|
40 Article 5 |
|
41 Article 6 |
|
42 Article 4 |
|
43 Article 2 |
|
44 Article 3 |
|
45 Article 7 |
|
46 Article 1 |
|
47 |
|
48 # iterator() can be used on any QuerySet. |
|
49 >>> for a in Article.objects.filter(headline__endswith='4').iterator(): |
|
50 ... print a.headline |
|
51 Article 4 |
|
52 |
|
53 # count() returns the number of objects matching search criteria. |
|
54 >>> Article.objects.count() |
|
55 7L |
|
56 >>> Article.objects.filter(pub_date__exact=datetime(2005, 7, 27)).count() |
|
57 3L |
|
58 >>> Article.objects.filter(headline__startswith='Blah blah').count() |
|
59 0L |
|
60 |
|
61 # count() should respect sliced query sets. |
|
62 >>> articles = Article.objects.all() |
|
63 >>> articles.count() |
|
64 7L |
|
65 >>> articles[:4].count() |
|
66 4 |
|
67 >>> articles[1:100].count() |
|
68 6L |
|
69 >>> articles[10:100].count() |
|
70 0 |
|
71 |
|
72 # Date and date/time lookups can also be done with strings. |
|
73 >>> Article.objects.filter(pub_date__exact='2005-07-27 00:00:00').count() |
|
74 3L |
|
75 |
|
76 # in_bulk() takes a list of IDs and returns a dictionary mapping IDs |
|
77 # to objects. |
|
78 >>> Article.objects.in_bulk([1, 2]) |
|
79 {1: <Article: Article 1>, 2: <Article: Article 2>} |
|
80 >>> Article.objects.in_bulk([3]) |
|
81 {3: <Article: Article 3>} |
|
82 >>> Article.objects.in_bulk([1000]) |
|
83 {} |
|
84 >>> Article.objects.in_bulk([]) |
|
85 {} |
|
86 >>> Article.objects.in_bulk('foo') |
|
87 Traceback (most recent call last): |
|
88 ... |
|
89 AssertionError: in_bulk() must be provided with a list of IDs. |
|
90 >>> Article.objects.in_bulk() |
|
91 Traceback (most recent call last): |
|
92 ... |
|
93 TypeError: in_bulk() takes exactly 2 arguments (1 given) |
|
94 >>> Article.objects.in_bulk(headline__startswith='Blah') |
|
95 Traceback (most recent call last): |
|
96 ... |
|
97 TypeError: in_bulk() got an unexpected keyword argument 'headline__startswith' |
|
98 |
|
99 # values() returns a list of dictionaries instead of object instances -- and |
|
100 # you can specify which fields you want to retrieve. |
|
101 >>> Article.objects.values('headline') |
|
102 [{'headline': 'Article 5'}, {'headline': 'Article 6'}, {'headline': 'Article 4'}, {'headline': 'Article 2'}, {'headline': 'Article 3'}, {'headline': 'Article 7'}, {'headline': 'Article 1'}] |
|
103 >>> Article.objects.filter(pub_date__exact=datetime(2005, 7, 27)).values('id') |
|
104 [{'id': 2}, {'id': 3}, {'id': 7}] |
|
105 >>> list(Article.objects.values('id', 'headline')) == [{'id': 5, 'headline': 'Article 5'}, {'id': 6, 'headline': 'Article 6'}, {'id': 4, 'headline': 'Article 4'}, {'id': 2, 'headline': 'Article 2'}, {'id': 3, 'headline': 'Article 3'}, {'id': 7, 'headline': 'Article 7'}, {'id': 1, 'headline': 'Article 1'}] |
|
106 True |
|
107 |
|
108 >>> for d in Article.objects.values('id', 'headline'): |
|
109 ... i = d.items() |
|
110 ... i.sort() |
|
111 ... i |
|
112 [('headline', 'Article 5'), ('id', 5)] |
|
113 [('headline', 'Article 6'), ('id', 6)] |
|
114 [('headline', 'Article 4'), ('id', 4)] |
|
115 [('headline', 'Article 2'), ('id', 2)] |
|
116 [('headline', 'Article 3'), ('id', 3)] |
|
117 [('headline', 'Article 7'), ('id', 7)] |
|
118 [('headline', 'Article 1'), ('id', 1)] |
|
119 |
|
120 # You can use values() with iterator() for memory savings, because iterator() |
|
121 # uses database-level iteration. |
|
122 >>> for d in Article.objects.values('id', 'headline').iterator(): |
|
123 ... i = d.items() |
|
124 ... i.sort() |
|
125 ... i |
|
126 [('headline', 'Article 5'), ('id', 5)] |
|
127 [('headline', 'Article 6'), ('id', 6)] |
|
128 [('headline', 'Article 4'), ('id', 4)] |
|
129 [('headline', 'Article 2'), ('id', 2)] |
|
130 [('headline', 'Article 3'), ('id', 3)] |
|
131 [('headline', 'Article 7'), ('id', 7)] |
|
132 [('headline', 'Article 1'), ('id', 1)] |
|
133 |
|
134 # if you don't specify which fields, all are returned |
|
135 >>> list(Article.objects.filter(id=5).values()) == [{'id': 5, 'headline': 'Article 5', 'pub_date': datetime(2005, 8, 1, 9, 0)}] |
|
136 True |
|
137 |
|
138 # Every DateField and DateTimeField creates get_next_by_FOO() and |
|
139 # get_previous_by_FOO() methods. |
|
140 # In the case of identical date values, these methods will use the ID as a |
|
141 # fallback check. This guarantees that no records are skipped or duplicated. |
|
142 >>> a1.get_next_by_pub_date() |
|
143 <Article: Article 2> |
|
144 >>> a2.get_next_by_pub_date() |
|
145 <Article: Article 3> |
|
146 >>> a2.get_next_by_pub_date(headline__endswith='6') |
|
147 <Article: Article 6> |
|
148 >>> a3.get_next_by_pub_date() |
|
149 <Article: Article 7> |
|
150 >>> a4.get_next_by_pub_date() |
|
151 <Article: Article 6> |
|
152 >>> a5.get_next_by_pub_date() |
|
153 Traceback (most recent call last): |
|
154 ... |
|
155 DoesNotExist: Article matching query does not exist. |
|
156 >>> a6.get_next_by_pub_date() |
|
157 <Article: Article 5> |
|
158 >>> a7.get_next_by_pub_date() |
|
159 <Article: Article 4> |
|
160 |
|
161 >>> a7.get_previous_by_pub_date() |
|
162 <Article: Article 3> |
|
163 >>> a6.get_previous_by_pub_date() |
|
164 <Article: Article 4> |
|
165 >>> a5.get_previous_by_pub_date() |
|
166 <Article: Article 6> |
|
167 >>> a4.get_previous_by_pub_date() |
|
168 <Article: Article 7> |
|
169 >>> a3.get_previous_by_pub_date() |
|
170 <Article: Article 2> |
|
171 >>> a2.get_previous_by_pub_date() |
|
172 <Article: Article 1> |
|
173 |
|
174 # Underscores and percent signs have special meaning in the underlying |
|
175 # SQL code, but Django handles the quoting of them automatically. |
|
176 >>> a8 = Article(headline='Article_ with underscore', pub_date=datetime(2005, 11, 20)) |
|
177 >>> a8.save() |
|
178 >>> Article.objects.filter(headline__startswith='Article') |
|
179 [<Article: Article_ with underscore>, <Article: Article 5>, <Article: Article 6>, <Article: Article 4>, <Article: Article 2>, <Article: Article 3>, <Article: Article 7>, <Article: Article 1>] |
|
180 >>> Article.objects.filter(headline__startswith='Article_') |
|
181 [<Article: Article_ with underscore>] |
|
182 |
|
183 >>> a9 = Article(headline='Article% with percent sign', pub_date=datetime(2005, 11, 21)) |
|
184 >>> a9.save() |
|
185 >>> Article.objects.filter(headline__startswith='Article') |
|
186 [<Article: Article% with percent sign>, <Article: Article_ with underscore>, <Article: Article 5>, <Article: Article 6>, <Article: Article 4>, <Article: Article 2>, <Article: Article 3>, <Article: Article 7>, <Article: Article 1>] |
|
187 >>> Article.objects.filter(headline__startswith='Article%') |
|
188 [<Article: Article% with percent sign>] |
|
189 |
|
190 # exclude() is the opposite of filter() when doing lookups: |
|
191 >>> Article.objects.filter(headline__contains='Article').exclude(headline__contains='with') |
|
192 [<Article: Article 5>, <Article: Article 6>, <Article: Article 4>, <Article: Article 2>, <Article: Article 3>, <Article: Article 7>, <Article: Article 1>] |
|
193 >>> Article.objects.exclude(headline__startswith="Article_") |
|
194 [<Article: Article% with percent sign>, <Article: Article 5>, <Article: Article 6>, <Article: Article 4>, <Article: Article 2>, <Article: Article 3>, <Article: Article 7>, <Article: Article 1>] |
|
195 >>> Article.objects.exclude(headline="Article 7") |
|
196 [<Article: Article% with percent sign>, <Article: Article_ with underscore>, <Article: Article 5>, <Article: Article 6>, <Article: Article 4>, <Article: Article 2>, <Article: Article 3>, <Article: Article 1>] |
|
197 |
|
198 # Backslashes also have special meaning in the underlying SQL code, but Django |
|
199 # automatically quotes them appropriately. |
|
200 >>> a10 = Article(headline='Article with \\ backslash', pub_date=datetime(2005, 11, 22)) |
|
201 >>> a10.save() |
|
202 >>> Article.objects.filter(headline__contains='\\') |
|
203 [<Article: Article with \ backslash>] |
|
204 |
|
205 # none() returns an EmptyQuerySet that behaves like any other QuerySet object |
|
206 >>> Article.objects.none() |
|
207 [] |
|
208 >>> Article.objects.none().filter(headline__startswith='Article') |
|
209 [] |
|
210 >>> Article.objects.none().count() |
|
211 0 |
|
212 >>> [article for article in Article.objects.none().iterator()] |
|
213 [] |
|
214 |
|
215 # using __in with an empty list should return an empty query set |
|
216 >>> Article.objects.filter(id__in=[]) |
|
217 [] |
|
218 |
|
219 >>> Article.objects.exclude(id__in=[]) |
|
220 [<Article: Article with \ backslash>, <Article: Article% with percent sign>, <Article: Article_ with underscore>, <Article: Article 5>, <Article: Article 6>, <Article: Article 4>, <Article: Article 2>, <Article: Article 3>, <Article: Article 7>, <Article: Article 1>] |
|
221 |
|
222 # Programming errors are pointed out with nice error messages |
|
223 >>> Article.objects.filter(pub_date_year='2005').count() |
|
224 Traceback (most recent call last): |
|
225 ... |
|
226 TypeError: Cannot resolve keyword 'pub_date_year' into field |
|
227 |
|
228 >>> Article.objects.filter(headline__starts='Article') |
|
229 Traceback (most recent call last): |
|
230 ... |
|
231 TypeError: Cannot resolve keyword 'headline__starts' into field |
|
232 |
|
233 """} |