Django

Code

root/django/trunk/tests/modeltests/lookup/models.py

Revision 8242, 15.2 kB (checked in by mtredinnick, 1 month ago)

Fixed #6523 -- Use the correct cast on field types for PostgreSQL when
searching within a field column (e.g. "like", "contains", etc). Required for
PostgreSQL 8.3. Thanks to Dan Watson for the patch.

  • Property svn:eol-style set to native
Line 
1 """
2 7. The lookup API
3
4 This demonstrates features of the database API.
5 """
6
7 from django.db import models
8 from django.conf import settings
9
10 class Article(models.Model):
11     headline = models.CharField(max_length=100)
12     pub_date = models.DateTimeField()
13     class Meta:
14         ordering = ('-pub_date', 'headline')
15
16     def __unicode__(self):
17         return self.headline
18
19 __test__ = {'API_TESTS':r"""
20 # Create a couple of Articles.
21 >>> from datetime import datetime
22 >>> a1 = Article(headline='Article 1', pub_date=datetime(2005, 7, 26))
23 >>> a1.save()
24 >>> a2 = Article(headline='Article 2', pub_date=datetime(2005, 7, 27))
25 >>> a2.save()
26 >>> a3 = Article(headline='Article 3', pub_date=datetime(2005, 7, 27))
27 >>> a3.save()
28 >>> a4 = Article(headline='Article 4', pub_date=datetime(2005, 7, 28))
29 >>> a4.save()
30 >>> a5 = Article(headline='Article 5', pub_date=datetime(2005, 8, 1, 9, 0))
31 >>> a5.save()
32 >>> a6 = Article(headline='Article 6', pub_date=datetime(2005, 8, 1, 8, 0))
33 >>> a6.save()
34 >>> a7 = Article(headline='Article 7', pub_date=datetime(2005, 7, 27))
35 >>> a7.save()
36
37 # text matching tests for PostgreSQL 8.3
38 >>> Article.objects.filter(id__iexact='1')
39 [<Article: Article 1>]
40 >>> Article.objects.filter(pub_date__startswith='2005')
41 [<Article: Article 5>, <Article: Article 6>, <Article: Article 4>, <Article: Article 2>, <Article: Article 3>, <Article: Article 7>, <Article: Article 1>]
42
43 # Each QuerySet gets iterator(), which is a generator that "lazily" returns
44 # results using database-level iteration.
45 >>> for a in Article.objects.iterator():
46 ...     print a.headline
47 Article 5
48 Article 6
49 Article 4
50 Article 2
51 Article 3
52 Article 7
53 Article 1
54
55 # iterator() can be used on any QuerySet.
56 >>> for a in Article.objects.filter(headline__endswith='4').iterator():
57 ...     print a.headline
58 Article 4
59
60 # count() returns the number of objects matching search criteria.
61 >>> Article.objects.count()
62 7L
63 >>> Article.objects.filter(pub_date__exact=datetime(2005, 7, 27)).count()
64 3L
65 >>> Article.objects.filter(headline__startswith='Blah blah').count()
66 0L
67
68 # count() should respect sliced query sets.
69 >>> articles = Article.objects.all()
70 >>> articles.count()
71 7L
72 >>> articles[:4].count()
73 4
74 >>> articles[1:100].count()
75 6L
76 >>> articles[10:100].count()
77 0
78
79 # Date and date/time lookups can also be done with strings.
80 >>> Article.objects.filter(pub_date__exact='2005-07-27 00:00:00').count()
81 3L
82
83 # in_bulk() takes a list of IDs and returns a dictionary mapping IDs
84 # to objects.
85 >>> arts = Article.objects.in_bulk([1, 2])
86 >>> arts[1]
87 <Article: Article 1>
88 >>> arts[2]
89 <Article: Article 2>
90 >>> Article.objects.in_bulk([3])
91 {3: <Article: Article 3>}
92 >>> Article.objects.in_bulk([1000])
93 {}
94 >>> Article.objects.in_bulk([])
95 {}
96 >>> Article.objects.in_bulk('foo')
97 Traceback (most recent call last):
98     ...
99 AssertionError: in_bulk() must be provided with a list of IDs.
100 >>> Article.objects.in_bulk()
101 Traceback (most recent call last):
102     ...
103 TypeError: in_bulk() takes exactly 2 arguments (1 given)
104 >>> Article.objects.in_bulk(headline__startswith='Blah')
105 Traceback (most recent call last):
106     ...
107 TypeError: in_bulk() got an unexpected keyword argument 'headline__startswith'
108
109 # values() returns a list of dictionaries instead of object instances -- and
110 # you can specify which fields you want to retrieve.
111 >>> Article.objects.values('headline')
112 [{'headline': u'Article 5'}, {'headline': u'Article 6'}, {'headline': u'Article 4'}, {'headline': u'Article 2'}, {'headline': u'Article 3'}, {'headline': u'Article 7'}, {'headline': u'Article 1'}]
113 >>> Article.objects.filter(pub_date__exact=datetime(2005, 7, 27)).values('id')
114 [{'id': 2}, {'id': 3}, {'id': 7}]
115 >>> 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'}]
116 True
117
118 >>> for d in Article.objects.values('id', 'headline'):
119 ...     i = d.items()
120 ...     i.sort()
121 ...     i
122 [('headline', u'Article 5'), ('id', 5)]
123 [('headline', u'Article 6'), ('id', 6)]
124 [('headline', u'Article 4'), ('id', 4)]
125 [('headline', u'Article 2'), ('id', 2)]
126 [('headline', u'Article 3'), ('id', 3)]
127 [('headline', u'Article 7'), ('id', 7)]
128 [('headline', u'Article 1'), ('id', 1)]
129
130 # You can use values() with iterator() for memory savings, because iterator()
131 # uses database-level iteration.
132 >>> for d in Article.objects.values('id', 'headline').iterator():
133 ...     i = d.items()
134 ...     i.sort()
135 ...     i
136 [('headline', u'Article 5'), ('id', 5)]
137 [('headline', u'Article 6'), ('id', 6)]
138 [('headline', u'Article 4'), ('id', 4)]
139 [('headline', u'Article 2'), ('id', 2)]
140 [('headline', u'Article 3'), ('id', 3)]
141 [('headline', u'Article 7'), ('id', 7)]
142 [('headline', u'Article 1'), ('id', 1)]
143
144 # The values() method works with "extra" fields specified in extra(select).
145 >>> for d in Article.objects.extra(select={'id_plus_one': 'id + 1'}).values('id', 'id_plus_one'):
146 ...     i = d.items()
147 ...     i.sort()
148 ...     i
149 [('id', 5), ('id_plus_one', 6)]
150 [('id', 6), ('id_plus_one', 7)]
151 [('id', 4), ('id_plus_one', 5)]
152 [('id', 2), ('id_plus_one', 3)]
153 [('id', 3), ('id_plus_one', 4)]
154 [('id', 7), ('id_plus_one', 8)]
155 [('id', 1), ('id_plus_one', 2)]
156 >>> data = {'id_plus_one': 'id+1', 'id_plus_two': 'id+2', 'id_plus_three': 'id+3',
157 ...         'id_plus_four': 'id+4', 'id_plus_five': 'id+5', 'id_plus_six': 'id+6',
158 ...         'id_plus_seven': 'id+7', 'id_plus_eight': 'id+8'}
159 >>> result = list(Article.objects.filter(id=1).extra(select=data).values(*data.keys()))[0]
160 >>> result = result.items()
161 >>> result.sort()
162 >>> result
163 [('id_plus_eight', 9), ('id_plus_five', 6), ('id_plus_four', 5), ('id_plus_one', 2), ('id_plus_seven', 8), ('id_plus_six', 7), ('id_plus_three', 4), ('id_plus_two', 3)]
164
165 # However, an exception FieldDoesNotExist will be thrown if you specify a
166 # non-existent field name in values() (a field that is neither in the model
167 # nor in extra(select)).
168 >>> Article.objects.extra(select={'id_plus_one': 'id + 1'}).values('id', 'id_plus_two')
169 Traceback (most recent call last):
170     ...
171 FieldError: Cannot resolve keyword 'id_plus_two' into field. Choices are: headline, id, id_plus_one, pub_date
172
173 # If you don't specify field names to values(), all are returned.
174 >>> list(Article.objects.filter(id=5).values()) == [{'id': 5, 'headline': 'Article 5', 'pub_date': datetime(2005, 8, 1, 9, 0)}]
175 True
176
177 # values_list() is similar to values(), except that the results are returned as
178 # a list of tuples, rather than a list of dictionaries. Within each tuple, the
179 # order of the elemnts is the same as the order of fields in the values_list()
180 # call.
181 >>> Article.objects.values_list('headline')
182 [(u'Article 5',), (u'Article 6',), (u'Article 4',), (u'Article 2',), (u'Article 3',), (u'Article 7',), (u'Article 1',)]
183
184 >>> Article.objects.values_list('id').order_by('id')
185 [(1,), (2,), (3,), (4,), (5,), (6,), (7,)]
186 >>> Article.objects.values_list('id', flat=True).order_by('id')
187 [1, 2, 3, 4, 5, 6, 7]
188
189 >>> Article.objects.extra(select={'id_plus_one': 'id+1'}).order_by('id').values_list('id')
190 [(1,), (2,), (3,), (4,), (5,), (6,), (7,)]
191 >>> Article.objects.extra(select={'id_plus_one': 'id+1'}).order_by('id').values_list('id_plus_one', 'id')
192 [(2, 1), (3, 2), (4, 3), (5, 4), (6, 5), (7, 6), (8, 7)]
193 >>> Article.objects.extra(select={'id_plus_one': 'id+1'}).order_by('id').values_list('id', 'id_plus_one')
194 [(1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (6, 7), (7, 8)]
195
196 >>> Article.objects.values_list('id', 'headline', flat=True)
197 Traceback (most recent call last):
198 ...
199 TypeError: 'flat' is not valid when values_list is called with more than one field.
200
201 # Every DateField and DateTimeField creates get_next_by_FOO() and
202 # get_previous_by_FOO() methods.
203 # In the case of identical date values, these methods will use the ID as a
204 # fallback check. This guarantees that no records are skipped or duplicated.
205 >>> a1.get_next_by_pub_date()
206 <Article: Article 2>
207 >>> a2.get_next_by_pub_date()
208 <Article: Article 3>
209 >>> a2.get_next_by_pub_date(headline__endswith='6')
210 <Article: Article 6>
211 >>> a3.get_next_by_pub_date()
212 <Article: Article 7>
213 >>> a4.get_next_by_pub_date()
214 <Article: Article 6>
215 >>> a5.get_next_by_pub_date()
216 Traceback (most recent call last):
217     ...
218 DoesNotExist: Article matching query does not exist.
219 >>> a6.get_next_by_pub_date()
220 <Article: Article 5>
221 >>> a7.get_next_by_pub_date()
222 <Article: Article 4>
223
224 >>> a7.get_previous_by_pub_date()
225 <Article: Article 3>
226 >>> a6.get_previous_by_pub_date()
227 <Article: Article 4>
228 >>> a5.get_previous_by_pub_date()
229 <Article: Article 6>
230 >>> a4.get_previous_by_pub_date()
231 <Article: Article 7>
232 >>> a3.get_previous_by_pub_date()
233 <Article: Article 2>
234 >>> a2.get_previous_by_pub_date()
235 <Article: Article 1>
236
237 # Underscores and percent signs have special meaning in the underlying
238 # SQL code, but Django handles the quoting of them automatically.
239 >>> a8 = Article(headline='Article_ with underscore', pub_date=datetime(2005, 11, 20))
240 >>> a8.save()
241 >>> Article.objects.filter(headline__startswith='Article')
242 [<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>]
243 >>> Article.objects.filter(headline__startswith='Article_')
244 [<Article: Article_ with underscore>]
245
246 >>> a9 = Article(headline='Article% with percent sign', pub_date=datetime(2005, 11, 21))
247 >>> a9.save()
248 >>> Article.objects.filter(headline__startswith='Article')
249 [<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>]
250 >>> Article.objects.filter(headline__startswith='Article%')
251 [<Article: Article% with percent sign>]
252
253 # exclude() is the opposite of filter() when doing lookups:
254 >>> Article.objects.filter(headline__contains='Article').exclude(headline__contains='with')
255 [<Article: Article 5>, <Article: Article 6>, <Article: Article 4>, <Article: Article 2>, <Article: Article 3>, <Article: Article 7>, <Article: Article 1>]
256 >>> Article.objects.exclude(headline__startswith="Article_")
257 [<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>]
258 >>> Article.objects.exclude(headline="Article 7")
259 [<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>]
260
261 # Backslashes also have special meaning in the underlying SQL code, but Django
262 # automatically quotes them appropriately.
263 >>> a10 = Article(headline='Article with \\ backslash', pub_date=datetime(2005, 11, 22))
264 >>> a10.save()
265 >>> Article.objects.filter(headline__contains='\\')
266 [<Article: Article with \ backslash>]
267
268 # none() returns an EmptyQuerySet that behaves like any other QuerySet object
269 >>> Article.objects.none()
270 []
271 >>> Article.objects.none().filter(headline__startswith='Article')
272 []
273 >>> Article.objects.filter(headline__startswith='Article').none()
274 []
275 >>> Article.objects.none().count()
276 0
277 >>> [article for article in Article.objects.none().iterator()]
278 []
279
280 # using __in with an empty list should return an empty query set
281 >>> Article.objects.filter(id__in=[])
282 []
283
284 >>> Article.objects.exclude(id__in=[])
285 [<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>]
286
287 # Programming errors are pointed out with nice error messages
288 >>> Article.objects.filter(pub_date_year='2005').count()
289 Traceback (most recent call last):
290     ...
291 FieldError: Cannot resolve keyword 'pub_date_year' into field. Choices are: headline, id, pub_date
292
293 >>> Article.objects.filter(headline__starts='Article')
294 Traceback (most recent call last):
295     ...
296 FieldError: Join on field 'headline' not permitted.
297
298 # Create some articles with a bit more interesting headlines for testing field lookups:
299 >>> now = datetime.now()
300 >>> for a in Article.objects.all():
301 ...     a.delete()
302 >>> a1 = Article(pub_date=now, headline='f')
303 >>> a1.save()
304 >>> a2 = Article(pub_date=now, headline='fo')
305 >>> a2.save()
306 >>> a3 = Article(pub_date=now, headline='foo')
307 >>> a3.save()
308 >>> a4 = Article(pub_date=now, headline='fooo')
309 >>> a4.save()
310 >>> a5 = Article(pub_date=now, headline='hey-Foo')
311 >>> a5.save()
312
313 # zero-or-more
314 >>> Article.objects.filter(headline__regex=r'fo*')
315 [<Article: f>, <Article: fo>, <Article: foo>, <Article: fooo>]
316 >>> Article.objects.filter(headline__iregex=r'fo*')
317 [<Article: f>, <Article: fo>, <Article: foo>, <Article: fooo>, <Article: hey-Foo>]
318
319 # one-or-more
320 >>> Article.objects.filter(headline__regex=r'fo+')
321 [<Article: fo>, <Article: foo>, <Article: fooo>]
322
323 # wildcard
324 >>> Article.objects.filter(headline__regex=r'fooo?')
325 [<Article: foo>, <Article: fooo>]
326
327 # and some more:
328 >>> a6 = Article(pub_date=now, headline='bar')
329 >>> a6.save()
330 >>> a7 = Article(pub_date=now, headline='AbBa')
331 >>> a7.save()
332 >>> a8 = Article(pub_date=now, headline='baz')
333 >>> a8.save()
334 >>> a9 = Article(pub_date=now, headline='baxZ')
335 >>> a9.save()
336
337 # leading anchor
338 >>> Article.objects.filter(headline__regex=r'^b')
339 [<Article: bar>, <Article: baxZ>, <Article: baz>]
340 >>> Article.objects.filter(headline__iregex=r'^a')
341 [<Article: AbBa>]
342
343 # trailing anchor
344 >>> Article.objects.filter(headline__regex=r'z$')
345 [<Article: baz>]
346 >>> Article.objects.filter(headline__iregex=r'z$')
347 [<Article: baxZ>, <Article: baz>]
348
349 # character sets
350 >>> Article.objects.filter(headline__regex=r'ba[rz]')
351 [<Article: bar>, <Article: baz>]
352 >>> Article.objects.filter(headline__regex=r'ba.[RxZ]')
353 [<Article: baxZ>]
354 >>> Article.objects.filter(headline__iregex=r'ba[RxZ]')
355 [<Article: bar>, <Article: baxZ>, <Article: baz>]
356
357 # and yet more:
358 >>> a10 = Article(pub_date=now, headline='foobar')
359 >>> a10.save()
360 >>> a11 = Article(pub_date=now, headline='foobaz')
361 >>> a11.save()
362 >>> a12 = Article(pub_date=now, headline='ooF')
363 >>> a12.save()
364 >>> a13 = Article(pub_date=now, headline='foobarbaz')
365 >>> a13.save()
366 >>> a14 = Article(pub_date=now, headline='zoocarfaz')
367 >>> a14.save()
368 >>> a15 = Article(pub_date=now, headline='barfoobaz')
369 >>> a15.save()
370 >>> a16 = Article(pub_date=now, headline='bazbaRFOO')
371 >>> a16.save()
372
373 # alternation
374 >>> Article.objects.filter(headline__regex=r'oo(f|b)')
375 [<Article: barfoobaz>, <Article: foobar>, <Article: foobarbaz>, <Article: foobaz>]
376 >>> Article.objects.filter(headline__iregex=r'oo(f|b)')
377 [<Article: barfoobaz>, <Article: foobar>, <Article: foobarbaz>, <Article: foobaz>, <Article: ooF>]
378 >>> Article.objects.filter(headline__regex=r'^foo(f|b)')
379 [<Article: foobar>, <Article: foobarbaz>, <Article: foobaz>]
380
381 # greedy matching
382 >>> Article.objects.filter(headline__regex=r'b.*az')
383 [<Article: barfoobaz>, <Article: baz>, <Article: bazbaRFOO>, <Article: foobarbaz>, <Article: foobaz>]
384 >>> Article.objects.filter(headline__iregex=r'b.*ar')
385 [<Article: bar>, <Article: barfoobaz>, <Article: bazbaRFOO>, <Article: foobar>, <Article: foobarbaz>]
386 """}
387
388
389 if settings.DATABASE_ENGINE != 'mysql':
390     __test__['API_TESTS'] += r"""
391 # grouping and backreferences
392 >>> Article.objects.filter(headline__regex=r'b(.).*b\1')
393 [<Article: barfoobaz>, <Article: bazbaRFOO>, <Article: foobarbaz>]
394 """
Note: See TracBrowser for help on using the browser.