| 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 |
""" |
|---|