mirror of https://github.com/django/django.git
Migrated lookup doctests. Thanks to George Sakkis for the patch.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@14423 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
4a15719405
commit
e57cd291cc
|
@ -15,404 +15,3 @@ class Article(models.Model):
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return self.headline
|
return self.headline
|
||||||
|
|
||||||
__test__ = {'API_TESTS': r"""
|
|
||||||
# We can use .exists() to check that there are none yet
|
|
||||||
>>> Article.objects.exists()
|
|
||||||
False
|
|
||||||
|
|
||||||
# Create a couple of Articles.
|
|
||||||
>>> from datetime import datetime
|
|
||||||
>>> a1 = Article(headline='Article 1', pub_date=datetime(2005, 7, 26))
|
|
||||||
>>> a1.save()
|
|
||||||
>>> a2 = Article(headline='Article 2', pub_date=datetime(2005, 7, 27))
|
|
||||||
>>> a2.save()
|
|
||||||
>>> a3 = Article(headline='Article 3', pub_date=datetime(2005, 7, 27))
|
|
||||||
>>> a3.save()
|
|
||||||
>>> a4 = Article(headline='Article 4', pub_date=datetime(2005, 7, 28))
|
|
||||||
>>> a4.save()
|
|
||||||
>>> a5 = Article(headline='Article 5', pub_date=datetime(2005, 8, 1, 9, 0))
|
|
||||||
>>> a5.save()
|
|
||||||
>>> a6 = Article(headline='Article 6', pub_date=datetime(2005, 8, 1, 8, 0))
|
|
||||||
>>> a6.save()
|
|
||||||
>>> a7 = Article(headline='Article 7', pub_date=datetime(2005, 7, 27))
|
|
||||||
>>> a7.save()
|
|
||||||
|
|
||||||
# There should be some now!
|
|
||||||
>>> Article.objects.exists()
|
|
||||||
True
|
|
||||||
|
|
||||||
# Integer value can be queried using string
|
|
||||||
>>> Article.objects.filter(id__iexact='1')
|
|
||||||
[<Article: Article 1>]
|
|
||||||
|
|
||||||
"""}
|
|
||||||
|
|
||||||
if connection.features.supports_date_lookup_using_string:
|
|
||||||
__test__['API_TESTS'] += r"""
|
|
||||||
# A date lookup can be performed using a string search
|
|
||||||
>>> Article.objects.filter(pub_date__startswith='2005')
|
|
||||||
[<Article: Article 5>, <Article: Article 6>, <Article: Article 4>, <Article: Article 2>, <Article: Article 3>, <Article: Article 7>, <Article: Article 1>]
|
|
||||||
"""
|
|
||||||
|
|
||||||
__test__['API_TESTS'] += r"""
|
|
||||||
# Each QuerySet gets iterator(), which is a generator that "lazily" returns
|
|
||||||
# results using database-level iteration.
|
|
||||||
>>> for a in Article.objects.iterator():
|
|
||||||
... print a.headline
|
|
||||||
Article 5
|
|
||||||
Article 6
|
|
||||||
Article 4
|
|
||||||
Article 2
|
|
||||||
Article 3
|
|
||||||
Article 7
|
|
||||||
Article 1
|
|
||||||
|
|
||||||
# iterator() can be used on any QuerySet.
|
|
||||||
>>> for a in Article.objects.filter(headline__endswith='4').iterator():
|
|
||||||
... print a.headline
|
|
||||||
Article 4
|
|
||||||
|
|
||||||
# count() returns the number of objects matching search criteria.
|
|
||||||
>>> Article.objects.count()
|
|
||||||
7L
|
|
||||||
>>> Article.objects.filter(pub_date__exact=datetime(2005, 7, 27)).count()
|
|
||||||
3L
|
|
||||||
>>> Article.objects.filter(headline__startswith='Blah blah').count()
|
|
||||||
0L
|
|
||||||
|
|
||||||
# count() should respect sliced query sets.
|
|
||||||
>>> articles = Article.objects.all()
|
|
||||||
>>> articles.count()
|
|
||||||
7L
|
|
||||||
>>> articles[:4].count()
|
|
||||||
4
|
|
||||||
>>> articles[1:100].count()
|
|
||||||
6L
|
|
||||||
>>> articles[10:100].count()
|
|
||||||
0
|
|
||||||
|
|
||||||
# Date and date/time lookups can also be done with strings.
|
|
||||||
>>> Article.objects.filter(pub_date__exact='2005-07-27 00:00:00').count()
|
|
||||||
3L
|
|
||||||
|
|
||||||
# in_bulk() takes a list of IDs and returns a dictionary mapping IDs
|
|
||||||
# to objects.
|
|
||||||
>>> arts = Article.objects.in_bulk([1, 2])
|
|
||||||
>>> arts[1]
|
|
||||||
<Article: Article 1>
|
|
||||||
>>> arts[2]
|
|
||||||
<Article: Article 2>
|
|
||||||
>>> Article.objects.in_bulk([3])
|
|
||||||
{3: <Article: Article 3>}
|
|
||||||
>>> Article.objects.in_bulk(set([3]))
|
|
||||||
{3: <Article: Article 3>}
|
|
||||||
>>> Article.objects.in_bulk(frozenset([3]))
|
|
||||||
{3: <Article: Article 3>}
|
|
||||||
>>> Article.objects.in_bulk((3,))
|
|
||||||
{3: <Article: Article 3>}
|
|
||||||
>>> Article.objects.in_bulk([1000])
|
|
||||||
{}
|
|
||||||
>>> Article.objects.in_bulk([])
|
|
||||||
{}
|
|
||||||
>>> Article.objects.in_bulk('foo')
|
|
||||||
Traceback (most recent call last):
|
|
||||||
...
|
|
||||||
AssertionError: in_bulk() must be provided with a list of IDs.
|
|
||||||
>>> Article.objects.in_bulk()
|
|
||||||
Traceback (most recent call last):
|
|
||||||
...
|
|
||||||
TypeError: in_bulk() takes exactly 2 arguments (1 given)
|
|
||||||
>>> Article.objects.in_bulk(headline__startswith='Blah')
|
|
||||||
Traceback (most recent call last):
|
|
||||||
...
|
|
||||||
TypeError: in_bulk() got an unexpected keyword argument 'headline__startswith'
|
|
||||||
|
|
||||||
# values() returns a list of dictionaries instead of object instances -- and
|
|
||||||
# you can specify which fields you want to retrieve.
|
|
||||||
>>> Article.objects.values('headline')
|
|
||||||
[{'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'}]
|
|
||||||
>>> Article.objects.filter(pub_date__exact=datetime(2005, 7, 27)).values('id')
|
|
||||||
[{'id': 2}, {'id': 3}, {'id': 7}]
|
|
||||||
>>> 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'}]
|
|
||||||
True
|
|
||||||
|
|
||||||
>>> for d in Article.objects.values('id', 'headline'):
|
|
||||||
... i = d.items()
|
|
||||||
... i.sort()
|
|
||||||
... i
|
|
||||||
[('headline', u'Article 5'), ('id', 5)]
|
|
||||||
[('headline', u'Article 6'), ('id', 6)]
|
|
||||||
[('headline', u'Article 4'), ('id', 4)]
|
|
||||||
[('headline', u'Article 2'), ('id', 2)]
|
|
||||||
[('headline', u'Article 3'), ('id', 3)]
|
|
||||||
[('headline', u'Article 7'), ('id', 7)]
|
|
||||||
[('headline', u'Article 1'), ('id', 1)]
|
|
||||||
|
|
||||||
# You can use values() with iterator() for memory savings, because iterator()
|
|
||||||
# uses database-level iteration.
|
|
||||||
>>> for d in Article.objects.values('id', 'headline').iterator():
|
|
||||||
... i = d.items()
|
|
||||||
... i.sort()
|
|
||||||
... i
|
|
||||||
[('headline', u'Article 5'), ('id', 5)]
|
|
||||||
[('headline', u'Article 6'), ('id', 6)]
|
|
||||||
[('headline', u'Article 4'), ('id', 4)]
|
|
||||||
[('headline', u'Article 2'), ('id', 2)]
|
|
||||||
[('headline', u'Article 3'), ('id', 3)]
|
|
||||||
[('headline', u'Article 7'), ('id', 7)]
|
|
||||||
[('headline', u'Article 1'), ('id', 1)]
|
|
||||||
|
|
||||||
# The values() method works with "extra" fields specified in extra(select).
|
|
||||||
>>> for d in Article.objects.extra(select={'id_plus_one': 'id + 1'}).values('id', 'id_plus_one'):
|
|
||||||
... i = d.items()
|
|
||||||
... i.sort()
|
|
||||||
... i
|
|
||||||
[('id', 5), ('id_plus_one', 6)]
|
|
||||||
[('id', 6), ('id_plus_one', 7)]
|
|
||||||
[('id', 4), ('id_plus_one', 5)]
|
|
||||||
[('id', 2), ('id_plus_one', 3)]
|
|
||||||
[('id', 3), ('id_plus_one', 4)]
|
|
||||||
[('id', 7), ('id_plus_one', 8)]
|
|
||||||
[('id', 1), ('id_plus_one', 2)]
|
|
||||||
>>> data = {'id_plus_one': 'id+1', 'id_plus_two': 'id+2', 'id_plus_three': 'id+3',
|
|
||||||
... 'id_plus_four': 'id+4', 'id_plus_five': 'id+5', 'id_plus_six': 'id+6',
|
|
||||||
... 'id_plus_seven': 'id+7', 'id_plus_eight': 'id+8'}
|
|
||||||
>>> result = list(Article.objects.filter(id=1).extra(select=data).values(*data.keys()))[0]
|
|
||||||
>>> result = result.items()
|
|
||||||
>>> result.sort()
|
|
||||||
>>> result
|
|
||||||
[('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)]
|
|
||||||
|
|
||||||
# However, an exception FieldDoesNotExist will be thrown if you specify a
|
|
||||||
# non-existent field name in values() (a field that is neither in the model
|
|
||||||
# nor in extra(select)).
|
|
||||||
>>> Article.objects.extra(select={'id_plus_one': 'id + 1'}).values('id', 'id_plus_two')
|
|
||||||
Traceback (most recent call last):
|
|
||||||
...
|
|
||||||
FieldError: Cannot resolve keyword 'id_plus_two' into field. Choices are: headline, id, id_plus_one, pub_date
|
|
||||||
|
|
||||||
# If you don't specify field names to values(), all are returned.
|
|
||||||
>>> list(Article.objects.filter(id=5).values()) == [{'id': 5, 'headline': 'Article 5', 'pub_date': datetime(2005, 8, 1, 9, 0)}]
|
|
||||||
True
|
|
||||||
|
|
||||||
# values_list() is similar to values(), except that the results are returned as
|
|
||||||
# a list of tuples, rather than a list of dictionaries. Within each tuple, the
|
|
||||||
# order of the elemnts is the same as the order of fields in the values_list()
|
|
||||||
# call.
|
|
||||||
>>> Article.objects.values_list('headline')
|
|
||||||
[(u'Article 5',), (u'Article 6',), (u'Article 4',), (u'Article 2',), (u'Article 3',), (u'Article 7',), (u'Article 1',)]
|
|
||||||
|
|
||||||
>>> Article.objects.values_list('id').order_by('id')
|
|
||||||
[(1,), (2,), (3,), (4,), (5,), (6,), (7,)]
|
|
||||||
>>> Article.objects.values_list('id', flat=True).order_by('id')
|
|
||||||
[1, 2, 3, 4, 5, 6, 7]
|
|
||||||
|
|
||||||
>>> Article.objects.extra(select={'id_plus_one': 'id+1'}).order_by('id').values_list('id')
|
|
||||||
[(1,), (2,), (3,), (4,), (5,), (6,), (7,)]
|
|
||||||
>>> Article.objects.extra(select={'id_plus_one': 'id+1'}).order_by('id').values_list('id_plus_one', 'id')
|
|
||||||
[(2, 1), (3, 2), (4, 3), (5, 4), (6, 5), (7, 6), (8, 7)]
|
|
||||||
>>> Article.objects.extra(select={'id_plus_one': 'id+1'}).order_by('id').values_list('id', 'id_plus_one')
|
|
||||||
[(1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (6, 7), (7, 8)]
|
|
||||||
|
|
||||||
>>> Article.objects.values_list('id', 'headline', flat=True)
|
|
||||||
Traceback (most recent call last):
|
|
||||||
...
|
|
||||||
TypeError: 'flat' is not valid when values_list is called with more than one field.
|
|
||||||
|
|
||||||
# Every DateField and DateTimeField creates get_next_by_FOO() and
|
|
||||||
# get_previous_by_FOO() methods.
|
|
||||||
# In the case of identical date values, these methods will use the ID as a
|
|
||||||
# fallback check. This guarantees that no records are skipped or duplicated.
|
|
||||||
>>> a1.get_next_by_pub_date()
|
|
||||||
<Article: Article 2>
|
|
||||||
>>> a2.get_next_by_pub_date()
|
|
||||||
<Article: Article 3>
|
|
||||||
>>> a2.get_next_by_pub_date(headline__endswith='6')
|
|
||||||
<Article: Article 6>
|
|
||||||
>>> a3.get_next_by_pub_date()
|
|
||||||
<Article: Article 7>
|
|
||||||
>>> a4.get_next_by_pub_date()
|
|
||||||
<Article: Article 6>
|
|
||||||
>>> a5.get_next_by_pub_date()
|
|
||||||
Traceback (most recent call last):
|
|
||||||
...
|
|
||||||
DoesNotExist: Article matching query does not exist.
|
|
||||||
>>> a6.get_next_by_pub_date()
|
|
||||||
<Article: Article 5>
|
|
||||||
>>> a7.get_next_by_pub_date()
|
|
||||||
<Article: Article 4>
|
|
||||||
|
|
||||||
>>> a7.get_previous_by_pub_date()
|
|
||||||
<Article: Article 3>
|
|
||||||
>>> a6.get_previous_by_pub_date()
|
|
||||||
<Article: Article 4>
|
|
||||||
>>> a5.get_previous_by_pub_date()
|
|
||||||
<Article: Article 6>
|
|
||||||
>>> a4.get_previous_by_pub_date()
|
|
||||||
<Article: Article 7>
|
|
||||||
>>> a3.get_previous_by_pub_date()
|
|
||||||
<Article: Article 2>
|
|
||||||
>>> a2.get_previous_by_pub_date()
|
|
||||||
<Article: Article 1>
|
|
||||||
|
|
||||||
# Underscores and percent signs have special meaning in the underlying
|
|
||||||
# SQL code, but Django handles the quoting of them automatically.
|
|
||||||
>>> a8 = Article(headline='Article_ with underscore', pub_date=datetime(2005, 11, 20))
|
|
||||||
>>> a8.save()
|
|
||||||
>>> Article.objects.filter(headline__startswith='Article')
|
|
||||||
[<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>]
|
|
||||||
>>> Article.objects.filter(headline__startswith='Article_')
|
|
||||||
[<Article: Article_ with underscore>]
|
|
||||||
|
|
||||||
>>> a9 = Article(headline='Article% with percent sign', pub_date=datetime(2005, 11, 21))
|
|
||||||
>>> a9.save()
|
|
||||||
>>> Article.objects.filter(headline__startswith='Article')
|
|
||||||
[<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>]
|
|
||||||
>>> Article.objects.filter(headline__startswith='Article%')
|
|
||||||
[<Article: Article% with percent sign>]
|
|
||||||
|
|
||||||
# exclude() is the opposite of filter() when doing lookups:
|
|
||||||
>>> Article.objects.filter(headline__contains='Article').exclude(headline__contains='with')
|
|
||||||
[<Article: Article 5>, <Article: Article 6>, <Article: Article 4>, <Article: Article 2>, <Article: Article 3>, <Article: Article 7>, <Article: Article 1>]
|
|
||||||
>>> Article.objects.exclude(headline__startswith="Article_")
|
|
||||||
[<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>]
|
|
||||||
>>> Article.objects.exclude(headline="Article 7")
|
|
||||||
[<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>]
|
|
||||||
|
|
||||||
# Backslashes also have special meaning in the underlying SQL code, but Django
|
|
||||||
# automatically quotes them appropriately.
|
|
||||||
>>> a10 = Article(headline='Article with \\ backslash', pub_date=datetime(2005, 11, 22))
|
|
||||||
>>> a10.save()
|
|
||||||
>>> Article.objects.filter(headline__contains='\\')
|
|
||||||
[<Article: Article with \ backslash>]
|
|
||||||
|
|
||||||
# none() returns an EmptyQuerySet that behaves like any other QuerySet object
|
|
||||||
>>> Article.objects.none()
|
|
||||||
[]
|
|
||||||
>>> Article.objects.none().filter(headline__startswith='Article')
|
|
||||||
[]
|
|
||||||
>>> Article.objects.filter(headline__startswith='Article').none()
|
|
||||||
[]
|
|
||||||
>>> Article.objects.none().count()
|
|
||||||
0
|
|
||||||
>>> Article.objects.none().update(headline="This should not take effect")
|
|
||||||
0
|
|
||||||
>>> [article for article in Article.objects.none().iterator()]
|
|
||||||
[]
|
|
||||||
|
|
||||||
# using __in with an empty list should return an empty query set
|
|
||||||
>>> Article.objects.filter(id__in=[])
|
|
||||||
[]
|
|
||||||
|
|
||||||
>>> Article.objects.exclude(id__in=[])
|
|
||||||
[<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>]
|
|
||||||
|
|
||||||
# Programming errors are pointed out with nice error messages
|
|
||||||
>>> Article.objects.filter(pub_date_year='2005').count()
|
|
||||||
Traceback (most recent call last):
|
|
||||||
...
|
|
||||||
FieldError: Cannot resolve keyword 'pub_date_year' into field. Choices are: headline, id, pub_date
|
|
||||||
|
|
||||||
>>> Article.objects.filter(headline__starts='Article')
|
|
||||||
Traceback (most recent call last):
|
|
||||||
...
|
|
||||||
FieldError: Join on field 'headline' not permitted. Did you misspell 'starts' for the lookup type?
|
|
||||||
|
|
||||||
# Create some articles with a bit more interesting headlines for testing field lookups:
|
|
||||||
>>> now = datetime.now()
|
|
||||||
>>> for a in Article.objects.all():
|
|
||||||
... a.delete()
|
|
||||||
>>> a1 = Article(pub_date=now, headline='f')
|
|
||||||
>>> a1.save()
|
|
||||||
>>> a2 = Article(pub_date=now, headline='fo')
|
|
||||||
>>> a2.save()
|
|
||||||
>>> a3 = Article(pub_date=now, headline='foo')
|
|
||||||
>>> a3.save()
|
|
||||||
>>> a4 = Article(pub_date=now, headline='fooo')
|
|
||||||
>>> a4.save()
|
|
||||||
>>> a5 = Article(pub_date=now, headline='hey-Foo')
|
|
||||||
>>> a5.save()
|
|
||||||
|
|
||||||
# zero-or-more
|
|
||||||
>>> Article.objects.filter(headline__regex=r'fo*')
|
|
||||||
[<Article: f>, <Article: fo>, <Article: foo>, <Article: fooo>]
|
|
||||||
>>> Article.objects.filter(headline__iregex=r'fo*')
|
|
||||||
[<Article: f>, <Article: fo>, <Article: foo>, <Article: fooo>, <Article: hey-Foo>]
|
|
||||||
|
|
||||||
# one-or-more
|
|
||||||
>>> Article.objects.filter(headline__regex=r'fo+')
|
|
||||||
[<Article: fo>, <Article: foo>, <Article: fooo>]
|
|
||||||
|
|
||||||
# wildcard
|
|
||||||
>>> Article.objects.filter(headline__regex=r'fooo?')
|
|
||||||
[<Article: foo>, <Article: fooo>]
|
|
||||||
|
|
||||||
# and some more:
|
|
||||||
>>> a6 = Article(pub_date=now, headline='bar')
|
|
||||||
>>> a6.save()
|
|
||||||
>>> a7 = Article(pub_date=now, headline='AbBa')
|
|
||||||
>>> a7.save()
|
|
||||||
>>> a8 = Article(pub_date=now, headline='baz')
|
|
||||||
>>> a8.save()
|
|
||||||
>>> a9 = Article(pub_date=now, headline='baxZ')
|
|
||||||
>>> a9.save()
|
|
||||||
|
|
||||||
# leading anchor
|
|
||||||
>>> Article.objects.filter(headline__regex=r'^b')
|
|
||||||
[<Article: bar>, <Article: baxZ>, <Article: baz>]
|
|
||||||
>>> Article.objects.filter(headline__iregex=r'^a')
|
|
||||||
[<Article: AbBa>]
|
|
||||||
|
|
||||||
# trailing anchor
|
|
||||||
>>> Article.objects.filter(headline__regex=r'z$')
|
|
||||||
[<Article: baz>]
|
|
||||||
>>> Article.objects.filter(headline__iregex=r'z$')
|
|
||||||
[<Article: baxZ>, <Article: baz>]
|
|
||||||
|
|
||||||
# character sets
|
|
||||||
>>> Article.objects.filter(headline__regex=r'ba[rz]')
|
|
||||||
[<Article: bar>, <Article: baz>]
|
|
||||||
>>> Article.objects.filter(headline__regex=r'ba.[RxZ]')
|
|
||||||
[<Article: baxZ>]
|
|
||||||
>>> Article.objects.filter(headline__iregex=r'ba[RxZ]')
|
|
||||||
[<Article: bar>, <Article: baxZ>, <Article: baz>]
|
|
||||||
|
|
||||||
# and yet more:
|
|
||||||
>>> a10 = Article(pub_date=now, headline='foobar')
|
|
||||||
>>> a10.save()
|
|
||||||
>>> a11 = Article(pub_date=now, headline='foobaz')
|
|
||||||
>>> a11.save()
|
|
||||||
>>> a12 = Article(pub_date=now, headline='ooF')
|
|
||||||
>>> a12.save()
|
|
||||||
>>> a13 = Article(pub_date=now, headline='foobarbaz')
|
|
||||||
>>> a13.save()
|
|
||||||
>>> a14 = Article(pub_date=now, headline='zoocarfaz')
|
|
||||||
>>> a14.save()
|
|
||||||
>>> a15 = Article(pub_date=now, headline='barfoobaz')
|
|
||||||
>>> a15.save()
|
|
||||||
>>> a16 = Article(pub_date=now, headline='bazbaRFOO')
|
|
||||||
>>> a16.save()
|
|
||||||
|
|
||||||
# alternation
|
|
||||||
>>> Article.objects.filter(headline__regex=r'oo(f|b)')
|
|
||||||
[<Article: barfoobaz>, <Article: foobar>, <Article: foobarbaz>, <Article: foobaz>]
|
|
||||||
>>> Article.objects.filter(headline__iregex=r'oo(f|b)')
|
|
||||||
[<Article: barfoobaz>, <Article: foobar>, <Article: foobarbaz>, <Article: foobaz>, <Article: ooF>]
|
|
||||||
>>> Article.objects.filter(headline__regex=r'^foo(f|b)')
|
|
||||||
[<Article: foobar>, <Article: foobarbaz>, <Article: foobaz>]
|
|
||||||
|
|
||||||
# greedy matching
|
|
||||||
>>> Article.objects.filter(headline__regex=r'b.*az')
|
|
||||||
[<Article: barfoobaz>, <Article: baz>, <Article: bazbaRFOO>, <Article: foobarbaz>, <Article: foobaz>]
|
|
||||||
>>> Article.objects.filter(headline__iregex=r'b.*ar')
|
|
||||||
[<Article: bar>, <Article: barfoobaz>, <Article: bazbaRFOO>, <Article: foobar>, <Article: foobarbaz>]
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
if connection.features.supports_regex_backreferencing:
|
|
||||||
__test__['API_TESTS'] += r"""
|
|
||||||
# grouping and backreferences
|
|
||||||
>>> Article.objects.filter(headline__regex=r'b(.).*b\1')
|
|
||||||
[<Article: barfoobaz>, <Article: bazbaRFOO>, <Article: foobarbaz>]
|
|
||||||
"""
|
|
||||||
|
|
|
@ -0,0 +1,543 @@
|
||||||
|
from datetime import datetime
|
||||||
|
from operator import attrgetter
|
||||||
|
from django.core.exceptions import FieldError
|
||||||
|
from django.db import connection
|
||||||
|
from django.test import TestCase, skipUnlessDBFeature
|
||||||
|
from models import Article
|
||||||
|
|
||||||
|
|
||||||
|
class LookupTests(TestCase):
|
||||||
|
|
||||||
|
#def setUp(self):
|
||||||
|
def setUp(self):
|
||||||
|
# Create a couple of Articles.
|
||||||
|
self.a1 = Article(headline='Article 1', pub_date=datetime(2005, 7, 26))
|
||||||
|
self.a1.save()
|
||||||
|
self.a2 = Article(headline='Article 2', pub_date=datetime(2005, 7, 27))
|
||||||
|
self.a2.save()
|
||||||
|
self.a3 = Article(headline='Article 3', pub_date=datetime(2005, 7, 27))
|
||||||
|
self.a3.save()
|
||||||
|
self.a4 = Article(headline='Article 4', pub_date=datetime(2005, 7, 28))
|
||||||
|
self.a4.save()
|
||||||
|
self.a5 = Article(headline='Article 5', pub_date=datetime(2005, 8, 1, 9, 0))
|
||||||
|
self.a5.save()
|
||||||
|
self.a6 = Article(headline='Article 6', pub_date=datetime(2005, 8, 1, 8, 0))
|
||||||
|
self.a6.save()
|
||||||
|
self.a7 = Article(headline='Article 7', pub_date=datetime(2005, 7, 27))
|
||||||
|
self.a7.save()
|
||||||
|
|
||||||
|
def test_exists(self):
|
||||||
|
# We can use .exists() to check that there are some
|
||||||
|
self.assertTrue(Article.objects.exists())
|
||||||
|
for a in Article.objects.all():
|
||||||
|
a.delete()
|
||||||
|
# There should be none now!
|
||||||
|
self.assertFalse(Article.objects.exists())
|
||||||
|
|
||||||
|
def test_lookup_int_as_str(self):
|
||||||
|
# Integer value can be queried using string
|
||||||
|
self.assertQuerysetEqual(Article.objects.filter(id__iexact=str(self.a1.id)),
|
||||||
|
['<Article: Article 1>'])
|
||||||
|
|
||||||
|
@skipUnlessDBFeature('supports_date_lookup_using_string')
|
||||||
|
def test_lookup_date_as_str(self):
|
||||||
|
# A date lookup can be performed using a string search
|
||||||
|
self.assertQuerysetEqual(Article.objects.filter(pub_date__startswith='2005'),
|
||||||
|
[
|
||||||
|
'<Article: Article 5>',
|
||||||
|
'<Article: Article 6>',
|
||||||
|
'<Article: Article 4>',
|
||||||
|
'<Article: Article 2>',
|
||||||
|
'<Article: Article 3>',
|
||||||
|
'<Article: Article 7>',
|
||||||
|
'<Article: Article 1>',
|
||||||
|
])
|
||||||
|
|
||||||
|
def test_iterator(self):
|
||||||
|
# Each QuerySet gets iterator(), which is a generator that "lazily"
|
||||||
|
# returns results using database-level iteration.
|
||||||
|
self.assertQuerysetEqual(Article.objects.iterator(),
|
||||||
|
[
|
||||||
|
'Article 5',
|
||||||
|
'Article 6',
|
||||||
|
'Article 4',
|
||||||
|
'Article 2',
|
||||||
|
'Article 3',
|
||||||
|
'Article 7',
|
||||||
|
'Article 1',
|
||||||
|
],
|
||||||
|
transform=attrgetter('headline'))
|
||||||
|
# iterator() can be used on any QuerySet.
|
||||||
|
self.assertQuerysetEqual(
|
||||||
|
Article.objects.filter(headline__endswith='4').iterator(),
|
||||||
|
['Article 4'],
|
||||||
|
transform=attrgetter('headline'))
|
||||||
|
|
||||||
|
def test_count(self):
|
||||||
|
# count() returns the number of objects matching search criteria.
|
||||||
|
self.assertEqual(Article.objects.count(), 7)
|
||||||
|
self.assertEqual(Article.objects.filter(pub_date__exact=datetime(2005, 7, 27)).count(), 3)
|
||||||
|
self.assertEqual(Article.objects.filter(headline__startswith='Blah blah').count(), 0)
|
||||||
|
|
||||||
|
# count() should respect sliced query sets.
|
||||||
|
articles = Article.objects.all()
|
||||||
|
self.assertEqual(articles.count(), 7)
|
||||||
|
self.assertEqual(articles[:4].count(), 4)
|
||||||
|
self.assertEqual(articles[1:100].count(), 6)
|
||||||
|
self.assertEqual(articles[10:100].count(), 0)
|
||||||
|
|
||||||
|
# Date and date/time lookups can also be done with strings.
|
||||||
|
self.assertEqual(Article.objects.filter(pub_date__exact='2005-07-27 00:00:00').count(), 3)
|
||||||
|
|
||||||
|
def test_in_bulk(self):
|
||||||
|
# in_bulk() takes a list of IDs and returns a dictionary mapping IDs to objects.
|
||||||
|
arts = Article.objects.in_bulk([self.a1.id, self.a2.id])
|
||||||
|
self.assertEqual(arts[self.a1.id], self.a1)
|
||||||
|
self.assertEqual(arts[self.a2.id], self.a2)
|
||||||
|
self.assertEqual(Article.objects.in_bulk([self.a3.id]), {self.a3.id: self.a3})
|
||||||
|
self.assertEqual(Article.objects.in_bulk(set([self.a3.id])), {self.a3.id: self.a3})
|
||||||
|
self.assertEqual(Article.objects.in_bulk(frozenset([self.a3.id])), {self.a3.id: self.a3})
|
||||||
|
self.assertEqual(Article.objects.in_bulk((self.a3.id,)), {self.a3.id: self.a3})
|
||||||
|
self.assertEqual(Article.objects.in_bulk([1000]), {})
|
||||||
|
self.assertEqual(Article.objects.in_bulk([]), {})
|
||||||
|
self.assertRaises(AssertionError, Article.objects.in_bulk, 'foo')
|
||||||
|
self.assertRaises(TypeError, Article.objects.in_bulk)
|
||||||
|
self.assertRaises(TypeError, Article.objects.in_bulk, headline__startswith='Blah')
|
||||||
|
|
||||||
|
def test_values(self):
|
||||||
|
# values() returns a list of dictionaries instead of object instances --
|
||||||
|
# and you can specify which fields you want to retrieve.
|
||||||
|
identity = lambda x:x
|
||||||
|
self.assertQuerysetEqual(Article.objects.values('headline'),
|
||||||
|
[
|
||||||
|
{'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'},
|
||||||
|
],
|
||||||
|
transform=identity)
|
||||||
|
self.assertQuerysetEqual(
|
||||||
|
Article.objects.filter(pub_date__exact=datetime(2005, 7, 27)).values('id'),
|
||||||
|
[{'id': self.a2.id}, {'id': self.a3.id}, {'id': self.a7.id}],
|
||||||
|
transform=identity)
|
||||||
|
self.assertQuerysetEqual(Article.objects.values('id', 'headline'),
|
||||||
|
[
|
||||||
|
{'id': self.a5.id, 'headline': 'Article 5'},
|
||||||
|
{'id': self.a6.id, 'headline': 'Article 6'},
|
||||||
|
{'id': self.a4.id, 'headline': 'Article 4'},
|
||||||
|
{'id': self.a2.id, 'headline': 'Article 2'},
|
||||||
|
{'id': self.a3.id, 'headline': 'Article 3'},
|
||||||
|
{'id': self.a7.id, 'headline': 'Article 7'},
|
||||||
|
{'id': self.a1.id, 'headline': 'Article 1'},
|
||||||
|
],
|
||||||
|
transform=identity)
|
||||||
|
# You can use values() with iterator() for memory savings,
|
||||||
|
# because iterator() uses database-level iteration.
|
||||||
|
self.assertQuerysetEqual(Article.objects.values('id', 'headline').iterator(),
|
||||||
|
[
|
||||||
|
{'headline': u'Article 5', 'id': self.a5.id},
|
||||||
|
{'headline': u'Article 6', 'id': self.a6.id},
|
||||||
|
{'headline': u'Article 4', 'id': self.a4.id},
|
||||||
|
{'headline': u'Article 2', 'id': self.a2.id},
|
||||||
|
{'headline': u'Article 3', 'id': self.a3.id},
|
||||||
|
{'headline': u'Article 7', 'id': self.a7.id},
|
||||||
|
{'headline': u'Article 1', 'id': self.a1.id},
|
||||||
|
],
|
||||||
|
transform=identity)
|
||||||
|
# The values() method works with "extra" fields specified in extra(select).
|
||||||
|
self.assertQuerysetEqual(
|
||||||
|
Article.objects.extra(select={'id_plus_one': 'id + 1'}).values('id', 'id_plus_one'),
|
||||||
|
[
|
||||||
|
{'id': self.a5.id, 'id_plus_one': self.a5.id + 1},
|
||||||
|
{'id': self.a6.id, 'id_plus_one': self.a6.id + 1},
|
||||||
|
{'id': self.a4.id, 'id_plus_one': self.a4.id + 1},
|
||||||
|
{'id': self.a2.id, 'id_plus_one': self.a2.id + 1},
|
||||||
|
{'id': self.a3.id, 'id_plus_one': self.a3.id + 1},
|
||||||
|
{'id': self.a7.id, 'id_plus_one': self.a7.id + 1},
|
||||||
|
{'id': self.a1.id, 'id_plus_one': self.a1.id + 1},
|
||||||
|
],
|
||||||
|
transform=identity)
|
||||||
|
data = {
|
||||||
|
'id_plus_one': 'id+1',
|
||||||
|
'id_plus_two': 'id+2',
|
||||||
|
'id_plus_three': 'id+3',
|
||||||
|
'id_plus_four': 'id+4',
|
||||||
|
'id_plus_five': 'id+5',
|
||||||
|
'id_plus_six': 'id+6',
|
||||||
|
'id_plus_seven': 'id+7',
|
||||||
|
'id_plus_eight': 'id+8',
|
||||||
|
}
|
||||||
|
self.assertQuerysetEqual(
|
||||||
|
Article.objects.filter(id=self.a1.id).extra(select=data).values(*data.keys()),
|
||||||
|
[{
|
||||||
|
'id_plus_one': self.a1.id + 1,
|
||||||
|
'id_plus_two': self.a1.id + 2,
|
||||||
|
'id_plus_three': self.a1.id + 3,
|
||||||
|
'id_plus_four': self.a1.id + 4,
|
||||||
|
'id_plus_five': self.a1.id + 5,
|
||||||
|
'id_plus_six': self.a1.id + 6,
|
||||||
|
'id_plus_seven': self.a1.id + 7,
|
||||||
|
'id_plus_eight': self.a1.id + 8,
|
||||||
|
}], transform=identity)
|
||||||
|
# However, an exception FieldDoesNotExist will be thrown if you specify
|
||||||
|
# a non-existent field name in values() (a field that is neither in the
|
||||||
|
# model nor in extra(select)).
|
||||||
|
self.assertRaises(FieldError,
|
||||||
|
Article.objects.extra(select={'id_plus_one': 'id + 1'}).values,
|
||||||
|
'id', 'id_plus_two')
|
||||||
|
# If you don't specify field names to values(), all are returned.
|
||||||
|
self.assertQuerysetEqual(Article.objects.filter(id=self.a5.id).values(),
|
||||||
|
[{
|
||||||
|
'id': self.a5.id,
|
||||||
|
'headline': 'Article 5',
|
||||||
|
'pub_date': datetime(2005, 8, 1, 9, 0)
|
||||||
|
}], transform=identity)
|
||||||
|
|
||||||
|
def test_values_list(self):
|
||||||
|
# values_list() is similar to values(), except that the results are
|
||||||
|
# returned as a list of tuples, rather than a list of dictionaries.
|
||||||
|
# Within each tuple, the order of the elemnts is the same as the order
|
||||||
|
# of fields in the values_list() call.
|
||||||
|
identity = lambda x:x
|
||||||
|
self.assertQuerysetEqual(Article.objects.values_list('headline'),
|
||||||
|
[
|
||||||
|
(u'Article 5',),
|
||||||
|
(u'Article 6',),
|
||||||
|
(u'Article 4',),
|
||||||
|
(u'Article 2',),
|
||||||
|
(u'Article 3',),
|
||||||
|
(u'Article 7',),
|
||||||
|
(u'Article 1',),
|
||||||
|
], transform=identity)
|
||||||
|
self.assertQuerysetEqual(Article.objects.values_list('id').order_by('id'),
|
||||||
|
[(self.a1.id,), (self.a2.id,), (self.a3.id,), (self.a4.id,), (self.a5.id,), (self.a6.id,), (self.a7.id,)],
|
||||||
|
transform=identity)
|
||||||
|
self.assertQuerysetEqual(
|
||||||
|
Article.objects.values_list('id', flat=True).order_by('id'),
|
||||||
|
[self.a1.id, self.a2.id, self.a3.id, self.a4.id, self.a5.id, self.a6.id, self.a7.id],
|
||||||
|
transform=identity)
|
||||||
|
self.assertQuerysetEqual(
|
||||||
|
Article.objects.extra(select={'id_plus_one': 'id+1'})
|
||||||
|
.order_by('id').values_list('id'),
|
||||||
|
[(self.a1.id,), (self.a2.id,), (self.a3.id,), (self.a4.id,), (self.a5.id,), (self.a6.id,), (self.a7.id,)],
|
||||||
|
transform=identity)
|
||||||
|
self.assertQuerysetEqual(
|
||||||
|
Article.objects.extra(select={'id_plus_one': 'id+1'})
|
||||||
|
.order_by('id').values_list('id_plus_one', 'id'),
|
||||||
|
[
|
||||||
|
(self.a1.id+1, self.a1.id),
|
||||||
|
(self.a2.id+1, self.a2.id),
|
||||||
|
(self.a3.id+1, self.a3.id),
|
||||||
|
(self.a4.id+1, self.a4.id),
|
||||||
|
(self.a5.id+1, self.a5.id),
|
||||||
|
(self.a6.id+1, self.a6.id),
|
||||||
|
(self.a7.id+1, self.a7.id)
|
||||||
|
],
|
||||||
|
transform=identity)
|
||||||
|
self.assertQuerysetEqual(
|
||||||
|
Article.objects.extra(select={'id_plus_one': 'id+1'})
|
||||||
|
.order_by('id').values_list('id', 'id_plus_one'),
|
||||||
|
[
|
||||||
|
(self.a1.id, self.a1.id+1),
|
||||||
|
(self.a2.id, self.a2.id+1),
|
||||||
|
(self.a3.id, self.a3.id+1),
|
||||||
|
(self.a4.id, self.a4.id+1),
|
||||||
|
(self.a5.id, self.a5.id+1),
|
||||||
|
(self.a6.id, self.a6.id+1),
|
||||||
|
(self.a7.id, self.a7.id+1)
|
||||||
|
],
|
||||||
|
transform=identity)
|
||||||
|
self.assertRaises(TypeError, Article.objects.values_list, 'id', 'headline', flat=True)
|
||||||
|
|
||||||
|
def test_get_next_previous_by(self):
|
||||||
|
# Every DateField and DateTimeField creates get_next_by_FOO() and
|
||||||
|
# get_previous_by_FOO() methods. In the case of identical date values,
|
||||||
|
# these methods will use the ID as a fallback check. This guarantees
|
||||||
|
# that no records are skipped or duplicated.
|
||||||
|
self.assertEqual(repr(self.a1.get_next_by_pub_date()),
|
||||||
|
'<Article: Article 2>')
|
||||||
|
self.assertEqual(repr(self.a2.get_next_by_pub_date()),
|
||||||
|
'<Article: Article 3>')
|
||||||
|
self.assertEqual(repr(self.a2.get_next_by_pub_date(headline__endswith='6')),
|
||||||
|
'<Article: Article 6>')
|
||||||
|
self.assertEqual(repr(self.a3.get_next_by_pub_date()),
|
||||||
|
'<Article: Article 7>')
|
||||||
|
self.assertEqual(repr(self.a4.get_next_by_pub_date()),
|
||||||
|
'<Article: Article 6>')
|
||||||
|
self.assertRaises(Article.DoesNotExist, self.a5.get_next_by_pub_date)
|
||||||
|
self.assertEqual(repr(self.a6.get_next_by_pub_date()),
|
||||||
|
'<Article: Article 5>')
|
||||||
|
self.assertEqual(repr(self.a7.get_next_by_pub_date()),
|
||||||
|
'<Article: Article 4>')
|
||||||
|
|
||||||
|
self.assertEqual(repr(self.a7.get_previous_by_pub_date()),
|
||||||
|
'<Article: Article 3>')
|
||||||
|
self.assertEqual(repr(self.a6.get_previous_by_pub_date()),
|
||||||
|
'<Article: Article 4>')
|
||||||
|
self.assertEqual(repr(self.a5.get_previous_by_pub_date()),
|
||||||
|
'<Article: Article 6>')
|
||||||
|
self.assertEqual(repr(self.a4.get_previous_by_pub_date()),
|
||||||
|
'<Article: Article 7>')
|
||||||
|
self.assertEqual(repr(self.a3.get_previous_by_pub_date()),
|
||||||
|
'<Article: Article 2>')
|
||||||
|
self.assertEqual(repr(self.a2.get_previous_by_pub_date()),
|
||||||
|
'<Article: Article 1>')
|
||||||
|
|
||||||
|
def test_escaping(self):
|
||||||
|
# Underscores, percent signs and backslashes have special meaning in the
|
||||||
|
# underlying SQL code, but Django handles the quoting of them automatically.
|
||||||
|
a8 = Article(headline='Article_ with underscore', pub_date=datetime(2005, 11, 20))
|
||||||
|
a8.save()
|
||||||
|
self.assertQuerysetEqual(Article.objects.filter(headline__startswith='Article'),
|
||||||
|
[
|
||||||
|
'<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>',
|
||||||
|
])
|
||||||
|
self.assertQuerysetEqual(Article.objects.filter(headline__startswith='Article_'),
|
||||||
|
['<Article: Article_ with underscore>'])
|
||||||
|
a9 = Article(headline='Article% with percent sign', pub_date=datetime(2005, 11, 21))
|
||||||
|
a9.save()
|
||||||
|
self.assertQuerysetEqual(Article.objects.filter(headline__startswith='Article'),
|
||||||
|
[
|
||||||
|
'<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>',
|
||||||
|
])
|
||||||
|
self.assertQuerysetEqual(Article.objects.filter(headline__startswith='Article%'),
|
||||||
|
['<Article: Article% with percent sign>'])
|
||||||
|
a10 = Article(headline='Article with \\ backslash', pub_date=datetime(2005, 11, 22))
|
||||||
|
a10.save()
|
||||||
|
self.assertQuerysetEqual(Article.objects.filter(headline__contains='\\'),
|
||||||
|
['<Article: Article with \ backslash>'])
|
||||||
|
|
||||||
|
def test_exclude(self):
|
||||||
|
a8 = Article.objects.create(headline='Article_ with underscore', pub_date=datetime(2005, 11, 20))
|
||||||
|
a9 = Article.objects.create(headline='Article% with percent sign', pub_date=datetime(2005, 11, 21))
|
||||||
|
a10 = Article.objects.create(headline='Article with \\ backslash', pub_date=datetime(2005, 11, 22))
|
||||||
|
|
||||||
|
# exclude() is the opposite of filter() when doing lookups:
|
||||||
|
self.assertQuerysetEqual(
|
||||||
|
Article.objects.filter(headline__contains='Article').exclude(headline__contains='with'),
|
||||||
|
[
|
||||||
|
'<Article: Article 5>',
|
||||||
|
'<Article: Article 6>',
|
||||||
|
'<Article: Article 4>',
|
||||||
|
'<Article: Article 2>',
|
||||||
|
'<Article: Article 3>',
|
||||||
|
'<Article: Article 7>',
|
||||||
|
'<Article: Article 1>',
|
||||||
|
])
|
||||||
|
self.assertQuerysetEqual(Article.objects.exclude(headline__startswith="Article_"),
|
||||||
|
[
|
||||||
|
'<Article: Article with \\ backslash>',
|
||||||
|
'<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>',
|
||||||
|
])
|
||||||
|
self.assertQuerysetEqual(Article.objects.exclude(headline="Article 7"),
|
||||||
|
[
|
||||||
|
'<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 1>',
|
||||||
|
])
|
||||||
|
|
||||||
|
def test_none(self):
|
||||||
|
# none() returns an EmptyQuerySet that behaves like any other QuerySet object
|
||||||
|
self.assertQuerysetEqual(Article.objects.none(), [])
|
||||||
|
self.assertQuerysetEqual(
|
||||||
|
Article.objects.none().filter(headline__startswith='Article'), [])
|
||||||
|
self.assertQuerysetEqual(
|
||||||
|
Article.objects.filter(headline__startswith='Article').none(), [])
|
||||||
|
self.assertEqual(Article.objects.none().count(), 0)
|
||||||
|
self.assertEqual(
|
||||||
|
Article.objects.none().update(headline="This should not take effect"), 0)
|
||||||
|
self.assertQuerysetEqual(
|
||||||
|
[article for article in Article.objects.none().iterator()],
|
||||||
|
[])
|
||||||
|
|
||||||
|
def test_in(self):
|
||||||
|
# using __in with an empty list should return an empty query set
|
||||||
|
self.assertQuerysetEqual(Article.objects.filter(id__in=[]), [])
|
||||||
|
self.assertQuerysetEqual(Article.objects.exclude(id__in=[]),
|
||||||
|
[
|
||||||
|
'<Article: Article 5>',
|
||||||
|
'<Article: Article 6>',
|
||||||
|
'<Article: Article 4>',
|
||||||
|
'<Article: Article 2>',
|
||||||
|
'<Article: Article 3>',
|
||||||
|
'<Article: Article 7>',
|
||||||
|
'<Article: Article 1>',
|
||||||
|
])
|
||||||
|
|
||||||
|
def test_error_messages(self):
|
||||||
|
# Programming errors are pointed out with nice error messages
|
||||||
|
try:
|
||||||
|
Article.objects.filter(pub_date_year='2005').count()
|
||||||
|
self.fail('FieldError not raised')
|
||||||
|
except FieldError, ex:
|
||||||
|
self.assertEqual(str(ex), "Cannot resolve keyword 'pub_date_year' "
|
||||||
|
"into field. Choices are: headline, id, pub_date")
|
||||||
|
try:
|
||||||
|
Article.objects.filter(headline__starts='Article')
|
||||||
|
self.fail('FieldError not raised')
|
||||||
|
except FieldError, ex:
|
||||||
|
self.assertEqual(str(ex), "Join on field 'headline' not permitted. "
|
||||||
|
"Did you misspell 'starts' for the lookup type?")
|
||||||
|
|
||||||
|
def test_regex(self):
|
||||||
|
# Create some articles with a bit more interesting headlines for testing field lookups:
|
||||||
|
for a in Article.objects.all():
|
||||||
|
a.delete()
|
||||||
|
now = datetime.now()
|
||||||
|
a1 = Article(pub_date=now, headline='f')
|
||||||
|
a1.save()
|
||||||
|
a2 = Article(pub_date=now, headline='fo')
|
||||||
|
a2.save()
|
||||||
|
a3 = Article(pub_date=now, headline='foo')
|
||||||
|
a3.save()
|
||||||
|
a4 = Article(pub_date=now, headline='fooo')
|
||||||
|
a4.save()
|
||||||
|
a5 = Article(pub_date=now, headline='hey-Foo')
|
||||||
|
a5.save()
|
||||||
|
a6 = Article(pub_date=now, headline='bar')
|
||||||
|
a6.save()
|
||||||
|
a7 = Article(pub_date=now, headline='AbBa')
|
||||||
|
a7.save()
|
||||||
|
a8 = Article(pub_date=now, headline='baz')
|
||||||
|
a8.save()
|
||||||
|
a9 = Article(pub_date=now, headline='baxZ')
|
||||||
|
a9.save()
|
||||||
|
# zero-or-more
|
||||||
|
self.assertQuerysetEqual(Article.objects.filter(headline__regex=r'fo*'),
|
||||||
|
['<Article: f>', '<Article: fo>', '<Article: foo>', '<Article: fooo>'])
|
||||||
|
self.assertQuerysetEqual(Article.objects.filter(headline__iregex=r'fo*'),
|
||||||
|
[
|
||||||
|
'<Article: f>',
|
||||||
|
'<Article: fo>',
|
||||||
|
'<Article: foo>',
|
||||||
|
'<Article: fooo>',
|
||||||
|
'<Article: hey-Foo>',
|
||||||
|
])
|
||||||
|
# one-or-more
|
||||||
|
self.assertQuerysetEqual(Article.objects.filter(headline__regex=r'fo+'),
|
||||||
|
['<Article: fo>', '<Article: foo>', '<Article: fooo>'])
|
||||||
|
# wildcard
|
||||||
|
self.assertQuerysetEqual(Article.objects.filter(headline__regex=r'fooo?'),
|
||||||
|
['<Article: foo>', '<Article: fooo>'])
|
||||||
|
# leading anchor
|
||||||
|
self.assertQuerysetEqual(Article.objects.filter(headline__regex=r'^b'),
|
||||||
|
['<Article: bar>', '<Article: baxZ>', '<Article: baz>'])
|
||||||
|
self.assertQuerysetEqual(Article.objects.filter(headline__iregex=r'^a'),
|
||||||
|
['<Article: AbBa>'])
|
||||||
|
# trailing anchor
|
||||||
|
self.assertQuerysetEqual(Article.objects.filter(headline__regex=r'z$'),
|
||||||
|
['<Article: baz>'])
|
||||||
|
self.assertQuerysetEqual(Article.objects.filter(headline__iregex=r'z$'),
|
||||||
|
['<Article: baxZ>', '<Article: baz>'])
|
||||||
|
# character sets
|
||||||
|
self.assertQuerysetEqual(Article.objects.filter(headline__regex=r'ba[rz]'),
|
||||||
|
['<Article: bar>', '<Article: baz>'])
|
||||||
|
self.assertQuerysetEqual(Article.objects.filter(headline__regex=r'ba.[RxZ]'),
|
||||||
|
['<Article: baxZ>'])
|
||||||
|
self.assertQuerysetEqual(Article.objects.filter(headline__iregex=r'ba[RxZ]'),
|
||||||
|
['<Article: bar>', '<Article: baxZ>', '<Article: baz>'])
|
||||||
|
|
||||||
|
# and more articles:
|
||||||
|
a10 = Article(pub_date=now, headline='foobar')
|
||||||
|
a10.save()
|
||||||
|
a11 = Article(pub_date=now, headline='foobaz')
|
||||||
|
a11.save()
|
||||||
|
a12 = Article(pub_date=now, headline='ooF')
|
||||||
|
a12.save()
|
||||||
|
a13 = Article(pub_date=now, headline='foobarbaz')
|
||||||
|
a13.save()
|
||||||
|
a14 = Article(pub_date=now, headline='zoocarfaz')
|
||||||
|
a14.save()
|
||||||
|
a15 = Article(pub_date=now, headline='barfoobaz')
|
||||||
|
a15.save()
|
||||||
|
a16 = Article(pub_date=now, headline='bazbaRFOO')
|
||||||
|
a16.save()
|
||||||
|
|
||||||
|
# alternation
|
||||||
|
self.assertQuerysetEqual(Article.objects.filter(headline__regex=r'oo(f|b)'),
|
||||||
|
[
|
||||||
|
'<Article: barfoobaz>',
|
||||||
|
'<Article: foobar>',
|
||||||
|
'<Article: foobarbaz>',
|
||||||
|
'<Article: foobaz>',
|
||||||
|
])
|
||||||
|
self.assertQuerysetEqual(Article.objects.filter(headline__iregex=r'oo(f|b)'),
|
||||||
|
[
|
||||||
|
'<Article: barfoobaz>',
|
||||||
|
'<Article: foobar>',
|
||||||
|
'<Article: foobarbaz>',
|
||||||
|
'<Article: foobaz>',
|
||||||
|
'<Article: ooF>',
|
||||||
|
])
|
||||||
|
self.assertQuerysetEqual(Article.objects.filter(headline__regex=r'^foo(f|b)'),
|
||||||
|
['<Article: foobar>', '<Article: foobarbaz>', '<Article: foobaz>'])
|
||||||
|
|
||||||
|
# greedy matching
|
||||||
|
self.assertQuerysetEqual(Article.objects.filter(headline__regex=r'b.*az'),
|
||||||
|
[
|
||||||
|
'<Article: barfoobaz>',
|
||||||
|
'<Article: baz>',
|
||||||
|
'<Article: bazbaRFOO>',
|
||||||
|
'<Article: foobarbaz>',
|
||||||
|
'<Article: foobaz>',
|
||||||
|
])
|
||||||
|
self.assertQuerysetEqual(Article.objects.filter(headline__iregex=r'b.*ar'),
|
||||||
|
[
|
||||||
|
'<Article: bar>',
|
||||||
|
'<Article: barfoobaz>',
|
||||||
|
'<Article: bazbaRFOO>',
|
||||||
|
'<Article: foobar>',
|
||||||
|
'<Article: foobarbaz>',
|
||||||
|
])
|
||||||
|
|
||||||
|
@skipUnlessDBFeature('supports_regex_backreferencing')
|
||||||
|
def test_regex_backreferencing(self):
|
||||||
|
# grouping and backreferences
|
||||||
|
now = datetime.now()
|
||||||
|
a10 = Article(pub_date=now, headline='foobar')
|
||||||
|
a10.save()
|
||||||
|
a11 = Article(pub_date=now, headline='foobaz')
|
||||||
|
a11.save()
|
||||||
|
a12 = Article(pub_date=now, headline='ooF')
|
||||||
|
a12.save()
|
||||||
|
a13 = Article(pub_date=now, headline='foobarbaz')
|
||||||
|
a13.save()
|
||||||
|
a14 = Article(pub_date=now, headline='zoocarfaz')
|
||||||
|
a14.save()
|
||||||
|
a15 = Article(pub_date=now, headline='barfoobaz')
|
||||||
|
a15.save()
|
||||||
|
a16 = Article(pub_date=now, headline='bazbaRFOO')
|
||||||
|
a16.save()
|
||||||
|
self.assertQuerysetEqual(Article.objects.filter(headline__regex=r'b(.).*b\1'),
|
||||||
|
['<Article: barfoobaz>', '<Article: bazbaRFOO>', '<Article: foobarbaz>'])
|
Loading…
Reference in New Issue