Fixed #31235 -- Made assertQuerysetEqual() compare querysets directly.
This also replaces assertQuerysetEqual() to assertSequenceEqual()/assertCountEqual() where appropriate. Co-authored-by: Peter Inglesby <peter.inglesby@gmail.com> Co-authored-by: Mariusz Felisiak <felisiak.mariusz@gmail.com>
This commit is contained in:
parent
13b6fff117
commit
3f7b327562
|
@ -1040,11 +1040,29 @@ class TransactionTestCase(SimpleTestCase):
|
||||||
allow_cascade=self.available_apps is not None,
|
allow_cascade=self.available_apps is not None,
|
||||||
inhibit_post_migrate=inhibit_post_migrate)
|
inhibit_post_migrate=inhibit_post_migrate)
|
||||||
|
|
||||||
def assertQuerysetEqual(self, qs, values, transform=repr, ordered=True, msg=None):
|
def assertQuerysetEqual(self, qs, values, transform=None, ordered=True, msg=None):
|
||||||
items = map(transform, qs)
|
values = list(values)
|
||||||
|
# RemovedInDjango41Warning.
|
||||||
|
if transform is None:
|
||||||
|
if (
|
||||||
|
values and isinstance(values[0], str) and
|
||||||
|
qs and not isinstance(qs[0], str)
|
||||||
|
):
|
||||||
|
# Transform qs using repr() if the first element of values is a
|
||||||
|
# string and the first element of qs is not (which would be the
|
||||||
|
# case if qs is a flattened values_list).
|
||||||
|
warnings.warn(
|
||||||
|
"In Django 4.1, repr() will not be called automatically "
|
||||||
|
"on a queryset when compared to string values. Set an "
|
||||||
|
"explicit 'transform' to silence this warning.",
|
||||||
|
category=RemovedInDjango41Warning,
|
||||||
|
)
|
||||||
|
transform = repr
|
||||||
|
items = qs
|
||||||
|
if transform is not None:
|
||||||
|
items = map(transform, items)
|
||||||
if not ordered:
|
if not ordered:
|
||||||
return self.assertEqual(Counter(items), Counter(values), msg=msg)
|
return self.assertEqual(Counter(items), Counter(values), msg=msg)
|
||||||
values = list(values)
|
|
||||||
# For example qs.iterator() could be passed as qs, but it does not
|
# For example qs.iterator() could be passed as qs, but it does not
|
||||||
# have 'ordered' attribute.
|
# have 'ordered' attribute.
|
||||||
if len(values) > 1 and hasattr(qs, 'ordered') and not qs.ordered:
|
if len(values) > 1 and hasattr(qs, 'ordered') and not qs.ordered:
|
||||||
|
|
|
@ -26,6 +26,9 @@ details on these changes.
|
||||||
|
|
||||||
* The ``default_app_config`` module variable will be removed.
|
* The ``default_app_config`` module variable will be removed.
|
||||||
|
|
||||||
|
* ``TransactionTestCase.assertQuerysetEqual()` will no longer automatically
|
||||||
|
call ``repr()`` on a queryset when compared to string values.
|
||||||
|
|
||||||
.. _deprecation-removed-in-4.0:
|
.. _deprecation-removed-in-4.0:
|
||||||
|
|
||||||
4.0
|
4.0
|
||||||
|
|
|
@ -498,11 +498,11 @@ class:
|
||||||
Questions with a pub_date in the past are displayed on the
|
Questions with a pub_date in the past are displayed on the
|
||||||
index page.
|
index page.
|
||||||
"""
|
"""
|
||||||
create_question(question_text="Past question.", days=-30)
|
question = create_question(question_text="Past question.", days=-30)
|
||||||
response = self.client.get(reverse('polls:index'))
|
response = self.client.get(reverse('polls:index'))
|
||||||
self.assertQuerysetEqual(
|
self.assertQuerysetEqual(
|
||||||
response.context['latest_question_list'],
|
response.context['latest_question_list'],
|
||||||
['<Question: Past question.>']
|
[question],
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_future_question(self):
|
def test_future_question(self):
|
||||||
|
@ -520,24 +520,24 @@ class:
|
||||||
Even if both past and future questions exist, only past questions
|
Even if both past and future questions exist, only past questions
|
||||||
are displayed.
|
are displayed.
|
||||||
"""
|
"""
|
||||||
create_question(question_text="Past question.", days=-30)
|
question = create_question(question_text="Past question.", days=-30)
|
||||||
create_question(question_text="Future question.", days=30)
|
create_question(question_text="Future question.", days=30)
|
||||||
response = self.client.get(reverse('polls:index'))
|
response = self.client.get(reverse('polls:index'))
|
||||||
self.assertQuerysetEqual(
|
self.assertQuerysetEqual(
|
||||||
response.context['latest_question_list'],
|
response.context['latest_question_list'],
|
||||||
['<Question: Past question.>']
|
[question],
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_two_past_questions(self):
|
def test_two_past_questions(self):
|
||||||
"""
|
"""
|
||||||
The questions index page may display multiple questions.
|
The questions index page may display multiple questions.
|
||||||
"""
|
"""
|
||||||
create_question(question_text="Past question 1.", days=-30)
|
question1 = create_question(question_text="Past question 1.", days=-30)
|
||||||
create_question(question_text="Past question 2.", days=-5)
|
question2 = create_question(question_text="Past question 2.", days=-5)
|
||||||
response = self.client.get(reverse('polls:index'))
|
response = self.client.get(reverse('polls:index'))
|
||||||
self.assertQuerysetEqual(
|
self.assertQuerysetEqual(
|
||||||
response.context['latest_question_list'],
|
response.context['latest_question_list'],
|
||||||
['<Question: Past question 2.>', '<Question: Past question 1.>']
|
[question2, question1],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -422,6 +422,11 @@ Tests
|
||||||
<django.db.transaction.on_commit>` in a list. This allows you to test such
|
<django.db.transaction.on_commit>` in a list. This allows you to test such
|
||||||
callbacks without using the slower :class:`.TransactionTestCase`.
|
callbacks without using the slower :class:`.TransactionTestCase`.
|
||||||
|
|
||||||
|
* :meth:`.TransactionTestCase.assertQuerysetEqual` now supports direct
|
||||||
|
comparison against another queryset rather than being restricted to
|
||||||
|
comparison against a list of string representations of objects when using the
|
||||||
|
default value for the ``transform`` argument.
|
||||||
|
|
||||||
URLs
|
URLs
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
|
@ -615,3 +620,8 @@ Miscellaneous
|
||||||
* The ``default_app_config`` application configuration variable is deprecated,
|
* The ``default_app_config`` application configuration variable is deprecated,
|
||||||
due to the now automatic ``AppConfig`` discovery. See :ref:`whats-new-3.2`
|
due to the now automatic ``AppConfig`` discovery. See :ref:`whats-new-3.2`
|
||||||
for more details.
|
for more details.
|
||||||
|
|
||||||
|
* Automatically calling ``repr()`` on a queryset in
|
||||||
|
``TransactionTestCase.assertQuerysetEqual()``, when compared to string
|
||||||
|
values, is deprecated. If you need the previous behavior, explicitly set
|
||||||
|
``transform`` to ``repr``.
|
||||||
|
|
|
@ -1683,15 +1683,13 @@ your test suite.
|
||||||
|
|
||||||
Output in case of error can be customized with the ``msg`` argument.
|
Output in case of error can be customized with the ``msg`` argument.
|
||||||
|
|
||||||
.. method:: TransactionTestCase.assertQuerysetEqual(qs, values, transform=repr, ordered=True, msg=None)
|
.. method:: TransactionTestCase.assertQuerysetEqual(qs, values, transform=None, ordered=True, msg=None)
|
||||||
|
|
||||||
Asserts that a queryset ``qs`` returns a particular list of values ``values``.
|
Asserts that a queryset ``qs`` matches a particular iterable of values
|
||||||
|
``values``.
|
||||||
|
|
||||||
The comparison of the contents of ``qs`` and ``values`` is performed by
|
If ``transform`` is provided, ``values`` is compared to a list produced by
|
||||||
applying ``transform`` to ``qs``. By default, this means that the
|
applying ``transform`` to each member of ``qs``.
|
||||||
``repr()`` of each value in ``qs`` is compared to the ``values``. Any other
|
|
||||||
callable can be used if ``repr()`` doesn't provide a unique or helpful
|
|
||||||
comparison.
|
|
||||||
|
|
||||||
By default, the comparison is also ordering dependent. If ``qs`` doesn't
|
By default, the comparison is also ordering dependent. If ``qs`` doesn't
|
||||||
provide an implicit ordering, you can set the ``ordered`` parameter to
|
provide an implicit ordering, you can set the ``ordered`` parameter to
|
||||||
|
@ -1702,6 +1700,21 @@ your test suite.
|
||||||
|
|
||||||
Output in case of error can be customized with the ``msg`` argument.
|
Output in case of error can be customized with the ``msg`` argument.
|
||||||
|
|
||||||
|
.. versionchanged:: 3.2
|
||||||
|
|
||||||
|
The default value of ``transform`` argument was changed to ``None``.
|
||||||
|
|
||||||
|
.. versionadded:: 3.2
|
||||||
|
|
||||||
|
Support for direct comparison between querysets was added.
|
||||||
|
|
||||||
|
.. deprecated:: 3.2
|
||||||
|
|
||||||
|
If ``transform`` is not provided and ``values`` is a list of strings,
|
||||||
|
it's compared to a list produced by applying ``repr()`` to each member
|
||||||
|
of ``qs``. This behavior is deprecated and will be removed in Django
|
||||||
|
4.1. If you need it, explicitly set ``transform`` to ``repr``.
|
||||||
|
|
||||||
.. method:: TransactionTestCase.assertNumQueries(num, func, *args, **kwargs)
|
.. method:: TransactionTestCase.assertNumQueries(num, func, *args, **kwargs)
|
||||||
|
|
||||||
Asserts that when ``func`` is called with ``*args`` and ``**kwargs`` that
|
Asserts that when ``func`` is called with ``*args`` and ``**kwargs`` that
|
||||||
|
|
|
@ -750,13 +750,13 @@ class AggregateTestCase(TestCase):
|
||||||
number of authors.
|
number of authors.
|
||||||
"""
|
"""
|
||||||
dates = Book.objects.annotate(num_authors=Count("authors")).dates('pubdate', 'year')
|
dates = Book.objects.annotate(num_authors=Count("authors")).dates('pubdate', 'year')
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
dates, [
|
dates, [
|
||||||
"datetime.date(1991, 1, 1)",
|
datetime.date(1991, 1, 1),
|
||||||
"datetime.date(1995, 1, 1)",
|
datetime.date(1995, 1, 1),
|
||||||
"datetime.date(2007, 1, 1)",
|
datetime.date(2007, 1, 1),
|
||||||
"datetime.date(2008, 1, 1)"
|
datetime.date(2008, 1, 1),
|
||||||
]
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_values_aggregation(self):
|
def test_values_aggregation(self):
|
||||||
|
|
|
@ -161,13 +161,11 @@ class ModelTest(TestCase):
|
||||||
Article(headline=headline, pub_date=some_pub_date).save()
|
Article(headline=headline, pub_date=some_pub_date).save()
|
||||||
self.assertQuerysetEqual(
|
self.assertQuerysetEqual(
|
||||||
Article.objects.all().order_by('headline'),
|
Article.objects.all().order_by('headline'),
|
||||||
["<Article: Amazing article>",
|
sorted(headlines),
|
||||||
"<Article: An article>",
|
transform=lambda a: a.headline,
|
||||||
"<Article: Article One>",
|
|
||||||
"<Article: Boring article>"]
|
|
||||||
)
|
)
|
||||||
Article.objects.filter(headline__startswith='A').delete()
|
Article.objects.filter(headline__startswith='A').delete()
|
||||||
self.assertQuerysetEqual(Article.objects.all().order_by('headline'), ["<Article: Boring article>"])
|
self.assertEqual(Article.objects.get().headline, 'Boring article')
|
||||||
|
|
||||||
def test_not_equal_and_equal_operators_behave_as_expected_on_instances(self):
|
def test_not_equal_and_equal_operators_behave_as_expected_on_instances(self):
|
||||||
some_pub_date = datetime(2014, 5, 16, 12, 1)
|
some_pub_date = datetime(2014, 5, 16, 12, 1)
|
||||||
|
@ -208,17 +206,17 @@ class ModelTest(TestCase):
|
||||||
def test_year_lookup_edge_case(self):
|
def test_year_lookup_edge_case(self):
|
||||||
# Edge-case test: A year lookup should retrieve all objects in
|
# Edge-case test: A year lookup should retrieve all objects in
|
||||||
# the given year, including Jan. 1 and Dec. 31.
|
# the given year, including Jan. 1 and Dec. 31.
|
||||||
Article.objects.create(
|
a11 = Article.objects.create(
|
||||||
headline='Article 11',
|
headline='Article 11',
|
||||||
pub_date=datetime(2008, 1, 1),
|
pub_date=datetime(2008, 1, 1),
|
||||||
)
|
)
|
||||||
Article.objects.create(
|
a12 = Article.objects.create(
|
||||||
headline='Article 12',
|
headline='Article 12',
|
||||||
pub_date=datetime(2008, 12, 31, 23, 59, 59, 999999),
|
pub_date=datetime(2008, 12, 31, 23, 59, 59, 999999),
|
||||||
)
|
)
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
Article.objects.filter(pub_date__year=2008),
|
Article.objects.filter(pub_date__year=2008),
|
||||||
["<Article: Article 11>", "<Article: Article 12>"]
|
[a11, a12],
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_unicode_data(self):
|
def test_unicode_data(self):
|
||||||
|
@ -442,7 +440,7 @@ class ModelLookupTest(TestCase):
|
||||||
self.a.save()
|
self.a.save()
|
||||||
|
|
||||||
# Article.objects.all() returns all the articles in the database.
|
# Article.objects.all() returns all the articles in the database.
|
||||||
self.assertQuerysetEqual(Article.objects.all(), ['<Article: Parrot programs in Python>'])
|
self.assertSequenceEqual(Article.objects.all(), [self.a])
|
||||||
|
|
||||||
def test_rich_lookup(self):
|
def test_rich_lookup(self):
|
||||||
# Django provides a rich database lookup API.
|
# Django provides a rich database lookup API.
|
||||||
|
@ -458,24 +456,24 @@ class ModelLookupTest(TestCase):
|
||||||
self.assertEqual(Article.objects.get(id=self.a.id), self.a)
|
self.assertEqual(Article.objects.get(id=self.a.id), self.a)
|
||||||
self.assertEqual(Article.objects.get(headline='Swallow programs in Python'), self.a)
|
self.assertEqual(Article.objects.get(headline='Swallow programs in Python'), self.a)
|
||||||
|
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
Article.objects.filter(pub_date__year=2005),
|
Article.objects.filter(pub_date__year=2005),
|
||||||
['<Article: Swallow programs in Python>'],
|
[self.a],
|
||||||
)
|
)
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
Article.objects.filter(pub_date__year=2004),
|
Article.objects.filter(pub_date__year=2004),
|
||||||
[],
|
[],
|
||||||
)
|
)
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
Article.objects.filter(pub_date__year=2005, pub_date__month=7),
|
Article.objects.filter(pub_date__year=2005, pub_date__month=7),
|
||||||
['<Article: Swallow programs in Python>'],
|
[self.a],
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
Article.objects.filter(pub_date__week_day=5),
|
Article.objects.filter(pub_date__week_day=5),
|
||||||
['<Article: Swallow programs in Python>'],
|
[self.a],
|
||||||
)
|
)
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
Article.objects.filter(pub_date__week_day=6),
|
Article.objects.filter(pub_date__week_day=6),
|
||||||
[],
|
[],
|
||||||
)
|
)
|
||||||
|
@ -499,7 +497,7 @@ class ModelLookupTest(TestCase):
|
||||||
self.assertEqual(Article.objects.get(pk=self.a.id), self.a)
|
self.assertEqual(Article.objects.get(pk=self.a.id), self.a)
|
||||||
|
|
||||||
# pk can be used as a shortcut for the primary key name in any query.
|
# pk can be used as a shortcut for the primary key name in any query.
|
||||||
self.assertQuerysetEqual(Article.objects.filter(pk__in=[self.a.id]), ["<Article: Swallow programs in Python>"])
|
self.assertSequenceEqual(Article.objects.filter(pk__in=[self.a.id]), [self.a])
|
||||||
|
|
||||||
# Model instances of the same type and same ID are considered equal.
|
# Model instances of the same type and same ID are considered equal.
|
||||||
a = Article.objects.get(pk=self.a.id)
|
a = Article.objects.get(pk=self.a.id)
|
||||||
|
|
|
@ -78,15 +78,15 @@ class CustomColumnsTests(TestCase):
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_author_querying(self):
|
def test_author_querying(self):
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
Author.objects.all().order_by('last_name'),
|
Author.objects.all().order_by('last_name'),
|
||||||
['<Author: Peter Jones>', '<Author: John Smith>']
|
[self.a2, self.a1],
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_author_filtering(self):
|
def test_author_filtering(self):
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
Author.objects.filter(first_name__exact='John'),
|
Author.objects.filter(first_name__exact='John'),
|
||||||
['<Author: John Smith>']
|
[self.a1],
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_author_get(self):
|
def test_author_get(self):
|
||||||
|
@ -111,15 +111,12 @@ class CustomColumnsTests(TestCase):
|
||||||
getattr(a, 'last')
|
getattr(a, 'last')
|
||||||
|
|
||||||
def test_m2m_table(self):
|
def test_m2m_table(self):
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
self.article.authors.all().order_by('last_name'),
|
self.article.authors.all().order_by('last_name'),
|
||||||
['<Author: Peter Jones>', '<Author: John Smith>']
|
[self.a2, self.a1],
|
||||||
)
|
)
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(self.a1.article_set.all(), [self.article])
|
||||||
self.a1.article_set.all(),
|
self.assertSequenceEqual(
|
||||||
['<Article: Django lets you build Web apps easily>']
|
|
||||||
)
|
|
||||||
self.assertQuerysetEqual(
|
|
||||||
self.article.authors.filter(last_name='Jones'),
|
self.article.authors.filter(last_name='Jones'),
|
||||||
['<Author: Peter Jones>']
|
[self.a2],
|
||||||
)
|
)
|
||||||
|
|
|
@ -308,17 +308,17 @@ class BilateralTransformTests(TestCase):
|
||||||
|
|
||||||
def test_bilateral_upper(self):
|
def test_bilateral_upper(self):
|
||||||
with register_lookup(models.CharField, UpperBilateralTransform):
|
with register_lookup(models.CharField, UpperBilateralTransform):
|
||||||
Author.objects.bulk_create([
|
author1 = Author.objects.create(name='Doe')
|
||||||
Author(name='Doe'),
|
author2 = Author.objects.create(name='doe')
|
||||||
Author(name='doe'),
|
author3 = Author.objects.create(name='Foo')
|
||||||
Author(name='Foo'),
|
self.assertCountEqual(
|
||||||
])
|
|
||||||
self.assertQuerysetEqual(
|
|
||||||
Author.objects.filter(name__upper='doe'),
|
Author.objects.filter(name__upper='doe'),
|
||||||
["<Author: Doe>", "<Author: doe>"], ordered=False)
|
[author1, author2],
|
||||||
self.assertQuerysetEqual(
|
)
|
||||||
|
self.assertSequenceEqual(
|
||||||
Author.objects.filter(name__upper__contains='f'),
|
Author.objects.filter(name__upper__contains='f'),
|
||||||
["<Author: Foo>"], ordered=False)
|
[author3],
|
||||||
|
)
|
||||||
|
|
||||||
def test_bilateral_inner_qs(self):
|
def test_bilateral_inner_qs(self):
|
||||||
with register_lookup(models.CharField, UpperBilateralTransform):
|
with register_lookup(models.CharField, UpperBilateralTransform):
|
||||||
|
|
|
@ -134,33 +134,42 @@ class DateTimesTests(TestCase):
|
||||||
for i, pub_date in enumerate(pub_dates):
|
for i, pub_date in enumerate(pub_dates):
|
||||||
Article(pub_date=pub_date, title='title #{}'.format(i)).save()
|
Article(pub_date=pub_date, title='title #{}'.format(i)).save()
|
||||||
|
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
Article.objects.datetimes('pub_date', 'year'),
|
Article.objects.datetimes('pub_date', 'year'),
|
||||||
["datetime.datetime(2005, 1, 1, 0, 0)"])
|
[datetime.datetime(2005, 1, 1, 0, 0)],
|
||||||
self.assertQuerysetEqual(
|
)
|
||||||
|
self.assertSequenceEqual(
|
||||||
Article.objects.datetimes('pub_date', 'month'),
|
Article.objects.datetimes('pub_date', 'month'),
|
||||||
["datetime.datetime(2005, 7, 1, 0, 0)"])
|
[datetime.datetime(2005, 7, 1, 0, 0)],
|
||||||
self.assertQuerysetEqual(
|
)
|
||||||
|
self.assertSequenceEqual(
|
||||||
Article.objects.datetimes('pub_date', 'week'),
|
Article.objects.datetimes('pub_date', 'week'),
|
||||||
["datetime.datetime(2005, 7, 25, 0, 0)"])
|
[datetime.datetime(2005, 7, 25, 0, 0)],
|
||||||
self.assertQuerysetEqual(
|
)
|
||||||
Article.objects.datetimes('pub_date', 'day'),
|
self.assertSequenceEqual(Article.objects.datetimes('pub_date', 'day'), [
|
||||||
["datetime.datetime(2005, 7, 28, 0, 0)",
|
datetime.datetime(2005, 7, 28, 0, 0),
|
||||||
"datetime.datetime(2005, 7, 29, 0, 0)",
|
datetime.datetime(2005, 7, 29, 0, 0),
|
||||||
"datetime.datetime(2005, 7, 30, 0, 0)",
|
datetime.datetime(2005, 7, 30, 0, 0),
|
||||||
"datetime.datetime(2005, 7, 31, 0, 0)"])
|
datetime.datetime(2005, 7, 31, 0, 0),
|
||||||
self.assertQuerysetEqual(
|
])
|
||||||
|
self.assertSequenceEqual(
|
||||||
Article.objects.datetimes('pub_date', 'day', order='ASC'),
|
Article.objects.datetimes('pub_date', 'day', order='ASC'),
|
||||||
["datetime.datetime(2005, 7, 28, 0, 0)",
|
[
|
||||||
"datetime.datetime(2005, 7, 29, 0, 0)",
|
datetime.datetime(2005, 7, 28, 0, 0),
|
||||||
"datetime.datetime(2005, 7, 30, 0, 0)",
|
datetime.datetime(2005, 7, 29, 0, 0),
|
||||||
"datetime.datetime(2005, 7, 31, 0, 0)"])
|
datetime.datetime(2005, 7, 30, 0, 0),
|
||||||
self.assertQuerysetEqual(
|
datetime.datetime(2005, 7, 31, 0, 0),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
self.assertSequenceEqual(
|
||||||
Article.objects.datetimes('pub_date', 'day', order='DESC'),
|
Article.objects.datetimes('pub_date', 'day', order='DESC'),
|
||||||
["datetime.datetime(2005, 7, 31, 0, 0)",
|
[
|
||||||
"datetime.datetime(2005, 7, 30, 0, 0)",
|
datetime.datetime(2005, 7, 31, 0, 0),
|
||||||
"datetime.datetime(2005, 7, 29, 0, 0)",
|
datetime.datetime(2005, 7, 30, 0, 0),
|
||||||
"datetime.datetime(2005, 7, 28, 0, 0)"])
|
datetime.datetime(2005, 7, 29, 0, 0),
|
||||||
|
datetime.datetime(2005, 7, 28, 0, 0),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
def test_datetimes_has_lazy_iterator(self):
|
def test_datetimes_has_lazy_iterator(self):
|
||||||
pub_dates = [
|
pub_dates = [
|
||||||
|
|
|
@ -23,15 +23,15 @@ class DistinctOnTests(TestCase):
|
||||||
cls.p3_o1 = Staff.objects.create(id=3, name="p3", organisation="o1")
|
cls.p3_o1 = Staff.objects.create(id=3, name="p3", organisation="o1")
|
||||||
cls.p1_o2 = Staff.objects.create(id=4, name="p1", organisation="o2")
|
cls.p1_o2 = Staff.objects.create(id=4, name="p1", organisation="o2")
|
||||||
cls.p1_o1.coworkers.add(cls.p2_o1, cls.p3_o1)
|
cls.p1_o1.coworkers.add(cls.p2_o1, cls.p3_o1)
|
||||||
StaffTag.objects.create(staff=cls.p1_o1, tag=cls.t1)
|
cls.st1 = StaffTag.objects.create(staff=cls.p1_o1, tag=cls.t1)
|
||||||
StaffTag.objects.create(staff=cls.p1_o1, tag=cls.t1)
|
StaffTag.objects.create(staff=cls.p1_o1, tag=cls.t1)
|
||||||
|
|
||||||
celeb1 = Celebrity.objects.create(name="c1")
|
cls.celeb1 = Celebrity.objects.create(name="c1")
|
||||||
celeb2 = Celebrity.objects.create(name="c2")
|
cls.celeb2 = Celebrity.objects.create(name="c2")
|
||||||
|
|
||||||
cls.fan1 = Fan.objects.create(fan_of=celeb1)
|
cls.fan1 = Fan.objects.create(fan_of=cls.celeb1)
|
||||||
cls.fan2 = Fan.objects.create(fan_of=celeb1)
|
cls.fan2 = Fan.objects.create(fan_of=cls.celeb1)
|
||||||
cls.fan3 = Fan.objects.create(fan_of=celeb2)
|
cls.fan3 = Fan.objects.create(fan_of=cls.celeb2)
|
||||||
|
|
||||||
def test_basic_distinct_on(self):
|
def test_basic_distinct_on(self):
|
||||||
"""QuerySet.distinct('field', ...) works"""
|
"""QuerySet.distinct('field', ...) works"""
|
||||||
|
@ -39,23 +39,23 @@ class DistinctOnTests(TestCase):
|
||||||
qsets = (
|
qsets = (
|
||||||
(
|
(
|
||||||
Staff.objects.distinct().order_by('name'),
|
Staff.objects.distinct().order_by('name'),
|
||||||
['<Staff: p1>', '<Staff: p1>', '<Staff: p2>', '<Staff: p3>'],
|
[self.p1_o1, self.p1_o2, self.p2_o1, self.p3_o1],
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
Staff.objects.distinct('name').order_by('name'),
|
Staff.objects.distinct('name').order_by('name'),
|
||||||
['<Staff: p1>', '<Staff: p2>', '<Staff: p3>'],
|
[self.p1_o1, self.p2_o1, self.p3_o1],
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
Staff.objects.distinct('organisation').order_by('organisation', 'name'),
|
Staff.objects.distinct('organisation').order_by('organisation', 'name'),
|
||||||
['<Staff: p1>', '<Staff: p1>'],
|
[self.p1_o1, self.p1_o2],
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
Staff.objects.distinct('name', 'organisation').order_by('name', 'organisation'),
|
Staff.objects.distinct('name', 'organisation').order_by('name', 'organisation'),
|
||||||
['<Staff: p1>', '<Staff: p1>', '<Staff: p2>', '<Staff: p3>'],
|
[self.p1_o1, self.p1_o2, self.p2_o1, self.p3_o1],
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
Celebrity.objects.filter(fan__in=[self.fan1, self.fan2, self.fan3]).distinct('name').order_by('name'),
|
Celebrity.objects.filter(fan__in=[self.fan1, self.fan2, self.fan3]).distinct('name').order_by('name'),
|
||||||
['<Celebrity: c1>', '<Celebrity: c2>'],
|
[self.celeb1, self.celeb2],
|
||||||
),
|
),
|
||||||
# Does combining querysets work?
|
# Does combining querysets work?
|
||||||
(
|
(
|
||||||
|
@ -63,31 +63,28 @@ class DistinctOnTests(TestCase):
|
||||||
distinct('name').order_by('name') |
|
distinct('name').order_by('name') |
|
||||||
Celebrity.objects.filter(fan__in=[self.fan3]).
|
Celebrity.objects.filter(fan__in=[self.fan3]).
|
||||||
distinct('name').order_by('name')),
|
distinct('name').order_by('name')),
|
||||||
['<Celebrity: c1>', '<Celebrity: c2>'],
|
[self.celeb1, self.celeb2],
|
||||||
),
|
|
||||||
(
|
|
||||||
StaffTag.objects.distinct('staff', 'tag'),
|
|
||||||
['<StaffTag: t1 -> p1>'],
|
|
||||||
),
|
),
|
||||||
|
(StaffTag.objects.distinct('staff', 'tag'), [self.st1]),
|
||||||
(
|
(
|
||||||
Tag.objects.order_by('parent__pk', 'pk').distinct('parent'),
|
Tag.objects.order_by('parent__pk', 'pk').distinct('parent'),
|
||||||
['<Tag: t2>', '<Tag: t4>', '<Tag: t1>']
|
[self.t2, self.t4, self.t1]
|
||||||
if connection.features.nulls_order_largest
|
if connection.features.nulls_order_largest
|
||||||
else ['<Tag: t1>', '<Tag: t2>', '<Tag: t4>'],
|
else [self.t1, self.t2, self.t4],
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
StaffTag.objects.select_related('staff').distinct('staff__name').order_by('staff__name'),
|
StaffTag.objects.select_related('staff').distinct('staff__name').order_by('staff__name'),
|
||||||
['<StaffTag: t1 -> p1>'],
|
[self.st1],
|
||||||
),
|
),
|
||||||
# Fetch the alphabetically first coworker for each worker
|
# Fetch the alphabetically first coworker for each worker
|
||||||
(
|
(
|
||||||
(Staff.objects.distinct('id').order_by('id', 'coworkers__name').
|
(Staff.objects.distinct('id').order_by('id', 'coworkers__name').
|
||||||
values_list('id', 'coworkers__name')),
|
values_list('id', 'coworkers__name')),
|
||||||
["(1, 'p2')", "(2, 'p1')", "(3, 'p1')", "(4, None)"]
|
[(1, 'p2'), (2, 'p1'), (3, 'p1'), (4, None)],
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
for qset, expected in qsets:
|
for qset, expected in qsets:
|
||||||
self.assertQuerysetEqual(qset, expected)
|
self.assertSequenceEqual(qset, expected)
|
||||||
self.assertEqual(qset.count(), len(expected))
|
self.assertEqual(qset.count(), len(expected))
|
||||||
|
|
||||||
# Combining queries with different distinct_fields is not allowed.
|
# Combining queries with different distinct_fields is not allowed.
|
||||||
|
|
|
@ -70,9 +70,9 @@ class BasicExpressionsTests(TestCase):
|
||||||
companies = Company.objects.annotate(
|
companies = Company.objects.annotate(
|
||||||
foo=RawSQL('%s', ['value']),
|
foo=RawSQL('%s', ['value']),
|
||||||
).filter(foo='value').order_by('name')
|
).filter(foo='value').order_by('name')
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
companies,
|
companies,
|
||||||
['<Company: Example Inc.>', '<Company: Foobar Ltd.>', '<Company: Test GmbH>'],
|
[self.example_inc, self.foobar_ltd, self.gmbh],
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_annotate_values_count(self):
|
def test_annotate_values_count(self):
|
||||||
|
@ -342,10 +342,10 @@ class BasicExpressionsTests(TestCase):
|
||||||
|
|
||||||
def test_ticket_11722_iexact_lookup(self):
|
def test_ticket_11722_iexact_lookup(self):
|
||||||
Employee.objects.create(firstname="John", lastname="Doe")
|
Employee.objects.create(firstname="John", lastname="Doe")
|
||||||
Employee.objects.create(firstname="Test", lastname="test")
|
test = Employee.objects.create(firstname="Test", lastname="test")
|
||||||
|
|
||||||
queryset = Employee.objects.filter(firstname__iexact=F('lastname'))
|
queryset = Employee.objects.filter(firstname__iexact=F('lastname'))
|
||||||
self.assertQuerysetEqual(queryset, ["<Employee: Test test>"])
|
self.assertSequenceEqual(queryset, [test])
|
||||||
|
|
||||||
def test_ticket_16731_startswith_lookup(self):
|
def test_ticket_16731_startswith_lookup(self):
|
||||||
Employee.objects.create(firstname="John", lastname="Doe")
|
Employee.objects.create(firstname="John", lastname="Doe")
|
||||||
|
@ -810,44 +810,38 @@ class IterableLookupInnerExpressionsTests(TestCase):
|
||||||
# MySQL requires that the values calculated for expressions don't pass
|
# MySQL requires that the values calculated for expressions don't pass
|
||||||
# outside of the field's range, so it's inconvenient to use the values
|
# outside of the field's range, so it's inconvenient to use the values
|
||||||
# in the more general tests.
|
# in the more general tests.
|
||||||
Company.objects.create(name='5020 Ltd', num_employees=50, num_chairs=20, ceo=ceo)
|
cls.c5020 = Company.objects.create(name='5020 Ltd', num_employees=50, num_chairs=20, ceo=ceo)
|
||||||
Company.objects.create(name='5040 Ltd', num_employees=50, num_chairs=40, ceo=ceo)
|
cls.c5040 = Company.objects.create(name='5040 Ltd', num_employees=50, num_chairs=40, ceo=ceo)
|
||||||
Company.objects.create(name='5050 Ltd', num_employees=50, num_chairs=50, ceo=ceo)
|
cls.c5050 = Company.objects.create(name='5050 Ltd', num_employees=50, num_chairs=50, ceo=ceo)
|
||||||
Company.objects.create(name='5060 Ltd', num_employees=50, num_chairs=60, ceo=ceo)
|
cls.c5060 = Company.objects.create(name='5060 Ltd', num_employees=50, num_chairs=60, ceo=ceo)
|
||||||
cls.c5 = Company.objects.create(name='99300 Ltd', num_employees=99, num_chairs=300, ceo=ceo)
|
cls.c99300 = Company.objects.create(name='99300 Ltd', num_employees=99, num_chairs=300, ceo=ceo)
|
||||||
|
|
||||||
def test_in_lookup_allows_F_expressions_and_expressions_for_integers(self):
|
def test_in_lookup_allows_F_expressions_and_expressions_for_integers(self):
|
||||||
# __in lookups can use F() expressions for integers.
|
# __in lookups can use F() expressions for integers.
|
||||||
queryset = Company.objects.filter(num_employees__in=([F('num_chairs') - 10]))
|
queryset = Company.objects.filter(num_employees__in=([F('num_chairs') - 10]))
|
||||||
self.assertQuerysetEqual(queryset, ['<Company: 5060 Ltd>'], ordered=False)
|
self.assertSequenceEqual(queryset, [self.c5060])
|
||||||
self.assertQuerysetEqual(
|
self.assertCountEqual(
|
||||||
Company.objects.filter(num_employees__in=([F('num_chairs') - 10, F('num_chairs') + 10])),
|
Company.objects.filter(num_employees__in=([F('num_chairs') - 10, F('num_chairs') + 10])),
|
||||||
['<Company: 5040 Ltd>', '<Company: 5060 Ltd>'],
|
[self.c5040, self.c5060],
|
||||||
ordered=False
|
|
||||||
)
|
)
|
||||||
self.assertQuerysetEqual(
|
self.assertCountEqual(
|
||||||
Company.objects.filter(
|
Company.objects.filter(
|
||||||
num_employees__in=([F('num_chairs') - 10, F('num_chairs'), F('num_chairs') + 10])
|
num_employees__in=([F('num_chairs') - 10, F('num_chairs'), F('num_chairs') + 10])
|
||||||
),
|
),
|
||||||
['<Company: 5040 Ltd>', '<Company: 5050 Ltd>', '<Company: 5060 Ltd>'],
|
[self.c5040, self.c5050, self.c5060],
|
||||||
ordered=False
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_expressions_in_lookups_join_choice(self):
|
def test_expressions_in_lookups_join_choice(self):
|
||||||
midpoint = datetime.time(13, 0)
|
midpoint = datetime.time(13, 0)
|
||||||
t1 = Time.objects.create(time=datetime.time(12, 0))
|
t1 = Time.objects.create(time=datetime.time(12, 0))
|
||||||
t2 = Time.objects.create(time=datetime.time(14, 0))
|
t2 = Time.objects.create(time=datetime.time(14, 0))
|
||||||
SimulationRun.objects.create(start=t1, end=t2, midpoint=midpoint)
|
s1 = SimulationRun.objects.create(start=t1, end=t2, midpoint=midpoint)
|
||||||
SimulationRun.objects.create(start=t1, end=None, midpoint=midpoint)
|
SimulationRun.objects.create(start=t1, end=None, midpoint=midpoint)
|
||||||
SimulationRun.objects.create(start=None, end=t2, midpoint=midpoint)
|
SimulationRun.objects.create(start=None, end=t2, midpoint=midpoint)
|
||||||
SimulationRun.objects.create(start=None, end=None, midpoint=midpoint)
|
SimulationRun.objects.create(start=None, end=None, midpoint=midpoint)
|
||||||
|
|
||||||
queryset = SimulationRun.objects.filter(midpoint__range=[F('start__time'), F('end__time')])
|
queryset = SimulationRun.objects.filter(midpoint__range=[F('start__time'), F('end__time')])
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(queryset, [s1])
|
||||||
queryset,
|
|
||||||
['<SimulationRun: 13:00:00 (12:00:00 to 14:00:00)>'],
|
|
||||||
ordered=False
|
|
||||||
)
|
|
||||||
for alias in queryset.query.alias_map.values():
|
for alias in queryset.query.alias_map.values():
|
||||||
if isinstance(alias, Join):
|
if isinstance(alias, Join):
|
||||||
self.assertEqual(alias.join_type, constants.INNER)
|
self.assertEqual(alias.join_type, constants.INNER)
|
||||||
|
@ -861,28 +855,21 @@ class IterableLookupInnerExpressionsTests(TestCase):
|
||||||
def test_range_lookup_allows_F_expressions_and_expressions_for_integers(self):
|
def test_range_lookup_allows_F_expressions_and_expressions_for_integers(self):
|
||||||
# Range lookups can use F() expressions for integers.
|
# Range lookups can use F() expressions for integers.
|
||||||
Company.objects.filter(num_employees__exact=F("num_chairs"))
|
Company.objects.filter(num_employees__exact=F("num_chairs"))
|
||||||
self.assertQuerysetEqual(
|
self.assertCountEqual(
|
||||||
Company.objects.filter(num_employees__range=(F('num_chairs'), 100)),
|
Company.objects.filter(num_employees__range=(F('num_chairs'), 100)),
|
||||||
['<Company: 5020 Ltd>', '<Company: 5040 Ltd>', '<Company: 5050 Ltd>'],
|
[self.c5020, self.c5040, self.c5050],
|
||||||
ordered=False
|
|
||||||
)
|
)
|
||||||
self.assertQuerysetEqual(
|
self.assertCountEqual(
|
||||||
Company.objects.filter(num_employees__range=(F('num_chairs') - 10, F('num_chairs') + 10)),
|
Company.objects.filter(num_employees__range=(F('num_chairs') - 10, F('num_chairs') + 10)),
|
||||||
['<Company: 5040 Ltd>', '<Company: 5050 Ltd>', '<Company: 5060 Ltd>'],
|
[self.c5040, self.c5050, self.c5060],
|
||||||
ordered=False
|
|
||||||
)
|
)
|
||||||
self.assertQuerysetEqual(
|
self.assertCountEqual(
|
||||||
Company.objects.filter(num_employees__range=(F('num_chairs') - 10, 100)),
|
Company.objects.filter(num_employees__range=(F('num_chairs') - 10, 100)),
|
||||||
['<Company: 5020 Ltd>', '<Company: 5040 Ltd>', '<Company: 5050 Ltd>', '<Company: 5060 Ltd>'],
|
[self.c5020, self.c5040, self.c5050, self.c5060],
|
||||||
ordered=False
|
|
||||||
)
|
)
|
||||||
self.assertQuerysetEqual(
|
self.assertCountEqual(
|
||||||
Company.objects.filter(num_employees__range=(1, 100)),
|
Company.objects.filter(num_employees__range=(1, 100)),
|
||||||
[
|
[self.c5020, self.c5040, self.c5050, self.c5060, self.c99300],
|
||||||
'<Company: 5020 Ltd>', '<Company: 5040 Ltd>', '<Company: 5050 Ltd>',
|
|
||||||
'<Company: 5060 Ltd>', '<Company: 99300 Ltd>',
|
|
||||||
],
|
|
||||||
ordered=False
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_range_lookup_namedtuple(self):
|
def test_range_lookup_namedtuple(self):
|
||||||
|
@ -890,7 +877,7 @@ class IterableLookupInnerExpressionsTests(TestCase):
|
||||||
qs = Company.objects.filter(
|
qs = Company.objects.filter(
|
||||||
num_employees__range=EmployeeRange(minimum=51, maximum=100),
|
num_employees__range=EmployeeRange(minimum=51, maximum=100),
|
||||||
)
|
)
|
||||||
self.assertSequenceEqual(qs, [self.c5])
|
self.assertSequenceEqual(qs, [self.c99300])
|
||||||
|
|
||||||
@unittest.skipUnless(connection.vendor == 'sqlite',
|
@unittest.skipUnless(connection.vendor == 'sqlite',
|
||||||
"This defensive test only works on databases that don't validate parameter types")
|
"This defensive test only works on databases that don't validate parameter types")
|
||||||
|
@ -926,7 +913,7 @@ class IterableLookupInnerExpressionsTests(TestCase):
|
||||||
completed=end.date(),
|
completed=end.date(),
|
||||||
estimated_time=end - start,
|
estimated_time=end - start,
|
||||||
)
|
)
|
||||||
Result.objects.create(
|
r1 = Result.objects.create(
|
||||||
experiment=experiment_1,
|
experiment=experiment_1,
|
||||||
result_time=datetime.datetime(2016, 2, 4, 15, 0, 0),
|
result_time=datetime.datetime(2016, 2, 4, 15, 0, 0),
|
||||||
)
|
)
|
||||||
|
@ -941,11 +928,11 @@ class IterableLookupInnerExpressionsTests(TestCase):
|
||||||
|
|
||||||
within_experiment_time = [F('experiment__start'), F('experiment__end')]
|
within_experiment_time = [F('experiment__start'), F('experiment__end')]
|
||||||
queryset = Result.objects.filter(result_time__range=within_experiment_time)
|
queryset = Result.objects.filter(result_time__range=within_experiment_time)
|
||||||
self.assertQuerysetEqual(queryset, ["<Result: Result at 2016-02-04 15:00:00>"])
|
self.assertSequenceEqual(queryset, [r1])
|
||||||
|
|
||||||
within_experiment_time = [F('experiment__start'), F('experiment__end')]
|
within_experiment_time = [F('experiment__start'), F('experiment__end')]
|
||||||
queryset = Result.objects.filter(result_time__range=within_experiment_time)
|
queryset = Result.objects.filter(result_time__range=within_experiment_time)
|
||||||
self.assertQuerysetEqual(queryset, ["<Result: Result at 2016-02-04 15:00:00>"])
|
self.assertSequenceEqual(queryset, [r1])
|
||||||
|
|
||||||
|
|
||||||
class FTests(SimpleTestCase):
|
class FTests(SimpleTestCase):
|
||||||
|
@ -1005,30 +992,27 @@ class ExpressionsTests(TestCase):
|
||||||
refs #16731
|
refs #16731
|
||||||
"""
|
"""
|
||||||
Employee.objects.bulk_create([
|
Employee.objects.bulk_create([
|
||||||
Employee(firstname="%Joh\\nny", lastname="%Joh\\n"),
|
|
||||||
Employee(firstname="Johnny", lastname="%John"),
|
Employee(firstname="Johnny", lastname="%John"),
|
||||||
Employee(firstname="Jean-Claude", lastname="Claud_"),
|
Employee(firstname="Jean-Claude", lastname="Claud_"),
|
||||||
Employee(firstname="Jean-Claude", lastname="Claude"),
|
|
||||||
Employee(firstname="Jean-Claude", lastname="Claude%"),
|
Employee(firstname="Jean-Claude", lastname="Claude%"),
|
||||||
Employee(firstname="Johnny", lastname="Joh\\n"),
|
Employee(firstname="Johnny", lastname="Joh\\n"),
|
||||||
Employee(firstname="Johnny", lastname="John"),
|
|
||||||
Employee(firstname="Johnny", lastname="_ohn"),
|
Employee(firstname="Johnny", lastname="_ohn"),
|
||||||
])
|
])
|
||||||
|
claude = Employee.objects.create(firstname='Jean-Claude', lastname='Claude')
|
||||||
|
john = Employee.objects.create(firstname='Johnny', lastname='John')
|
||||||
|
john_sign = Employee.objects.create(firstname='%Joh\\nny', lastname='%Joh\\n')
|
||||||
|
|
||||||
self.assertQuerysetEqual(
|
self.assertCountEqual(
|
||||||
Employee.objects.filter(firstname__contains=F('lastname')),
|
Employee.objects.filter(firstname__contains=F('lastname')),
|
||||||
["<Employee: %Joh\\nny %Joh\\n>", "<Employee: Jean-Claude Claude>", "<Employee: Johnny John>"],
|
[john_sign, john, claude],
|
||||||
ordered=False,
|
|
||||||
)
|
)
|
||||||
self.assertQuerysetEqual(
|
self.assertCountEqual(
|
||||||
Employee.objects.filter(firstname__startswith=F('lastname')),
|
Employee.objects.filter(firstname__startswith=F('lastname')),
|
||||||
["<Employee: %Joh\\nny %Joh\\n>", "<Employee: Johnny John>"],
|
[john_sign, john],
|
||||||
ordered=False,
|
|
||||||
)
|
)
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
Employee.objects.filter(firstname__endswith=F('lastname')),
|
Employee.objects.filter(firstname__endswith=F('lastname')),
|
||||||
["<Employee: Jean-Claude Claude>"],
|
[claude],
|
||||||
ordered=False,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_insensitive_patterns_escape(self):
|
def test_insensitive_patterns_escape(self):
|
||||||
|
@ -1038,30 +1022,27 @@ class ExpressionsTests(TestCase):
|
||||||
expression -- refs #16731
|
expression -- refs #16731
|
||||||
"""
|
"""
|
||||||
Employee.objects.bulk_create([
|
Employee.objects.bulk_create([
|
||||||
Employee(firstname="%Joh\\nny", lastname="%joh\\n"),
|
|
||||||
Employee(firstname="Johnny", lastname="%john"),
|
Employee(firstname="Johnny", lastname="%john"),
|
||||||
Employee(firstname="Jean-Claude", lastname="claud_"),
|
Employee(firstname="Jean-Claude", lastname="claud_"),
|
||||||
Employee(firstname="Jean-Claude", lastname="claude"),
|
|
||||||
Employee(firstname="Jean-Claude", lastname="claude%"),
|
Employee(firstname="Jean-Claude", lastname="claude%"),
|
||||||
Employee(firstname="Johnny", lastname="joh\\n"),
|
Employee(firstname="Johnny", lastname="joh\\n"),
|
||||||
Employee(firstname="Johnny", lastname="john"),
|
|
||||||
Employee(firstname="Johnny", lastname="_ohn"),
|
Employee(firstname="Johnny", lastname="_ohn"),
|
||||||
])
|
])
|
||||||
|
claude = Employee.objects.create(firstname='Jean-Claude', lastname='claude')
|
||||||
|
john = Employee.objects.create(firstname='Johnny', lastname='john')
|
||||||
|
john_sign = Employee.objects.create(firstname='%Joh\\nny', lastname='%joh\\n')
|
||||||
|
|
||||||
self.assertQuerysetEqual(
|
self.assertCountEqual(
|
||||||
Employee.objects.filter(firstname__icontains=F('lastname')),
|
Employee.objects.filter(firstname__icontains=F('lastname')),
|
||||||
["<Employee: %Joh\\nny %joh\\n>", "<Employee: Jean-Claude claude>", "<Employee: Johnny john>"],
|
[john_sign, john, claude],
|
||||||
ordered=False,
|
|
||||||
)
|
)
|
||||||
self.assertQuerysetEqual(
|
self.assertCountEqual(
|
||||||
Employee.objects.filter(firstname__istartswith=F('lastname')),
|
Employee.objects.filter(firstname__istartswith=F('lastname')),
|
||||||
["<Employee: %Joh\\nny %joh\\n>", "<Employee: Johnny john>"],
|
[john_sign, john],
|
||||||
ordered=False,
|
|
||||||
)
|
)
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
Employee.objects.filter(firstname__iendswith=F('lastname')),
|
Employee.objects.filter(firstname__iendswith=F('lastname')),
|
||||||
["<Employee: Jean-Claude claude>"],
|
[claude],
|
||||||
ordered=False,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -1126,7 +1107,8 @@ class ExpressionsNumericTests(TestCase):
|
||||||
"""
|
"""
|
||||||
self.assertQuerysetEqual(
|
self.assertQuerysetEqual(
|
||||||
Number.objects.all(),
|
Number.objects.all(),
|
||||||
['<Number: -1, -1.000>', '<Number: 42, 42.000>', '<Number: 1337, 1337.000>'],
|
[(-1, -1), (42, 42), (1337, 1337)],
|
||||||
|
lambda n: (n.integer, round(n.float)),
|
||||||
ordered=False
|
ordered=False
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1137,7 +1119,8 @@ class ExpressionsNumericTests(TestCase):
|
||||||
self.assertEqual(Number.objects.filter(integer__gt=0).update(integer=F('integer') + 1), 2)
|
self.assertEqual(Number.objects.filter(integer__gt=0).update(integer=F('integer') + 1), 2)
|
||||||
self.assertQuerysetEqual(
|
self.assertQuerysetEqual(
|
||||||
Number.objects.all(),
|
Number.objects.all(),
|
||||||
['<Number: -1, -1.000>', '<Number: 43, 42.000>', '<Number: 1338, 1337.000>'],
|
[(-1, -1), (43, 42), (1338, 1337)],
|
||||||
|
lambda n: (n.integer, round(n.float)),
|
||||||
ordered=False
|
ordered=False
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1149,7 +1132,8 @@ class ExpressionsNumericTests(TestCase):
|
||||||
self.assertEqual(Number.objects.filter(integer__gt=0).update(integer=F('integer') + 1), 2)
|
self.assertEqual(Number.objects.filter(integer__gt=0).update(integer=F('integer') + 1), 2)
|
||||||
self.assertQuerysetEqual(
|
self.assertQuerysetEqual(
|
||||||
Number.objects.exclude(float=F('integer')),
|
Number.objects.exclude(float=F('integer')),
|
||||||
['<Number: 43, 42.000>', '<Number: 1338, 1337.000>'],
|
[(43, 42), (1338, 1337)],
|
||||||
|
lambda n: (n.integer, round(n.float)),
|
||||||
ordered=False
|
ordered=False
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1790,15 +1774,15 @@ class FieldTransformTests(TestCase):
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_transform_in_values(self):
|
def test_transform_in_values(self):
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
Experiment.objects.values('assigned__month'),
|
Experiment.objects.values('assigned__month'),
|
||||||
["{'assigned__month': 6}"]
|
[{'assigned__month': 6}],
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_multiple_transforms_in_values(self):
|
def test_multiple_transforms_in_values(self):
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
Experiment.objects.values('end__date__month'),
|
Experiment.objects.values('end__date__month'),
|
||||||
["{'end__date__month': 6}"]
|
[{'end__date__month': 6}],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -118,8 +118,8 @@ class ExtraRegressTests(TestCase):
|
||||||
extra() bits.
|
extra() bits.
|
||||||
"""
|
"""
|
||||||
qs = User.objects.all().extra(where=['id=%s'], params=[self.u.id])
|
qs = User.objects.all().extra(where=['id=%s'], params=[self.u.id])
|
||||||
self.assertQuerysetEqual(qs, ['<User: fred>'])
|
self.assertSequenceEqual(qs, [self.u])
|
||||||
self.assertQuerysetEqual(qs[:1], ['<User: fred>'])
|
self.assertSequenceEqual(qs[:1], [self.u])
|
||||||
|
|
||||||
def test_regression_8039(self):
|
def test_regression_8039(self):
|
||||||
"""
|
"""
|
||||||
|
@ -140,17 +140,17 @@ class ExtraRegressTests(TestCase):
|
||||||
Regression test for #8819: Fields in the extra(select=...) list
|
Regression test for #8819: Fields in the extra(select=...) list
|
||||||
should be available to extra(order_by=...).
|
should be available to extra(order_by=...).
|
||||||
"""
|
"""
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
User.objects.filter(pk=self.u.id).extra(select={'extra_field': 1}).distinct(),
|
User.objects.filter(pk=self.u.id).extra(select={'extra_field': 1}).distinct(),
|
||||||
['<User: fred>']
|
[self.u],
|
||||||
)
|
)
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
User.objects.filter(pk=self.u.id).extra(select={'extra_field': 1}, order_by=['extra_field']),
|
User.objects.filter(pk=self.u.id).extra(select={'extra_field': 1}, order_by=['extra_field']),
|
||||||
['<User: fred>']
|
[self.u],
|
||||||
)
|
)
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
User.objects.filter(pk=self.u.id).extra(select={'extra_field': 1}, order_by=['extra_field']).distinct(),
|
User.objects.filter(pk=self.u.id).extra(select={'extra_field': 1}, order_by=['extra_field']).distinct(),
|
||||||
['<User: fred>']
|
[self.u],
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_dates_query(self):
|
def test_dates_query(self):
|
||||||
|
@ -364,11 +364,11 @@ class ExtraRegressTests(TestCase):
|
||||||
[{'pk': obj.pk}]
|
[{'pk': obj.pk}]
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
TestObject.objects.filter(
|
TestObject.objects.filter(
|
||||||
pk__in=TestObject.objects.extra(select={'extra': 1}).values('pk')
|
pk__in=TestObject.objects.extra(select={'extra': 1}).values('pk')
|
||||||
),
|
),
|
||||||
['<TestObject: TestObject: first,second,third>']
|
[obj],
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
|
@ -376,16 +376,16 @@ class ExtraRegressTests(TestCase):
|
||||||
[{'pk': obj.pk}]
|
[{'pk': obj.pk}]
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
TestObject.objects.filter(
|
TestObject.objects.filter(
|
||||||
pk__in=TestObject.objects.values('pk').extra(select={'extra': 1})
|
pk__in=TestObject.objects.values('pk').extra(select={'extra': 1})
|
||||||
),
|
),
|
||||||
['<TestObject: TestObject: first,second,third>']
|
[obj],
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
TestObject.objects.filter(pk=obj.pk) | TestObject.objects.extra(where=["id > %s"], params=[obj.pk]),
|
TestObject.objects.filter(pk=obj.pk) | TestObject.objects.extra(where=["id > %s"], params=[obj.pk]),
|
||||||
['<TestObject: TestObject: first,second,third>']
|
[obj],
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_regression_17877(self):
|
def test_regression_17877(self):
|
||||||
|
@ -394,11 +394,9 @@ class ExtraRegressTests(TestCase):
|
||||||
contain OR operations.
|
contain OR operations.
|
||||||
"""
|
"""
|
||||||
# Test Case 1: should appear in queryset.
|
# Test Case 1: should appear in queryset.
|
||||||
t = TestObject(first='a', second='a', third='a')
|
t1 = TestObject.objects.create(first='a', second='a', third='a')
|
||||||
t.save()
|
|
||||||
# Test Case 2: should appear in queryset.
|
# Test Case 2: should appear in queryset.
|
||||||
t = TestObject(first='b', second='a', third='a')
|
t2 = TestObject.objects.create(first='b', second='a', third='a')
|
||||||
t.save()
|
|
||||||
# Test Case 3: should not appear in queryset, bug case.
|
# Test Case 3: should not appear in queryset, bug case.
|
||||||
t = TestObject(first='a', second='a', third='b')
|
t = TestObject(first='a', second='a', third='b')
|
||||||
t.save()
|
t.save()
|
||||||
|
@ -412,12 +410,11 @@ class ExtraRegressTests(TestCase):
|
||||||
t = TestObject(first='a', second='b', third='b')
|
t = TestObject(first='a', second='b', third='b')
|
||||||
t.save()
|
t.save()
|
||||||
|
|
||||||
self.assertQuerysetEqual(
|
self.assertCountEqual(
|
||||||
TestObject.objects.extra(
|
TestObject.objects.extra(
|
||||||
where=["first = 'a' OR second = 'a'", "third = 'a'"],
|
where=["first = 'a' OR second = 'a'", "third = 'a'"],
|
||||||
),
|
),
|
||||||
['<TestObject: TestObject: a,a,a>', '<TestObject: TestObject: b,a,a>'],
|
[t1, t2],
|
||||||
ordered=False
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_extra_values_distinct_ordering(self):
|
def test_extra_values_distinct_ordering(self):
|
||||||
|
|
|
@ -39,11 +39,13 @@ class TestCaseFixtureLoadingTests(TestCase):
|
||||||
|
|
||||||
def test_class_fixtures(self):
|
def test_class_fixtures(self):
|
||||||
"Test case has installed 3 fixture objects"
|
"Test case has installed 3 fixture objects"
|
||||||
self.assertQuerysetEqual(Article.objects.all(), [
|
self.assertSequenceEqual(
|
||||||
'<Article: Django conquers world!>',
|
Article.objects.values_list('headline', flat=True), [
|
||||||
'<Article: Copyright is fine the way it is>',
|
'Django conquers world!',
|
||||||
'<Article: Poker has no place on ESPN>',
|
'Copyright is fine the way it is',
|
||||||
])
|
'Poker has no place on ESPN',
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class SubclassTestCaseFixtureLoadingTests(TestCaseFixtureLoadingTests):
|
class SubclassTestCaseFixtureLoadingTests(TestCaseFixtureLoadingTests):
|
||||||
|
@ -98,10 +100,10 @@ class FixtureLoadingTests(DumpDataAssertMixin, TestCase):
|
||||||
Site.objects.all().delete()
|
Site.objects.all().delete()
|
||||||
# Load fixture 1. Single JSON file, with two objects.
|
# Load fixture 1. Single JSON file, with two objects.
|
||||||
management.call_command('loaddata', 'fixture1.json', verbosity=0)
|
management.call_command('loaddata', 'fixture1.json', verbosity=0)
|
||||||
self.assertQuerysetEqual(Article.objects.all(), [
|
self.assertSequenceEqual(
|
||||||
'<Article: Time to reform copyright>',
|
Article.objects.values_list('headline', flat=True),
|
||||||
'<Article: Poker has no place on ESPN>',
|
['Time to reform copyright', 'Poker has no place on ESPN'],
|
||||||
])
|
)
|
||||||
|
|
||||||
# Dump the current contents of the database as a JSON fixture
|
# Dump the current contents of the database as a JSON fixture
|
||||||
self._dumpdata_assert(
|
self._dumpdata_assert(
|
||||||
|
@ -184,27 +186,33 @@ class FixtureLoadingTests(DumpDataAssertMixin, TestCase):
|
||||||
|
|
||||||
# Load fixture 2. JSON file imported by default. Overwrites some existing objects
|
# Load fixture 2. JSON file imported by default. Overwrites some existing objects
|
||||||
management.call_command('loaddata', 'fixture2.json', verbosity=0)
|
management.call_command('loaddata', 'fixture2.json', verbosity=0)
|
||||||
self.assertQuerysetEqual(Article.objects.all(), [
|
self.assertSequenceEqual(
|
||||||
'<Article: Django conquers world!>',
|
Article.objects.values_list('headline', flat=True),
|
||||||
'<Article: Copyright is fine the way it is>',
|
[
|
||||||
'<Article: Poker has no place on ESPN>',
|
'Django conquers world!',
|
||||||
])
|
'Copyright is fine the way it is',
|
||||||
|
'Poker has no place on ESPN',
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
# Load fixture 3, XML format.
|
# Load fixture 3, XML format.
|
||||||
management.call_command('loaddata', 'fixture3.xml', verbosity=0)
|
management.call_command('loaddata', 'fixture3.xml', verbosity=0)
|
||||||
self.assertQuerysetEqual(Article.objects.all(), [
|
self.assertSequenceEqual(
|
||||||
'<Article: XML identified as leading cause of cancer>',
|
Article.objects.values_list('headline', flat=True),
|
||||||
'<Article: Django conquers world!>',
|
[
|
||||||
'<Article: Copyright is fine the way it is>',
|
'XML identified as leading cause of cancer',
|
||||||
'<Article: Poker on TV is great!>',
|
'Django conquers world!',
|
||||||
])
|
'Copyright is fine the way it is',
|
||||||
|
'Poker on TV is great!',
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
# Load fixture 6, JSON file with dynamic ContentType fields. Testing ManyToOne.
|
# Load fixture 6, JSON file with dynamic ContentType fields. Testing ManyToOne.
|
||||||
management.call_command('loaddata', 'fixture6.json', verbosity=0)
|
management.call_command('loaddata', 'fixture6.json', verbosity=0)
|
||||||
self.assertQuerysetEqual(Tag.objects.all(), [
|
self.assertQuerysetEqual(Tag.objects.all(), [
|
||||||
'<Tag: <Article: Copyright is fine the way it is> tagged "copyright">',
|
'<Tag: <Article: Copyright is fine the way it is> tagged "copyright">',
|
||||||
'<Tag: <Article: Copyright is fine the way it is> tagged "law">',
|
'<Tag: <Article: Copyright is fine the way it is> tagged "law">',
|
||||||
], ordered=False)
|
], transform=repr, ordered=False)
|
||||||
|
|
||||||
# Load fixture 7, XML file with dynamic ContentType fields. Testing ManyToOne.
|
# Load fixture 7, XML file with dynamic ContentType fields. Testing ManyToOne.
|
||||||
management.call_command('loaddata', 'fixture7.xml', verbosity=0)
|
management.call_command('loaddata', 'fixture7.xml', verbosity=0)
|
||||||
|
@ -213,7 +221,7 @@ class FixtureLoadingTests(DumpDataAssertMixin, TestCase):
|
||||||
'<Tag: <Article: Copyright is fine the way it is> tagged "legal">',
|
'<Tag: <Article: Copyright is fine the way it is> tagged "legal">',
|
||||||
'<Tag: <Article: Django conquers world!> tagged "django">',
|
'<Tag: <Article: Django conquers world!> tagged "django">',
|
||||||
'<Tag: <Article: Django conquers world!> tagged "world domination">',
|
'<Tag: <Article: Django conquers world!> tagged "world domination">',
|
||||||
], ordered=False)
|
], transform=repr, ordered=False)
|
||||||
|
|
||||||
# Load fixture 8, JSON file with dynamic Permission fields. Testing ManyToMany.
|
# Load fixture 8, JSON file with dynamic Permission fields. Testing ManyToMany.
|
||||||
management.call_command('loaddata', 'fixture8.json', verbosity=0)
|
management.call_command('loaddata', 'fixture8.json', verbosity=0)
|
||||||
|
@ -221,7 +229,7 @@ class FixtureLoadingTests(DumpDataAssertMixin, TestCase):
|
||||||
'<Visa: Django Reinhardt Can add user, Can change user, Can delete user>',
|
'<Visa: Django Reinhardt Can add user, Can change user, Can delete user>',
|
||||||
'<Visa: Stephane Grappelli Can add user>',
|
'<Visa: Stephane Grappelli Can add user>',
|
||||||
'<Visa: Prince >'
|
'<Visa: Prince >'
|
||||||
], ordered=False)
|
], transform=repr, ordered=False)
|
||||||
|
|
||||||
# Load fixture 9, XML file with dynamic Permission fields. Testing ManyToMany.
|
# Load fixture 9, XML file with dynamic Permission fields. Testing ManyToMany.
|
||||||
management.call_command('loaddata', 'fixture9.xml', verbosity=0)
|
management.call_command('loaddata', 'fixture9.xml', verbosity=0)
|
||||||
|
@ -229,15 +237,18 @@ class FixtureLoadingTests(DumpDataAssertMixin, TestCase):
|
||||||
'<Visa: Django Reinhardt Can add user, Can change user, Can delete user>',
|
'<Visa: Django Reinhardt Can add user, Can change user, Can delete user>',
|
||||||
'<Visa: Stephane Grappelli Can add user, Can delete user>',
|
'<Visa: Stephane Grappelli Can add user, Can delete user>',
|
||||||
'<Visa: Artist formerly known as "Prince" Can change user>'
|
'<Visa: Artist formerly known as "Prince" Can change user>'
|
||||||
], ordered=False)
|
], transform=repr, ordered=False)
|
||||||
|
|
||||||
# object list is unaffected
|
# object list is unaffected
|
||||||
self.assertQuerysetEqual(Article.objects.all(), [
|
self.assertSequenceEqual(
|
||||||
'<Article: XML identified as leading cause of cancer>',
|
Article.objects.values_list('headline', flat=True),
|
||||||
'<Article: Django conquers world!>',
|
[
|
||||||
'<Article: Copyright is fine the way it is>',
|
'XML identified as leading cause of cancer',
|
||||||
'<Article: Poker on TV is great!>',
|
'Django conquers world!',
|
||||||
])
|
'Copyright is fine the way it is',
|
||||||
|
'Poker on TV is great!',
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
# By default, you get raw keys on dumpdata
|
# By default, you get raw keys on dumpdata
|
||||||
self._dumpdata_assert(
|
self._dumpdata_assert(
|
||||||
|
@ -390,13 +401,15 @@ class FixtureLoadingTests(DumpDataAssertMixin, TestCase):
|
||||||
@unittest.skipIf(sys.platform == 'win32', "Windows doesn't support '?' in filenames.")
|
@unittest.skipIf(sys.platform == 'win32', "Windows doesn't support '?' in filenames.")
|
||||||
def test_load_fixture_with_special_characters(self):
|
def test_load_fixture_with_special_characters(self):
|
||||||
management.call_command('loaddata', 'fixture_with[special]chars', verbosity=0)
|
management.call_command('loaddata', 'fixture_with[special]chars', verbosity=0)
|
||||||
self.assertQuerysetEqual(Article.objects.all(), ['<Article: How To Deal With Special Characters>'])
|
self.assertEqual(
|
||||||
|
Article.objects.get().headline,
|
||||||
|
'How To Deal With Special Characters',
|
||||||
|
)
|
||||||
|
|
||||||
def test_dumpdata_with_filtering_manager(self):
|
def test_dumpdata_with_filtering_manager(self):
|
||||||
spy1 = Spy.objects.create(name='Paul')
|
spy1 = Spy.objects.create(name='Paul')
|
||||||
spy2 = Spy.objects.create(name='Alex', cover_blown=True)
|
spy2 = Spy.objects.create(name='Alex', cover_blown=True)
|
||||||
self.assertQuerysetEqual(Spy.objects.all(),
|
self.assertSequenceEqual(Spy.objects.all(), [spy1])
|
||||||
['<Spy: Paul>'])
|
|
||||||
# Use the default manager
|
# Use the default manager
|
||||||
self._dumpdata_assert(
|
self._dumpdata_assert(
|
||||||
['fixtures.Spy'],
|
['fixtures.Spy'],
|
||||||
|
@ -533,50 +546,54 @@ class FixtureLoadingTests(DumpDataAssertMixin, TestCase):
|
||||||
def test_compress_format_loading(self):
|
def test_compress_format_loading(self):
|
||||||
# Load fixture 4 (compressed), using format specification
|
# Load fixture 4 (compressed), using format specification
|
||||||
management.call_command('loaddata', 'fixture4.json', verbosity=0)
|
management.call_command('loaddata', 'fixture4.json', verbosity=0)
|
||||||
self.assertQuerysetEqual(Article.objects.all(), [
|
self.assertEqual(Article.objects.get().headline, 'Django pets kitten')
|
||||||
'<Article: Django pets kitten>',
|
|
||||||
])
|
|
||||||
|
|
||||||
def test_compressed_specified_loading(self):
|
def test_compressed_specified_loading(self):
|
||||||
# Load fixture 5 (compressed), using format *and* compression specification
|
# Load fixture 5 (compressed), using format *and* compression specification
|
||||||
management.call_command('loaddata', 'fixture5.json.zip', verbosity=0)
|
management.call_command('loaddata', 'fixture5.json.zip', verbosity=0)
|
||||||
self.assertQuerysetEqual(Article.objects.all(), [
|
self.assertEqual(
|
||||||
'<Article: WoW subscribers now outnumber readers>',
|
Article.objects.get().headline,
|
||||||
])
|
'WoW subscribers now outnumber readers',
|
||||||
|
)
|
||||||
|
|
||||||
def test_compressed_loading(self):
|
def test_compressed_loading(self):
|
||||||
# Load fixture 5 (compressed), only compression specification
|
# Load fixture 5 (compressed), only compression specification
|
||||||
management.call_command('loaddata', 'fixture5.zip', verbosity=0)
|
management.call_command('loaddata', 'fixture5.zip', verbosity=0)
|
||||||
self.assertQuerysetEqual(Article.objects.all(), [
|
self.assertEqual(
|
||||||
'<Article: WoW subscribers now outnumber readers>',
|
Article.objects.get().headline,
|
||||||
])
|
'WoW subscribers now outnumber readers',
|
||||||
|
)
|
||||||
|
|
||||||
def test_compressed_loading_gzip(self):
|
def test_compressed_loading_gzip(self):
|
||||||
management.call_command('loaddata', 'fixture5.json.gz', verbosity=0)
|
management.call_command('loaddata', 'fixture5.json.gz', verbosity=0)
|
||||||
self.assertQuerysetEqual(Article.objects.all(), [
|
self.assertEqual(
|
||||||
'<Article: WoW subscribers now outnumber readers>',
|
Article.objects.get().headline,
|
||||||
])
|
'WoW subscribers now outnumber readers',
|
||||||
|
)
|
||||||
|
|
||||||
@unittest.skipUnless(HAS_BZ2, 'No bz2 library detected.')
|
@unittest.skipUnless(HAS_BZ2, 'No bz2 library detected.')
|
||||||
def test_compressed_loading_bz2(self):
|
def test_compressed_loading_bz2(self):
|
||||||
management.call_command('loaddata', 'fixture5.json.bz2', verbosity=0)
|
management.call_command('loaddata', 'fixture5.json.bz2', verbosity=0)
|
||||||
self.assertQuerysetEqual(Article.objects.all(), [
|
self.assertEqual(
|
||||||
'<Article: WoW subscribers now outnumber readers>',
|
Article.objects.get().headline,
|
||||||
])
|
'WoW subscribers now outnumber readers',
|
||||||
|
)
|
||||||
|
|
||||||
@unittest.skipUnless(HAS_LZMA, 'No lzma library detected.')
|
@unittest.skipUnless(HAS_LZMA, 'No lzma library detected.')
|
||||||
def test_compressed_loading_lzma(self):
|
def test_compressed_loading_lzma(self):
|
||||||
management.call_command('loaddata', 'fixture5.json.lzma', verbosity=0)
|
management.call_command('loaddata', 'fixture5.json.lzma', verbosity=0)
|
||||||
self.assertQuerysetEqual(Article.objects.all(), [
|
self.assertEqual(
|
||||||
'<Article: WoW subscribers now outnumber readers>',
|
Article.objects.get().headline,
|
||||||
])
|
'WoW subscribers now outnumber readers',
|
||||||
|
)
|
||||||
|
|
||||||
@unittest.skipUnless(HAS_LZMA, 'No lzma library detected.')
|
@unittest.skipUnless(HAS_LZMA, 'No lzma library detected.')
|
||||||
def test_compressed_loading_xz(self):
|
def test_compressed_loading_xz(self):
|
||||||
management.call_command('loaddata', 'fixture5.json.xz', verbosity=0)
|
management.call_command('loaddata', 'fixture5.json.xz', verbosity=0)
|
||||||
self.assertQuerysetEqual(Article.objects.all(), [
|
self.assertEqual(
|
||||||
'<Article: WoW subscribers now outnumber readers>',
|
Article.objects.get().headline,
|
||||||
])
|
'WoW subscribers now outnumber readers',
|
||||||
|
)
|
||||||
|
|
||||||
def test_ambiguous_compressed_fixture(self):
|
def test_ambiguous_compressed_fixture(self):
|
||||||
# The name "fixture5" is ambiguous, so loading raises an error.
|
# The name "fixture5" is ambiguous, so loading raises an error.
|
||||||
|
@ -588,10 +605,13 @@ class FixtureLoadingTests(DumpDataAssertMixin, TestCase):
|
||||||
# Load db fixtures 1 and 2. These will load using the 'default' database identifier implicitly
|
# Load db fixtures 1 and 2. These will load using the 'default' database identifier implicitly
|
||||||
management.call_command('loaddata', 'db_fixture_1', verbosity=0)
|
management.call_command('loaddata', 'db_fixture_1', verbosity=0)
|
||||||
management.call_command('loaddata', 'db_fixture_2', verbosity=0)
|
management.call_command('loaddata', 'db_fixture_2', verbosity=0)
|
||||||
self.assertQuerysetEqual(Article.objects.all(), [
|
self.assertSequenceEqual(
|
||||||
'<Article: Who needs more than one database?>',
|
Article.objects.values_list('headline', flat=True),
|
||||||
'<Article: Who needs to use compressed data?>',
|
[
|
||||||
])
|
'Who needs more than one database?',
|
||||||
|
'Who needs to use compressed data?',
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
def test_loaddata_error_message(self):
|
def test_loaddata_error_message(self):
|
||||||
"""
|
"""
|
||||||
|
@ -622,9 +642,10 @@ class FixtureLoadingTests(DumpDataAssertMixin, TestCase):
|
||||||
management.call_command('loaddata', 'db_fixture_1', verbosity=0, app_label="someotherapp")
|
management.call_command('loaddata', 'db_fixture_1', verbosity=0, app_label="someotherapp")
|
||||||
self.assertQuerysetEqual(Article.objects.all(), [])
|
self.assertQuerysetEqual(Article.objects.all(), [])
|
||||||
management.call_command('loaddata', 'db_fixture_1', verbosity=0, app_label="fixtures")
|
management.call_command('loaddata', 'db_fixture_1', verbosity=0, app_label="fixtures")
|
||||||
self.assertQuerysetEqual(Article.objects.all(), [
|
self.assertEqual(
|
||||||
'<Article: Who needs more than one database?>',
|
Article.objects.get().headline,
|
||||||
])
|
'Who needs more than one database?',
|
||||||
|
)
|
||||||
|
|
||||||
def test_loaddata_verbosity_three(self):
|
def test_loaddata_verbosity_three(self):
|
||||||
output = StringIO()
|
output = StringIO()
|
||||||
|
@ -640,10 +661,13 @@ class FixtureLoadingTests(DumpDataAssertMixin, TestCase):
|
||||||
# Load db fixtures 1 and 2. These will load using the 'default' database identifier explicitly
|
# Load db fixtures 1 and 2. These will load using the 'default' database identifier explicitly
|
||||||
management.call_command('loaddata', 'db_fixture_1', verbosity=0, database='default')
|
management.call_command('loaddata', 'db_fixture_1', verbosity=0, database='default')
|
||||||
management.call_command('loaddata', 'db_fixture_2', verbosity=0, database='default')
|
management.call_command('loaddata', 'db_fixture_2', verbosity=0, database='default')
|
||||||
self.assertQuerysetEqual(Article.objects.all(), [
|
self.assertSequenceEqual(
|
||||||
'<Article: Who needs more than one database?>',
|
Article.objects.values_list('headline', flat=True),
|
||||||
'<Article: Who needs to use compressed data?>',
|
[
|
||||||
])
|
'Who needs more than one database?',
|
||||||
|
'Who needs to use compressed data?',
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
def test_unmatched_identifier_loading(self):
|
def test_unmatched_identifier_loading(self):
|
||||||
# Try to load db fixture 3. This won't load because the database identifier doesn't match
|
# Try to load db fixture 3. This won't load because the database identifier doesn't match
|
||||||
|
@ -662,7 +686,7 @@ class FixtureLoadingTests(DumpDataAssertMixin, TestCase):
|
||||||
self.assertQuerysetEqual(Tag.objects.all(), [
|
self.assertQuerysetEqual(Tag.objects.all(), [
|
||||||
'<Tag: <Article: Time to reform copyright> tagged "copyright">',
|
'<Tag: <Article: Time to reform copyright> tagged "copyright">',
|
||||||
'<Tag: <Article: Time to reform copyright> tagged "law">'
|
'<Tag: <Article: Time to reform copyright> tagged "law">'
|
||||||
], ordered=False)
|
], transform=repr, ordered=False)
|
||||||
|
|
||||||
# Dump the current contents of the database as a JSON fixture
|
# Dump the current contents of the database as a JSON fixture
|
||||||
self._dumpdata_assert(
|
self._dumpdata_assert(
|
||||||
|
@ -707,14 +731,14 @@ class FixtureLoadingTests(DumpDataAssertMixin, TestCase):
|
||||||
management.call_command('loaddata', 'fixture1', exclude=['fixtures'], verbosity=0)
|
management.call_command('loaddata', 'fixture1', exclude=['fixtures'], verbosity=0)
|
||||||
self.assertFalse(Article.objects.exists())
|
self.assertFalse(Article.objects.exists())
|
||||||
self.assertFalse(Category.objects.exists())
|
self.assertFalse(Category.objects.exists())
|
||||||
self.assertQuerysetEqual(Site.objects.all(), ['<Site: example.com>'])
|
self.assertEqual(Site.objects.get().domain, 'example.com')
|
||||||
|
|
||||||
def test_loading_with_exclude_model(self):
|
def test_loading_with_exclude_model(self):
|
||||||
Site.objects.all().delete()
|
Site.objects.all().delete()
|
||||||
management.call_command('loaddata', 'fixture1', exclude=['fixtures.Article'], verbosity=0)
|
management.call_command('loaddata', 'fixture1', exclude=['fixtures.Article'], verbosity=0)
|
||||||
self.assertFalse(Article.objects.exists())
|
self.assertFalse(Article.objects.exists())
|
||||||
self.assertQuerysetEqual(Category.objects.all(), ['<Category: News Stories>'])
|
self.assertEqual(Category.objects.get().title, 'News Stories')
|
||||||
self.assertQuerysetEqual(Site.objects.all(), ['<Site: example.com>'])
|
self.assertEqual(Site.objects.get().domain, 'example.com')
|
||||||
|
|
||||||
def test_exclude_option_errors(self):
|
def test_exclude_option_errors(self):
|
||||||
"""Excluding a bogus app or model should raise an error."""
|
"""Excluding a bogus app or model should raise an error."""
|
||||||
|
@ -740,18 +764,21 @@ class FixtureLoadingTests(DumpDataAssertMixin, TestCase):
|
||||||
|
|
||||||
with mock.patch('django.core.management.commands.loaddata.sys.stdin', open(fixture_json)):
|
with mock.patch('django.core.management.commands.loaddata.sys.stdin', open(fixture_json)):
|
||||||
management.call_command('loaddata', '--format=json', '-', verbosity=0)
|
management.call_command('loaddata', '--format=json', '-', verbosity=0)
|
||||||
self.assertQuerysetEqual(Article.objects.all(), [
|
self.assertSequenceEqual(
|
||||||
'<Article: Time to reform copyright>',
|
Article.objects.values_list('headline', flat=True),
|
||||||
'<Article: Poker has no place on ESPN>',
|
['Time to reform copyright', 'Poker has no place on ESPN'],
|
||||||
])
|
)
|
||||||
|
|
||||||
with mock.patch('django.core.management.commands.loaddata.sys.stdin', open(fixture_xml)):
|
with mock.patch('django.core.management.commands.loaddata.sys.stdin', open(fixture_xml)):
|
||||||
management.call_command('loaddata', '--format=xml', '-', verbosity=0)
|
management.call_command('loaddata', '--format=xml', '-', verbosity=0)
|
||||||
self.assertQuerysetEqual(Article.objects.all(), [
|
self.assertSequenceEqual(
|
||||||
'<Article: XML identified as leading cause of cancer>',
|
Article.objects.values_list('headline', flat=True),
|
||||||
'<Article: Time to reform copyright>',
|
[
|
||||||
'<Article: Poker on TV is great!>',
|
'XML identified as leading cause of cancer',
|
||||||
])
|
'Time to reform copyright',
|
||||||
|
'Poker on TV is great!',
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class NonexistentFixtureTests(TestCase):
|
class NonexistentFixtureTests(TestCase):
|
||||||
|
@ -789,10 +816,10 @@ class FixtureTransactionTests(DumpDataAssertMixin, TransactionTestCase):
|
||||||
def test_format_discovery(self):
|
def test_format_discovery(self):
|
||||||
# Load fixture 1 again, using format discovery
|
# Load fixture 1 again, using format discovery
|
||||||
management.call_command('loaddata', 'fixture1', verbosity=0)
|
management.call_command('loaddata', 'fixture1', verbosity=0)
|
||||||
self.assertQuerysetEqual(Article.objects.all(), [
|
self.assertSequenceEqual(
|
||||||
'<Article: Time to reform copyright>',
|
Article.objects.values_list('headline', flat=True),
|
||||||
'<Article: Poker has no place on ESPN>',
|
['Time to reform copyright', 'Poker has no place on ESPN'],
|
||||||
])
|
)
|
||||||
|
|
||||||
# Try to load fixture 2 using format discovery; this will fail
|
# Try to load fixture 2 using format discovery; this will fail
|
||||||
# because there are two fixture2's in the fixtures directory
|
# because there are two fixture2's in the fixtures directory
|
||||||
|
@ -801,10 +828,10 @@ class FixtureTransactionTests(DumpDataAssertMixin, TransactionTestCase):
|
||||||
management.call_command('loaddata', 'fixture2', verbosity=0)
|
management.call_command('loaddata', 'fixture2', verbosity=0)
|
||||||
|
|
||||||
# object list is unaffected
|
# object list is unaffected
|
||||||
self.assertQuerysetEqual(Article.objects.all(), [
|
self.assertSequenceEqual(
|
||||||
'<Article: Time to reform copyright>',
|
Article.objects.values_list('headline', flat=True),
|
||||||
'<Article: Poker has no place on ESPN>',
|
['Time to reform copyright', 'Poker has no place on ESPN'],
|
||||||
])
|
)
|
||||||
|
|
||||||
# Dump the current contents of the database as a JSON fixture
|
# Dump the current contents of the database as a JSON fixture
|
||||||
self._dumpdata_assert(
|
self._dumpdata_assert(
|
||||||
|
@ -817,11 +844,14 @@ class FixtureTransactionTests(DumpDataAssertMixin, TransactionTestCase):
|
||||||
|
|
||||||
# Load fixture 4 (compressed), using format discovery
|
# Load fixture 4 (compressed), using format discovery
|
||||||
management.call_command('loaddata', 'fixture4', verbosity=0)
|
management.call_command('loaddata', 'fixture4', verbosity=0)
|
||||||
self.assertQuerysetEqual(Article.objects.all(), [
|
self.assertSequenceEqual(
|
||||||
'<Article: Django pets kitten>',
|
Article.objects.values_list('headline', flat=True),
|
||||||
'<Article: Time to reform copyright>',
|
[
|
||||||
'<Article: Poker has no place on ESPN>',
|
'Django pets kitten',
|
||||||
])
|
'Time to reform copyright',
|
||||||
|
'Poker has no place on ESPN',
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class ForwardReferenceTests(DumpDataAssertMixin, TestCase):
|
class ForwardReferenceTests(DumpDataAssertMixin, TestCase):
|
||||||
|
@ -861,9 +891,9 @@ class ForwardReferenceTests(DumpDataAssertMixin, TestCase):
|
||||||
management.call_command('loaddata', 'forward_reference_m2m.json', verbosity=0)
|
management.call_command('loaddata', 'forward_reference_m2m.json', verbosity=0)
|
||||||
self.assertEqual(NaturalKeyThing.objects.count(), 3)
|
self.assertEqual(NaturalKeyThing.objects.count(), 3)
|
||||||
t1 = NaturalKeyThing.objects.get_by_natural_key('t1')
|
t1 = NaturalKeyThing.objects.get_by_natural_key('t1')
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
t1.other_things.order_by('key'),
|
t1.other_things.order_by('key').values_list('key', flat=True),
|
||||||
['<NaturalKeyThing: t2>', '<NaturalKeyThing: t3>']
|
['t2', 't3'],
|
||||||
)
|
)
|
||||||
self._dumpdata_assert(
|
self._dumpdata_assert(
|
||||||
['fixtures'],
|
['fixtures'],
|
||||||
|
@ -883,9 +913,9 @@ class ForwardReferenceTests(DumpDataAssertMixin, TestCase):
|
||||||
)
|
)
|
||||||
self.assertEqual(NaturalKeyThing.objects.count(), 3)
|
self.assertEqual(NaturalKeyThing.objects.count(), 3)
|
||||||
t1 = NaturalKeyThing.objects.get_by_natural_key('t1')
|
t1 = NaturalKeyThing.objects.get_by_natural_key('t1')
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
t1.other_things.order_by('key'),
|
t1.other_things.order_by('key').values_list('key', flat=True),
|
||||||
['<NaturalKeyThing: t2>', '<NaturalKeyThing: t3>']
|
['t2', 't3'],
|
||||||
)
|
)
|
||||||
self._dumpdata_assert(
|
self._dumpdata_assert(
|
||||||
['fixtures'],
|
['fixtures'],
|
||||||
|
|
|
@ -747,7 +747,8 @@ class NaturalKeyFixtureTests(TestCase):
|
||||||
"<Book: Cryptonomicon by Neal Stephenson (available at Amazon, Borders)>",
|
"<Book: Cryptonomicon by Neal Stephenson (available at Amazon, Borders)>",
|
||||||
"<Book: Ender's Game by Orson Scott Card (available at Collins Bookstore)>",
|
"<Book: Ender's Game by Orson Scott Card (available at Collins Bookstore)>",
|
||||||
"<Book: Permutation City by Greg Egan (available at Angus and Robertson)>",
|
"<Book: Permutation City by Greg Egan (available at Angus and Robertson)>",
|
||||||
]
|
],
|
||||||
|
transform=repr,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -845,10 +846,7 @@ class M2MNaturalKeyFixtureTests(TestCase):
|
||||||
obj.save()
|
obj.save()
|
||||||
|
|
||||||
new_a = M2MSimpleA.objects.get_by_natural_key("a")
|
new_a = M2MSimpleA.objects.get_by_natural_key("a")
|
||||||
self.assertQuerysetEqual(new_a.b_set.all(), [
|
self.assertCountEqual(new_a.b_set.all(), [b1, b2])
|
||||||
"<M2MSimpleB: b1>",
|
|
||||||
"<M2MSimpleB: b2>"
|
|
||||||
], ordered=False)
|
|
||||||
|
|
||||||
|
|
||||||
class TestTicket11101(TransactionTestCase):
|
class TestTicket11101(TransactionTestCase):
|
||||||
|
|
|
@ -408,15 +408,15 @@ class MultiColumnFKTests(TestCase):
|
||||||
Person.objects.bulk_create(objs, 10)
|
Person.objects.bulk_create(objs, 10)
|
||||||
|
|
||||||
def test_isnull_lookup(self):
|
def test_isnull_lookup(self):
|
||||||
Membership.objects.create(membership_country=self.usa, person=self.bob, group_id=None)
|
m1 = Membership.objects.create(membership_country=self.usa, person=self.bob, group_id=None)
|
||||||
Membership.objects.create(membership_country=self.usa, person=self.bob, group=self.cia)
|
m2 = Membership.objects.create(membership_country=self.usa, person=self.bob, group=self.cia)
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
Membership.objects.filter(group__isnull=True),
|
Membership.objects.filter(group__isnull=True),
|
||||||
['<Membership: Bob is a member of NULL>']
|
[m1],
|
||||||
)
|
)
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
Membership.objects.filter(group__isnull=False),
|
Membership.objects.filter(group__isnull=False),
|
||||||
['<Membership: Bob is a member of CIA>']
|
[m2],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -25,10 +25,10 @@ class GenericRelationsTests(TestCase):
|
||||||
cls.quartz = Mineral.objects.create(name='Quartz', hardness=7)
|
cls.quartz = Mineral.objects.create(name='Quartz', hardness=7)
|
||||||
|
|
||||||
# Tagging stuff.
|
# Tagging stuff.
|
||||||
cls.bacon.tags.create(tag='fatty')
|
cls.fatty = cls.bacon.tags.create(tag='fatty')
|
||||||
cls.bacon.tags.create(tag='salty')
|
cls.salty = cls.bacon.tags.create(tag='salty')
|
||||||
cls.lion.tags.create(tag='yellow')
|
cls.yellow = cls.lion.tags.create(tag='yellow')
|
||||||
cls.lion.tags.create(tag='hairy')
|
cls.hairy = cls.lion.tags.create(tag='hairy')
|
||||||
|
|
||||||
def comp_func(self, obj):
|
def comp_func(self, obj):
|
||||||
# Original list of tags:
|
# Original list of tags:
|
||||||
|
@ -86,14 +86,8 @@ class GenericRelationsTests(TestCase):
|
||||||
Objects with declared GenericRelations can be tagged directly -- the
|
Objects with declared GenericRelations can be tagged directly -- the
|
||||||
API mimics the many-to-many API.
|
API mimics the many-to-many API.
|
||||||
"""
|
"""
|
||||||
self.assertQuerysetEqual(self.lion.tags.all(), [
|
self.assertSequenceEqual(self.lion.tags.all(), [self.hairy, self.yellow])
|
||||||
"<TaggedItem: hairy>",
|
self.assertSequenceEqual(self.bacon.tags.all(), [self.fatty, self.salty])
|
||||||
"<TaggedItem: yellow>"
|
|
||||||
])
|
|
||||||
self.assertQuerysetEqual(self.bacon.tags.all(), [
|
|
||||||
"<TaggedItem: fatty>",
|
|
||||||
"<TaggedItem: salty>"
|
|
||||||
])
|
|
||||||
|
|
||||||
def test_access_content_object(self):
|
def test_access_content_object(self):
|
||||||
"""
|
"""
|
||||||
|
@ -105,9 +99,7 @@ class GenericRelationsTests(TestCase):
|
||||||
def test_query_content_object(self):
|
def test_query_content_object(self):
|
||||||
qs = TaggedItem.objects.filter(
|
qs = TaggedItem.objects.filter(
|
||||||
animal__isnull=False).order_by('animal__common_name', 'tag')
|
animal__isnull=False).order_by('animal__common_name', 'tag')
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(qs, [self.hairy, self.yellow])
|
||||||
qs, ["<TaggedItem: hairy>", "<TaggedItem: yellow>"]
|
|
||||||
)
|
|
||||||
|
|
||||||
mpk = ManualPK.objects.create(id=1)
|
mpk = ManualPK.objects.create(id=1)
|
||||||
mpk.tags.create(tag='mpk')
|
mpk.tags.create(tag='mpk')
|
||||||
|
@ -124,17 +116,14 @@ class GenericRelationsTests(TestCase):
|
||||||
# defined. That's OK, because you can create TaggedItems explicitly.
|
# defined. That's OK, because you can create TaggedItems explicitly.
|
||||||
# However, excluding GenericRelations means your lookups have to be a
|
# However, excluding GenericRelations means your lookups have to be a
|
||||||
# bit more explicit.
|
# bit more explicit.
|
||||||
TaggedItem.objects.create(content_object=self.quartz, tag="shiny")
|
shiny = TaggedItem.objects.create(content_object=self.quartz, tag="shiny")
|
||||||
TaggedItem.objects.create(content_object=self.quartz, tag="clearish")
|
clearish = TaggedItem.objects.create(content_object=self.quartz, tag="clearish")
|
||||||
|
|
||||||
ctype = ContentType.objects.get_for_model(self.quartz)
|
ctype = ContentType.objects.get_for_model(self.quartz)
|
||||||
q = TaggedItem.objects.filter(
|
q = TaggedItem.objects.filter(
|
||||||
content_type__pk=ctype.id, object_id=self.quartz.id
|
content_type__pk=ctype.id, object_id=self.quartz.id
|
||||||
)
|
)
|
||||||
self.assertQuerysetEqual(q, [
|
self.assertSequenceEqual(q, [clearish, shiny])
|
||||||
"<TaggedItem: clearish>",
|
|
||||||
"<TaggedItem: shiny>"
|
|
||||||
])
|
|
||||||
|
|
||||||
def test_access_via_content_type(self):
|
def test_access_via_content_type(self):
|
||||||
"""
|
"""
|
||||||
|
@ -145,9 +134,10 @@ class GenericRelationsTests(TestCase):
|
||||||
|
|
||||||
ctype = ContentType.objects.get_for_model(self.platypus)
|
ctype = ContentType.objects.get_for_model(self.platypus)
|
||||||
|
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
Animal.objects.filter(tags__content_type=ctype),
|
Animal.objects.filter(tags__content_type=ctype),
|
||||||
["<Animal: Platypus>"])
|
[self.platypus],
|
||||||
|
)
|
||||||
|
|
||||||
def test_set_foreign_key(self):
|
def test_set_foreign_key(self):
|
||||||
"""
|
"""
|
||||||
|
@ -157,9 +147,7 @@ class GenericRelationsTests(TestCase):
|
||||||
tag1.content_object = self.platypus
|
tag1.content_object = self.platypus
|
||||||
tag1.save()
|
tag1.save()
|
||||||
|
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(self.platypus.tags.all(), [tag1])
|
||||||
self.platypus.tags.all(),
|
|
||||||
["<TaggedItem: shiny>"])
|
|
||||||
|
|
||||||
def test_queries_across_generic_relations(self):
|
def test_queries_across_generic_relations(self):
|
||||||
"""
|
"""
|
||||||
|
@ -167,10 +155,10 @@ class GenericRelationsTests(TestCase):
|
||||||
there are two TaggedItems with a tag of "fatty", this query only pulls
|
there are two TaggedItems with a tag of "fatty", this query only pulls
|
||||||
out the one with the content type related to Animals.
|
out the one with the content type related to Animals.
|
||||||
"""
|
"""
|
||||||
self.assertQuerysetEqual(Animal.objects.order_by('common_name'), [
|
self.assertSequenceEqual(
|
||||||
"<Animal: Lion>",
|
Animal.objects.order_by('common_name'),
|
||||||
"<Animal: Platypus>"
|
[self.lion, self.platypus],
|
||||||
])
|
)
|
||||||
|
|
||||||
def test_queries_content_type_restriction(self):
|
def test_queries_content_type_restriction(self):
|
||||||
"""
|
"""
|
||||||
|
@ -181,10 +169,14 @@ class GenericRelationsTests(TestCase):
|
||||||
mpk.tags.create(tag="fatty")
|
mpk.tags.create(tag="fatty")
|
||||||
self.platypus.tags.create(tag="fatty")
|
self.platypus.tags.create(tag="fatty")
|
||||||
|
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
Animal.objects.filter(tags__tag='fatty'), ["<Animal: Platypus>"])
|
Animal.objects.filter(tags__tag='fatty'),
|
||||||
self.assertQuerysetEqual(
|
[self.platypus],
|
||||||
Animal.objects.exclude(tags__tag='fatty'), ["<Animal: Lion>"])
|
)
|
||||||
|
self.assertSequenceEqual(
|
||||||
|
Animal.objects.exclude(tags__tag='fatty'),
|
||||||
|
[self.lion],
|
||||||
|
)
|
||||||
|
|
||||||
def test_object_deletion_with_generic_relation(self):
|
def test_object_deletion_with_generic_relation(self):
|
||||||
"""
|
"""
|
||||||
|
@ -236,7 +228,7 @@ class GenericRelationsTests(TestCase):
|
||||||
content_type__pk=ctype.id, object_id=self.lion.id, tag="hairy")
|
content_type__pk=ctype.id, object_id=self.lion.id, tag="hairy")
|
||||||
tag.delete()
|
tag.delete()
|
||||||
|
|
||||||
self.assertQuerysetEqual(self.lion.tags.all(), ["<TaggedItem: yellow>"])
|
self.assertSequenceEqual(self.lion.tags.all(), [self.yellow])
|
||||||
self.assertQuerysetEqual(TaggedItem.objects.all(), [
|
self.assertQuerysetEqual(TaggedItem.objects.all(), [
|
||||||
('fatty', Vegetable, self.bacon.pk),
|
('fatty', Vegetable, self.bacon.pk),
|
||||||
('salty', Vegetable, self.bacon.pk),
|
('salty', Vegetable, self.bacon.pk),
|
||||||
|
@ -282,32 +274,22 @@ class GenericRelationsTests(TestCase):
|
||||||
salty = bacon.tags.create(tag="salty")
|
salty = bacon.tags.create(tag="salty")
|
||||||
|
|
||||||
bacon.tags.set([fatty, salty])
|
bacon.tags.set([fatty, salty])
|
||||||
self.assertQuerysetEqual(bacon.tags.all(), [
|
self.assertSequenceEqual(bacon.tags.all(), [fatty, salty])
|
||||||
"<TaggedItem: fatty>",
|
|
||||||
"<TaggedItem: salty>",
|
|
||||||
])
|
|
||||||
|
|
||||||
bacon.tags.set([fatty])
|
bacon.tags.set([fatty])
|
||||||
self.assertQuerysetEqual(bacon.tags.all(), [
|
self.assertSequenceEqual(bacon.tags.all(), [fatty])
|
||||||
"<TaggedItem: fatty>",
|
|
||||||
])
|
|
||||||
|
|
||||||
bacon.tags.set([])
|
bacon.tags.set([])
|
||||||
self.assertQuerysetEqual(bacon.tags.all(), [])
|
self.assertSequenceEqual(bacon.tags.all(), [])
|
||||||
|
|
||||||
bacon.tags.set([fatty, salty], bulk=False, clear=True)
|
bacon.tags.set([fatty, salty], bulk=False, clear=True)
|
||||||
self.assertQuerysetEqual(bacon.tags.all(), [
|
self.assertSequenceEqual(bacon.tags.all(), [fatty, salty])
|
||||||
"<TaggedItem: fatty>",
|
|
||||||
"<TaggedItem: salty>",
|
|
||||||
])
|
|
||||||
|
|
||||||
bacon.tags.set([fatty], bulk=False, clear=True)
|
bacon.tags.set([fatty], bulk=False, clear=True)
|
||||||
self.assertQuerysetEqual(bacon.tags.all(), [
|
self.assertSequenceEqual(bacon.tags.all(), [fatty])
|
||||||
"<TaggedItem: fatty>",
|
|
||||||
])
|
|
||||||
|
|
||||||
bacon.tags.set([], clear=True)
|
bacon.tags.set([], clear=True)
|
||||||
self.assertQuerysetEqual(bacon.tags.all(), [])
|
self.assertSequenceEqual(bacon.tags.all(), [])
|
||||||
|
|
||||||
def test_assign(self):
|
def test_assign(self):
|
||||||
bacon = Vegetable.objects.create(name="Bacon", is_yucky=False)
|
bacon = Vegetable.objects.create(name="Bacon", is_yucky=False)
|
||||||
|
@ -315,18 +297,13 @@ class GenericRelationsTests(TestCase):
|
||||||
salty = bacon.tags.create(tag="salty")
|
salty = bacon.tags.create(tag="salty")
|
||||||
|
|
||||||
bacon.tags.set([fatty, salty])
|
bacon.tags.set([fatty, salty])
|
||||||
self.assertQuerysetEqual(bacon.tags.all(), [
|
self.assertSequenceEqual(bacon.tags.all(), [fatty, salty])
|
||||||
"<TaggedItem: fatty>",
|
|
||||||
"<TaggedItem: salty>",
|
|
||||||
])
|
|
||||||
|
|
||||||
bacon.tags.set([fatty])
|
bacon.tags.set([fatty])
|
||||||
self.assertQuerysetEqual(bacon.tags.all(), [
|
self.assertSequenceEqual(bacon.tags.all(), [fatty])
|
||||||
"<TaggedItem: fatty>",
|
|
||||||
])
|
|
||||||
|
|
||||||
bacon.tags.set([])
|
bacon.tags.set([])
|
||||||
self.assertQuerysetEqual(bacon.tags.all(), [])
|
self.assertSequenceEqual(bacon.tags.all(), [])
|
||||||
|
|
||||||
def test_assign_with_queryset(self):
|
def test_assign_with_queryset(self):
|
||||||
# Querysets used in reverse GFK assignments are pre-evaluated so their
|
# Querysets used in reverse GFK assignments are pre-evaluated so their
|
||||||
|
@ -361,42 +338,35 @@ class GenericRelationsTests(TestCase):
|
||||||
bear = Animal.objects.create(common_name="bear")
|
bear = Animal.objects.create(common_name="bear")
|
||||||
|
|
||||||
# Create directly
|
# Create directly
|
||||||
Comparison.objects.create(
|
c1 = Comparison.objects.create(
|
||||||
first_obj=cheetah, other_obj=tiger, comparative="faster"
|
first_obj=cheetah, other_obj=tiger, comparative="faster"
|
||||||
)
|
)
|
||||||
Comparison.objects.create(
|
c2 = Comparison.objects.create(
|
||||||
first_obj=tiger, other_obj=cheetah, comparative="cooler"
|
first_obj=tiger, other_obj=cheetah, comparative="cooler"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Create using GenericRelation
|
# Create using GenericRelation
|
||||||
tiger.comparisons.create(other_obj=bear, comparative="cooler")
|
c3 = tiger.comparisons.create(other_obj=bear, comparative="cooler")
|
||||||
tiger.comparisons.create(other_obj=cheetah, comparative="stronger")
|
c4 = tiger.comparisons.create(other_obj=cheetah, comparative="stronger")
|
||||||
self.assertQuerysetEqual(cheetah.comparisons.all(), [
|
self.assertSequenceEqual(cheetah.comparisons.all(), [c1])
|
||||||
"<Comparison: cheetah is faster than tiger>"
|
|
||||||
])
|
|
||||||
|
|
||||||
# Filtering works
|
# Filtering works
|
||||||
self.assertQuerysetEqual(tiger.comparisons.filter(comparative="cooler"), [
|
self.assertCountEqual(
|
||||||
"<Comparison: tiger is cooler than cheetah>",
|
tiger.comparisons.filter(comparative='cooler'),
|
||||||
"<Comparison: tiger is cooler than bear>",
|
[c2, c3],
|
||||||
], ordered=False)
|
)
|
||||||
|
|
||||||
# Filtering and deleting works
|
# Filtering and deleting works
|
||||||
subjective = ["cooler"]
|
subjective = ["cooler"]
|
||||||
tiger.comparisons.filter(comparative__in=subjective).delete()
|
tiger.comparisons.filter(comparative__in=subjective).delete()
|
||||||
self.assertQuerysetEqual(Comparison.objects.all(), [
|
self.assertCountEqual(Comparison.objects.all(), [c1, c4])
|
||||||
"<Comparison: cheetah is faster than tiger>",
|
|
||||||
"<Comparison: tiger is stronger than cheetah>"
|
|
||||||
], ordered=False)
|
|
||||||
|
|
||||||
# If we delete cheetah, Comparisons with cheetah as 'first_obj' will be
|
# If we delete cheetah, Comparisons with cheetah as 'first_obj' will be
|
||||||
# deleted since Animal has an explicit GenericRelation to Comparison
|
# deleted since Animal has an explicit GenericRelation to Comparison
|
||||||
# through first_obj. Comparisons with cheetah as 'other_obj' will not
|
# through first_obj. Comparisons with cheetah as 'other_obj' will not
|
||||||
# be deleted.
|
# be deleted.
|
||||||
cheetah.delete()
|
cheetah.delete()
|
||||||
self.assertQuerysetEqual(Comparison.objects.all(), [
|
self.assertSequenceEqual(Comparison.objects.all(), [c4])
|
||||||
"<Comparison: tiger is stronger than None>"
|
|
||||||
])
|
|
||||||
|
|
||||||
def test_gfk_subclasses(self):
|
def test_gfk_subclasses(self):
|
||||||
# GenericForeignKey should work with subclasses (see #8309)
|
# GenericForeignKey should work with subclasses (see #8309)
|
||||||
|
|
|
@ -105,7 +105,7 @@ class CreateViewTests(TestCase):
|
||||||
res = self.client.post('/edit/authors/create/', {'name': 'Randall Munroe', 'slug': 'randall-munroe'})
|
res = self.client.post('/edit/authors/create/', {'name': 'Randall Munroe', 'slug': 'randall-munroe'})
|
||||||
self.assertEqual(res.status_code, 302)
|
self.assertEqual(res.status_code, 302)
|
||||||
self.assertRedirects(res, '/list/authors/')
|
self.assertRedirects(res, '/list/authors/')
|
||||||
self.assertQuerysetEqual(Author.objects.all(), ['<Author: Randall Munroe>'])
|
self.assertQuerysetEqual(Author.objects.values_list('name', flat=True), ['Randall Munroe'])
|
||||||
|
|
||||||
def test_create_invalid(self):
|
def test_create_invalid(self):
|
||||||
res = self.client.post('/edit/authors/create/', {'name': 'A' * 101, 'slug': 'randall-munroe'})
|
res = self.client.post('/edit/authors/create/', {'name': 'A' * 101, 'slug': 'randall-munroe'})
|
||||||
|
@ -119,20 +119,20 @@ class CreateViewTests(TestCase):
|
||||||
self.assertEqual(res.status_code, 302)
|
self.assertEqual(res.status_code, 302)
|
||||||
artist = Artist.objects.get(name='Rene Magritte')
|
artist = Artist.objects.get(name='Rene Magritte')
|
||||||
self.assertRedirects(res, '/detail/artist/%d/' % artist.pk)
|
self.assertRedirects(res, '/detail/artist/%d/' % artist.pk)
|
||||||
self.assertQuerysetEqual(Artist.objects.all(), ['<Artist: Rene Magritte>'])
|
self.assertQuerysetEqual(Artist.objects.all(), [artist])
|
||||||
|
|
||||||
def test_create_with_redirect(self):
|
def test_create_with_redirect(self):
|
||||||
res = self.client.post('/edit/authors/create/redirect/', {'name': 'Randall Munroe', 'slug': 'randall-munroe'})
|
res = self.client.post('/edit/authors/create/redirect/', {'name': 'Randall Munroe', 'slug': 'randall-munroe'})
|
||||||
self.assertEqual(res.status_code, 302)
|
self.assertEqual(res.status_code, 302)
|
||||||
self.assertRedirects(res, '/edit/authors/create/')
|
self.assertRedirects(res, '/edit/authors/create/')
|
||||||
self.assertQuerysetEqual(Author.objects.all(), ['<Author: Randall Munroe>'])
|
self.assertQuerysetEqual(Author.objects.values_list('name', flat=True), ['Randall Munroe'])
|
||||||
|
|
||||||
def test_create_with_interpolated_redirect(self):
|
def test_create_with_interpolated_redirect(self):
|
||||||
res = self.client.post(
|
res = self.client.post(
|
||||||
'/edit/authors/create/interpolate_redirect/',
|
'/edit/authors/create/interpolate_redirect/',
|
||||||
{'name': 'Randall Munroe', 'slug': 'randall-munroe'}
|
{'name': 'Randall Munroe', 'slug': 'randall-munroe'}
|
||||||
)
|
)
|
||||||
self.assertQuerysetEqual(Author.objects.all(), ['<Author: Randall Munroe>'])
|
self.assertQuerysetEqual(Author.objects.values_list('name', flat=True), ['Randall Munroe'])
|
||||||
self.assertEqual(res.status_code, 302)
|
self.assertEqual(res.status_code, 302)
|
||||||
pk = Author.objects.first().pk
|
pk = Author.objects.first().pk
|
||||||
self.assertRedirects(res, '/edit/author/%d/update/' % pk)
|
self.assertRedirects(res, '/edit/author/%d/update/' % pk)
|
||||||
|
@ -157,7 +157,7 @@ class CreateViewTests(TestCase):
|
||||||
self.assertEqual(res.status_code, 302)
|
self.assertEqual(res.status_code, 302)
|
||||||
obj = Author.objects.get(slug='randall-munroe')
|
obj = Author.objects.get(slug='randall-munroe')
|
||||||
self.assertRedirects(res, reverse('author_detail', kwargs={'pk': obj.pk}))
|
self.assertRedirects(res, reverse('author_detail', kwargs={'pk': obj.pk}))
|
||||||
self.assertQuerysetEqual(Author.objects.all(), ['<Author: Randall Munroe>'])
|
self.assertQuerysetEqual(Author.objects.all(), [obj])
|
||||||
|
|
||||||
def test_create_without_redirect(self):
|
def test_create_without_redirect(self):
|
||||||
msg = (
|
msg = (
|
||||||
|
@ -239,7 +239,7 @@ class UpdateViewTests(TestCase):
|
||||||
)
|
)
|
||||||
self.assertEqual(res.status_code, 302)
|
self.assertEqual(res.status_code, 302)
|
||||||
self.assertRedirects(res, '/list/authors/')
|
self.assertRedirects(res, '/list/authors/')
|
||||||
self.assertQuerysetEqual(Author.objects.all(), ['<Author: Randall Munroe (xkcd)>'])
|
self.assertQuerysetEqual(Author.objects.values_list('name', flat=True), ['Randall Munroe (xkcd)'])
|
||||||
|
|
||||||
def test_update_invalid(self):
|
def test_update_invalid(self):
|
||||||
res = self.client.post(
|
res = self.client.post(
|
||||||
|
@ -249,7 +249,7 @@ class UpdateViewTests(TestCase):
|
||||||
self.assertEqual(res.status_code, 200)
|
self.assertEqual(res.status_code, 200)
|
||||||
self.assertTemplateUsed(res, 'generic_views/author_form.html')
|
self.assertTemplateUsed(res, 'generic_views/author_form.html')
|
||||||
self.assertEqual(len(res.context['form'].errors), 1)
|
self.assertEqual(len(res.context['form'].errors), 1)
|
||||||
self.assertQuerysetEqual(Author.objects.all(), ['<Author: Randall Munroe>'])
|
self.assertQuerysetEqual(Author.objects.all(), [self.author])
|
||||||
self.assertEqual(res.context['view'].get_form_called_count, 1)
|
self.assertEqual(res.context['view'].get_form_called_count, 1)
|
||||||
|
|
||||||
def test_update_with_object_url(self):
|
def test_update_with_object_url(self):
|
||||||
|
@ -257,7 +257,7 @@ class UpdateViewTests(TestCase):
|
||||||
res = self.client.post('/edit/artists/%d/update/' % a.pk, {'name': 'Rene Magritte'})
|
res = self.client.post('/edit/artists/%d/update/' % a.pk, {'name': 'Rene Magritte'})
|
||||||
self.assertEqual(res.status_code, 302)
|
self.assertEqual(res.status_code, 302)
|
||||||
self.assertRedirects(res, '/detail/artist/%d/' % a.pk)
|
self.assertRedirects(res, '/detail/artist/%d/' % a.pk)
|
||||||
self.assertQuerysetEqual(Artist.objects.all(), ['<Artist: Rene Magritte>'])
|
self.assertQuerysetEqual(Artist.objects.all(), [a])
|
||||||
|
|
||||||
def test_update_with_redirect(self):
|
def test_update_with_redirect(self):
|
||||||
res = self.client.post(
|
res = self.client.post(
|
||||||
|
@ -266,14 +266,14 @@ class UpdateViewTests(TestCase):
|
||||||
)
|
)
|
||||||
self.assertEqual(res.status_code, 302)
|
self.assertEqual(res.status_code, 302)
|
||||||
self.assertRedirects(res, '/edit/authors/create/')
|
self.assertRedirects(res, '/edit/authors/create/')
|
||||||
self.assertQuerysetEqual(Author.objects.all(), ['<Author: Randall Munroe (author of xkcd)>'])
|
self.assertQuerysetEqual(Author.objects.values_list('name', flat=True), ['Randall Munroe (author of xkcd)'])
|
||||||
|
|
||||||
def test_update_with_interpolated_redirect(self):
|
def test_update_with_interpolated_redirect(self):
|
||||||
res = self.client.post(
|
res = self.client.post(
|
||||||
'/edit/author/%d/update/interpolate_redirect/' % self.author.pk,
|
'/edit/author/%d/update/interpolate_redirect/' % self.author.pk,
|
||||||
{'name': 'Randall Munroe (author of xkcd)', 'slug': 'randall-munroe'}
|
{'name': 'Randall Munroe (author of xkcd)', 'slug': 'randall-munroe'}
|
||||||
)
|
)
|
||||||
self.assertQuerysetEqual(Author.objects.all(), ['<Author: Randall Munroe (author of xkcd)>'])
|
self.assertQuerysetEqual(Author.objects.values_list('name', flat=True), ['Randall Munroe (author of xkcd)'])
|
||||||
self.assertEqual(res.status_code, 302)
|
self.assertEqual(res.status_code, 302)
|
||||||
pk = Author.objects.first().pk
|
pk = Author.objects.first().pk
|
||||||
self.assertRedirects(res, '/edit/author/%d/update/' % pk)
|
self.assertRedirects(res, '/edit/author/%d/update/' % pk)
|
||||||
|
@ -301,7 +301,7 @@ class UpdateViewTests(TestCase):
|
||||||
)
|
)
|
||||||
self.assertEqual(res.status_code, 302)
|
self.assertEqual(res.status_code, 302)
|
||||||
self.assertRedirects(res, '/detail/author/%d/' % self.author.pk)
|
self.assertRedirects(res, '/detail/author/%d/' % self.author.pk)
|
||||||
self.assertQuerysetEqual(Author.objects.all(), ['<Author: Randall Munroe (author of xkcd)>'])
|
self.assertQuerysetEqual(Author.objects.values_list('name', flat=True), ['Randall Munroe (author of xkcd)'])
|
||||||
|
|
||||||
def test_update_without_redirect(self):
|
def test_update_without_redirect(self):
|
||||||
msg = (
|
msg = (
|
||||||
|
@ -327,7 +327,7 @@ class UpdateViewTests(TestCase):
|
||||||
res = self.client.post('/edit/author/update/', {'name': 'Randall Munroe (xkcd)', 'slug': 'randall-munroe'})
|
res = self.client.post('/edit/author/update/', {'name': 'Randall Munroe (xkcd)', 'slug': 'randall-munroe'})
|
||||||
self.assertEqual(res.status_code, 302)
|
self.assertEqual(res.status_code, 302)
|
||||||
self.assertRedirects(res, '/list/authors/')
|
self.assertRedirects(res, '/list/authors/')
|
||||||
self.assertQuerysetEqual(Author.objects.all(), ['<Author: Randall Munroe (xkcd)>'])
|
self.assertQuerysetEqual(Author.objects.values_list('name', flat=True), ['Randall Munroe (xkcd)'])
|
||||||
|
|
||||||
|
|
||||||
@override_settings(ROOT_URLCONF='generic_views.urls')
|
@override_settings(ROOT_URLCONF='generic_views.urls')
|
||||||
|
|
|
@ -13,22 +13,19 @@ class TimeFieldLookupTests(TestCase):
|
||||||
self.al3 = Alarm.objects.create(desc='Precise', time='12:34:56')
|
self.al3 = Alarm.objects.create(desc='Precise', time='12:34:56')
|
||||||
|
|
||||||
def test_hour_lookups(self):
|
def test_hour_lookups(self):
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
Alarm.objects.filter(time__hour=5),
|
Alarm.objects.filter(time__hour=5),
|
||||||
['<Alarm: 05:30:00 (Early)>'],
|
[self.al1],
|
||||||
ordered=False
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_minute_lookups(self):
|
def test_minute_lookups(self):
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
Alarm.objects.filter(time__minute=30),
|
Alarm.objects.filter(time__minute=30),
|
||||||
['<Alarm: 05:30:00 (Early)>'],
|
[self.al1],
|
||||||
ordered=False
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_second_lookups(self):
|
def test_second_lookups(self):
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
Alarm.objects.filter(time__second=56),
|
Alarm.objects.filter(time__second=56),
|
||||||
['<Alarm: 12:34:56 (Precise)>'],
|
[self.al3],
|
||||||
ordered=False
|
|
||||||
)
|
)
|
||||||
|
|
|
@ -84,23 +84,17 @@ class LookupTests(TestCase):
|
||||||
|
|
||||||
def test_lookup_int_as_str(self):
|
def test_lookup_int_as_str(self):
|
||||||
# Integer value can be queried using string
|
# Integer value can be queried using string
|
||||||
self.assertQuerysetEqual(Article.objects.filter(id__iexact=str(self.a1.id)),
|
self.assertSequenceEqual(
|
||||||
['<Article: Article 1>'])
|
Article.objects.filter(id__iexact=str(self.a1.id)),
|
||||||
|
[self.a1],
|
||||||
|
)
|
||||||
|
|
||||||
@skipUnlessDBFeature('supports_date_lookup_using_string')
|
@skipUnlessDBFeature('supports_date_lookup_using_string')
|
||||||
def test_lookup_date_as_str(self):
|
def test_lookup_date_as_str(self):
|
||||||
# A date lookup can be performed using a string search
|
# A date lookup can be performed using a string search
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
Article.objects.filter(pub_date__startswith='2005'),
|
Article.objects.filter(pub_date__startswith='2005'),
|
||||||
[
|
[self.a5, self.a6, self.a4, self.a2, self.a3, self.a7, self.a1],
|
||||||
'<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):
|
def test_iterator(self):
|
||||||
|
@ -492,96 +486,48 @@ class LookupTests(TestCase):
|
||||||
def test_escaping(self):
|
def test_escaping(self):
|
||||||
# Underscores, percent signs and backslashes have special meaning in the
|
# Underscores, percent signs and backslashes have special meaning in the
|
||||||
# underlying SQL code, but Django handles the quoting of them automatically.
|
# underlying SQL code, but Django handles the quoting of them automatically.
|
||||||
Article.objects.create(headline='Article_ with underscore', pub_date=datetime(2005, 11, 20))
|
a8 = Article.objects.create(headline='Article_ with underscore', pub_date=datetime(2005, 11, 20))
|
||||||
|
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
Article.objects.filter(headline__startswith='Article'),
|
Article.objects.filter(headline__startswith='Article'),
|
||||||
[
|
[a8, self.a5, self.a6, self.a4, self.a2, self.a3, self.a7, self.a1],
|
||||||
'<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(
|
self.assertSequenceEqual(
|
||||||
Article.objects.filter(headline__startswith='Article_'),
|
Article.objects.filter(headline__startswith='Article_'),
|
||||||
['<Article: Article_ with underscore>']
|
[a8],
|
||||||
)
|
)
|
||||||
Article.objects.create(headline='Article% with percent sign', pub_date=datetime(2005, 11, 21))
|
a9 = Article.objects.create(headline='Article% with percent sign', pub_date=datetime(2005, 11, 21))
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
Article.objects.filter(headline__startswith='Article'),
|
Article.objects.filter(headline__startswith='Article'),
|
||||||
[
|
[a9, a8, self.a5, self.a6, self.a4, self.a2, self.a3, self.a7, self.a1],
|
||||||
'<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(
|
self.assertSequenceEqual(
|
||||||
Article.objects.filter(headline__startswith='Article%'),
|
Article.objects.filter(headline__startswith='Article%'),
|
||||||
['<Article: Article% with percent sign>']
|
[a9],
|
||||||
)
|
)
|
||||||
Article.objects.create(headline='Article with \\ backslash', pub_date=datetime(2005, 11, 22))
|
a10 = Article.objects.create(headline='Article with \\ backslash', pub_date=datetime(2005, 11, 22))
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
Article.objects.filter(headline__contains='\\'),
|
Article.objects.filter(headline__contains='\\'),
|
||||||
[r'<Article: Article with \ backslash>']
|
[a10],
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_exclude(self):
|
def test_exclude(self):
|
||||||
Article.objects.bulk_create([
|
pub_date = datetime(2005, 11, 20)
|
||||||
Article(headline='Article_ with underscore', pub_date=datetime(2005, 11, 20)),
|
a8 = Article.objects.create(headline='Article_ with underscore', pub_date=pub_date)
|
||||||
Article(headline='Article% with percent sign', pub_date=datetime(2005, 11, 21)),
|
a9 = Article.objects.create(headline='Article% with percent sign', pub_date=pub_date)
|
||||||
Article(headline='Article with \\ backslash', pub_date=datetime(2005, 11, 22)),
|
a10 = Article.objects.create(headline='Article with \\ backslash', pub_date=pub_date)
|
||||||
])
|
|
||||||
# exclude() is the opposite of filter() when doing lookups:
|
# exclude() is the opposite of filter() when doing lookups:
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
Article.objects.filter(headline__contains='Article').exclude(headline__contains='with'),
|
Article.objects.filter(headline__contains='Article').exclude(headline__contains='with'),
|
||||||
[
|
[self.a5, self.a6, self.a4, self.a2, self.a3, self.a7, self.a1],
|
||||||
'<Article: Article 5>',
|
|
||||||
'<Article: Article 6>',
|
|
||||||
'<Article: Article 4>',
|
|
||||||
'<Article: Article 2>',
|
|
||||||
'<Article: Article 3>',
|
|
||||||
'<Article: Article 7>',
|
|
||||||
'<Article: Article 1>',
|
|
||||||
]
|
|
||||||
)
|
)
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
Article.objects.exclude(headline__startswith="Article_"),
|
Article.objects.exclude(headline__startswith="Article_"),
|
||||||
[
|
[a10, a9, self.a5, self.a6, self.a4, self.a2, self.a3, self.a7, self.a1],
|
||||||
'<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(
|
self.assertSequenceEqual(
|
||||||
Article.objects.exclude(headline="Article 7"),
|
Article.objects.exclude(headline="Article 7"),
|
||||||
[
|
[a10, a9, a8, self.a5, self.a6, self.a4, self.a2, self.a3, self.a1],
|
||||||
'<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):
|
def test_none(self):
|
||||||
|
@ -594,17 +540,9 @@ class LookupTests(TestCase):
|
||||||
self.assertQuerysetEqual(Article.objects.none().iterator(), [])
|
self.assertQuerysetEqual(Article.objects.none().iterator(), [])
|
||||||
|
|
||||||
def test_in(self):
|
def test_in(self):
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
Article.objects.exclude(id__in=[]),
|
Article.objects.exclude(id__in=[]),
|
||||||
[
|
[self.a5, self.a6, self.a4, self.a2, self.a3, self.a7, self.a1],
|
||||||
'<Article: Article 5>',
|
|
||||||
'<Article: Article 6>',
|
|
||||||
'<Article: Article 4>',
|
|
||||||
'<Article: Article 2>',
|
|
||||||
'<Article: Article 3>',
|
|
||||||
'<Article: Article 7>',
|
|
||||||
'<Article: Article 1>',
|
|
||||||
]
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_in_empty_list(self):
|
def test_in_empty_list(self):
|
||||||
|
@ -706,49 +644,52 @@ class LookupTests(TestCase):
|
||||||
# zero-or-more
|
# zero-or-more
|
||||||
self.assertQuerysetEqual(
|
self.assertQuerysetEqual(
|
||||||
Article.objects.filter(headline__regex=r'fo*'),
|
Article.objects.filter(headline__regex=r'fo*'),
|
||||||
['<Article: f>', '<Article: fo>', '<Article: foo>', '<Article: fooo>']
|
Article.objects.filter(headline__in=['f', 'fo', 'foo', 'fooo']),
|
||||||
)
|
)
|
||||||
self.assertQuerysetEqual(
|
self.assertQuerysetEqual(
|
||||||
Article.objects.filter(headline__iregex=r'fo*'),
|
Article.objects.filter(headline__iregex=r'fo*'),
|
||||||
[
|
Article.objects.filter(headline__in=['f', 'fo', 'foo', 'fooo', 'hey-Foo']),
|
||||||
'<Article: f>',
|
|
||||||
'<Article: fo>',
|
|
||||||
'<Article: foo>',
|
|
||||||
'<Article: fooo>',
|
|
||||||
'<Article: hey-Foo>',
|
|
||||||
]
|
|
||||||
)
|
)
|
||||||
# one-or-more
|
# one-or-more
|
||||||
self.assertQuerysetEqual(
|
self.assertQuerysetEqual(
|
||||||
Article.objects.filter(headline__regex=r'fo+'),
|
Article.objects.filter(headline__regex=r'fo+'),
|
||||||
['<Article: fo>', '<Article: foo>', '<Article: fooo>']
|
Article.objects.filter(headline__in=['fo', 'foo', 'fooo']),
|
||||||
)
|
)
|
||||||
# wildcard
|
# wildcard
|
||||||
self.assertQuerysetEqual(
|
self.assertQuerysetEqual(
|
||||||
Article.objects.filter(headline__regex=r'fooo?'),
|
Article.objects.filter(headline__regex=r'fooo?'),
|
||||||
['<Article: foo>', '<Article: fooo>']
|
Article.objects.filter(headline__in=['foo', 'fooo']),
|
||||||
)
|
)
|
||||||
# leading anchor
|
# leading anchor
|
||||||
self.assertQuerysetEqual(
|
self.assertQuerysetEqual(
|
||||||
Article.objects.filter(headline__regex=r'^b'),
|
Article.objects.filter(headline__regex=r'^b'),
|
||||||
['<Article: bar>', '<Article: baxZ>', '<Article: baz>']
|
Article.objects.filter(headline__in=['bar', 'baxZ', 'baz']),
|
||||||
|
)
|
||||||
|
self.assertQuerysetEqual(
|
||||||
|
Article.objects.filter(headline__iregex=r'^a'),
|
||||||
|
Article.objects.filter(headline='AbBa'),
|
||||||
)
|
)
|
||||||
self.assertQuerysetEqual(Article.objects.filter(headline__iregex=r'^a'), ['<Article: AbBa>'])
|
|
||||||
# trailing anchor
|
# trailing anchor
|
||||||
self.assertQuerysetEqual(Article.objects.filter(headline__regex=r'z$'), ['<Article: baz>'])
|
self.assertQuerysetEqual(
|
||||||
|
Article.objects.filter(headline__regex=r'z$'),
|
||||||
|
Article.objects.filter(headline='baz'),
|
||||||
|
)
|
||||||
self.assertQuerysetEqual(
|
self.assertQuerysetEqual(
|
||||||
Article.objects.filter(headline__iregex=r'z$'),
|
Article.objects.filter(headline__iregex=r'z$'),
|
||||||
['<Article: baxZ>', '<Article: baz>']
|
Article.objects.filter(headline__in=['baxZ', 'baz']),
|
||||||
)
|
)
|
||||||
# character sets
|
# character sets
|
||||||
self.assertQuerysetEqual(
|
self.assertQuerysetEqual(
|
||||||
Article.objects.filter(headline__regex=r'ba[rz]'),
|
Article.objects.filter(headline__regex=r'ba[rz]'),
|
||||||
['<Article: bar>', '<Article: baz>']
|
Article.objects.filter(headline__in=['bar', 'baz']),
|
||||||
|
)
|
||||||
|
self.assertQuerysetEqual(
|
||||||
|
Article.objects.filter(headline__regex=r'ba.[RxZ]'),
|
||||||
|
Article.objects.filter(headline='baxZ'),
|
||||||
)
|
)
|
||||||
self.assertQuerysetEqual(Article.objects.filter(headline__regex=r'ba.[RxZ]'), ['<Article: baxZ>'])
|
|
||||||
self.assertQuerysetEqual(
|
self.assertQuerysetEqual(
|
||||||
Article.objects.filter(headline__iregex=r'ba[RxZ]'),
|
Article.objects.filter(headline__iregex=r'ba[RxZ]'),
|
||||||
['<Article: bar>', '<Article: baxZ>', '<Article: baz>']
|
Article.objects.filter(headline__in=['bar', 'baxZ', 'baz']),
|
||||||
)
|
)
|
||||||
|
|
||||||
# and more articles:
|
# and more articles:
|
||||||
|
@ -765,48 +706,48 @@ class LookupTests(TestCase):
|
||||||
# alternation
|
# alternation
|
||||||
self.assertQuerysetEqual(
|
self.assertQuerysetEqual(
|
||||||
Article.objects.filter(headline__regex=r'oo(f|b)'),
|
Article.objects.filter(headline__regex=r'oo(f|b)'),
|
||||||
[
|
Article.objects.filter(headline__in=[
|
||||||
'<Article: barfoobaz>',
|
'barfoobaz',
|
||||||
'<Article: foobar>',
|
'foobar',
|
||||||
'<Article: foobarbaz>',
|
'foobarbaz',
|
||||||
'<Article: foobaz>',
|
'foobaz',
|
||||||
]
|
]),
|
||||||
)
|
)
|
||||||
self.assertQuerysetEqual(
|
self.assertQuerysetEqual(
|
||||||
Article.objects.filter(headline__iregex=r'oo(f|b)'),
|
Article.objects.filter(headline__iregex=r'oo(f|b)'),
|
||||||
[
|
Article.objects.filter(headline__in=[
|
||||||
'<Article: barfoobaz>',
|
'barfoobaz',
|
||||||
'<Article: foobar>',
|
'foobar',
|
||||||
'<Article: foobarbaz>',
|
'foobarbaz',
|
||||||
'<Article: foobaz>',
|
'foobaz',
|
||||||
'<Article: ooF>',
|
'ooF',
|
||||||
]
|
]),
|
||||||
)
|
)
|
||||||
self.assertQuerysetEqual(
|
self.assertQuerysetEqual(
|
||||||
Article.objects.filter(headline__regex=r'^foo(f|b)'),
|
Article.objects.filter(headline__regex=r'^foo(f|b)'),
|
||||||
['<Article: foobar>', '<Article: foobarbaz>', '<Article: foobaz>']
|
Article.objects.filter(headline__in=['foobar', 'foobarbaz', 'foobaz']),
|
||||||
)
|
)
|
||||||
|
|
||||||
# greedy matching
|
# greedy matching
|
||||||
self.assertQuerysetEqual(
|
self.assertQuerysetEqual(
|
||||||
Article.objects.filter(headline__regex=r'b.*az'),
|
Article.objects.filter(headline__regex=r'b.*az'),
|
||||||
[
|
Article.objects.filter(headline__in=[
|
||||||
'<Article: barfoobaz>',
|
'barfoobaz',
|
||||||
'<Article: baz>',
|
'baz',
|
||||||
'<Article: bazbaRFOO>',
|
'bazbaRFOO',
|
||||||
'<Article: foobarbaz>',
|
'foobarbaz',
|
||||||
'<Article: foobaz>',
|
'foobaz',
|
||||||
]
|
]),
|
||||||
)
|
)
|
||||||
self.assertQuerysetEqual(
|
self.assertQuerysetEqual(
|
||||||
Article.objects.filter(headline__iregex=r'b.*ar'),
|
Article.objects.filter(headline__iregex=r'b.*ar'),
|
||||||
[
|
Article.objects.filter(headline__in=[
|
||||||
'<Article: bar>',
|
'bar',
|
||||||
'<Article: barfoobaz>',
|
'barfoobaz',
|
||||||
'<Article: bazbaRFOO>',
|
'bazbaRFOO',
|
||||||
'<Article: foobar>',
|
'foobar',
|
||||||
'<Article: foobarbaz>',
|
'foobarbaz',
|
||||||
]
|
]),
|
||||||
)
|
)
|
||||||
|
|
||||||
@skipUnlessDBFeature('supports_regex_backreferencing')
|
@skipUnlessDBFeature('supports_regex_backreferencing')
|
||||||
|
@ -823,8 +764,8 @@ class LookupTests(TestCase):
|
||||||
Article(pub_date=now, headline='bazbaRFOO'),
|
Article(pub_date=now, headline='bazbaRFOO'),
|
||||||
])
|
])
|
||||||
self.assertQuerysetEqual(
|
self.assertQuerysetEqual(
|
||||||
Article.objects.filter(headline__regex=r'b(.).*b\1'),
|
Article.objects.filter(headline__regex=r'b(.).*b\1').values_list('headline', flat=True),
|
||||||
['<Article: barfoobaz>', '<Article: bazbaRFOO>', '<Article: foobarbaz>']
|
['barfoobaz', 'bazbaRFOO', 'foobarbaz'],
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_regex_null(self):
|
def test_regex_null(self):
|
||||||
|
@ -838,8 +779,8 @@ class LookupTests(TestCase):
|
||||||
"""
|
"""
|
||||||
A regex lookup does not fail on non-string fields
|
A regex lookup does not fail on non-string fields
|
||||||
"""
|
"""
|
||||||
Season.objects.create(year=2013, gt=444)
|
s = Season.objects.create(year=2013, gt=444)
|
||||||
self.assertQuerysetEqual(Season.objects.filter(gt__regex=r'^444$'), ['<Season: 2013>'])
|
self.assertQuerysetEqual(Season.objects.filter(gt__regex=r'^444$'), [s])
|
||||||
|
|
||||||
def test_regex_non_ascii(self):
|
def test_regex_non_ascii(self):
|
||||||
"""
|
"""
|
||||||
|
@ -928,31 +869,21 @@ class LookupTests(TestCase):
|
||||||
self.assertEqual(Player.objects.filter(games__season__gt__gt=222).distinct().count(), 2)
|
self.assertEqual(Player.objects.filter(games__season__gt__gt=222).distinct().count(), 2)
|
||||||
|
|
||||||
def test_chain_date_time_lookups(self):
|
def test_chain_date_time_lookups(self):
|
||||||
self.assertQuerysetEqual(
|
self.assertCountEqual(
|
||||||
Article.objects.filter(pub_date__month__gt=7),
|
Article.objects.filter(pub_date__month__gt=7),
|
||||||
['<Article: Article 5>', '<Article: Article 6>'],
|
[self.a5, self.a6],
|
||||||
ordered=False
|
|
||||||
)
|
)
|
||||||
self.assertQuerysetEqual(
|
self.assertCountEqual(
|
||||||
Article.objects.filter(pub_date__day__gte=27),
|
Article.objects.filter(pub_date__day__gte=27),
|
||||||
['<Article: Article 2>', '<Article: Article 3>',
|
[self.a2, self.a3, self.a4, self.a7],
|
||||||
'<Article: Article 4>', '<Article: Article 7>'],
|
|
||||||
ordered=False
|
|
||||||
)
|
)
|
||||||
self.assertQuerysetEqual(
|
self.assertCountEqual(
|
||||||
Article.objects.filter(pub_date__hour__lt=8),
|
Article.objects.filter(pub_date__hour__lt=8),
|
||||||
['<Article: Article 1>', '<Article: Article 2>',
|
[self.a1, self.a2, self.a3, self.a4, self.a7],
|
||||||
'<Article: Article 3>', '<Article: Article 4>',
|
|
||||||
'<Article: Article 7>'],
|
|
||||||
ordered=False
|
|
||||||
)
|
)
|
||||||
self.assertQuerysetEqual(
|
self.assertCountEqual(
|
||||||
Article.objects.filter(pub_date__minute__lte=0),
|
Article.objects.filter(pub_date__minute__lte=0),
|
||||||
['<Article: Article 1>', '<Article: Article 2>',
|
[self.a1, self.a2, self.a3, self.a4, self.a5, self.a6, self.a7],
|
||||||
'<Article: Article 3>', '<Article: Article 4>',
|
|
||||||
'<Article: Article 5>', '<Article: Article 6>',
|
|
||||||
'<Article: Article 7>'],
|
|
||||||
ordered=False
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_exact_none_transform(self):
|
def test_exact_none_transform(self):
|
||||||
|
|
|
@ -25,11 +25,11 @@ class M2MRegressionTests(TestCase):
|
||||||
e1.topics.add(t1)
|
e1.topics.add(t1)
|
||||||
e1.related.add(t2)
|
e1.related.add(t2)
|
||||||
|
|
||||||
self.assertQuerysetEqual(s1.references.all(), ["<SelfRefer: s2>"])
|
self.assertSequenceEqual(s1.references.all(), [s2])
|
||||||
self.assertQuerysetEqual(s1.related.all(), ["<SelfRefer: s3>"])
|
self.assertSequenceEqual(s1.related.all(), [s3])
|
||||||
|
|
||||||
self.assertQuerysetEqual(e1.topics.all(), ["<Tag: t1>"])
|
self.assertSequenceEqual(e1.topics.all(), [t1])
|
||||||
self.assertQuerysetEqual(e1.related.all(), ["<Tag: t2>"])
|
self.assertSequenceEqual(e1.related.all(), [t2])
|
||||||
|
|
||||||
def test_internal_related_name_not_in_error_msg(self):
|
def test_internal_related_name_not_in_error_msg(self):
|
||||||
# The secret internal related names for self-referential many-to-many
|
# The secret internal related names for self-referential many-to-many
|
||||||
|
@ -51,8 +51,8 @@ class M2MRegressionTests(TestCase):
|
||||||
sr_sibling.save()
|
sr_sibling.save()
|
||||||
sr_child.related.add(sr_sibling)
|
sr_child.related.add(sr_sibling)
|
||||||
|
|
||||||
self.assertQuerysetEqual(sr_child.related.all(), ["<SelfRefer: Beth>"])
|
self.assertSequenceEqual(sr_child.related.all(), [sr_sibling.selfrefer_ptr])
|
||||||
self.assertQuerysetEqual(sr_sibling.related.all(), ["<SelfRefer: Hanna>"])
|
self.assertSequenceEqual(sr_sibling.related.all(), [sr_child.selfrefer_ptr])
|
||||||
|
|
||||||
def test_m2m_pk_field_type(self):
|
def test_m2m_pk_field_type(self):
|
||||||
# Regression for #11311 - The primary key for models in a m2m relation
|
# Regression for #11311 - The primary key for models in a m2m relation
|
||||||
|
@ -73,8 +73,8 @@ class M2MRegressionTests(TestCase):
|
||||||
c1.tags.set([t1, t2])
|
c1.tags.set([t1, t2])
|
||||||
c1 = TagCollection.objects.get(name='c1')
|
c1 = TagCollection.objects.get(name='c1')
|
||||||
|
|
||||||
self.assertQuerysetEqual(c1.tags.all(), ["<Tag: t1>", "<Tag: t2>"], ordered=False)
|
self.assertCountEqual(c1.tags.all(), [t1, t2])
|
||||||
self.assertQuerysetEqual(t1.tag_collections.all(), ["<TagCollection: c1>"])
|
self.assertCountEqual(t1.tag_collections.all(), [c1])
|
||||||
|
|
||||||
def test_manager_class_caching(self):
|
def test_manager_class_caching(self):
|
||||||
e1 = Entry.objects.create()
|
e1 = Entry.objects.create()
|
||||||
|
@ -106,7 +106,7 @@ class M2MRegressionTests(TestCase):
|
||||||
c1.tags.set(7)
|
c1.tags.set(7)
|
||||||
|
|
||||||
c1.refresh_from_db()
|
c1.refresh_from_db()
|
||||||
self.assertQuerysetEqual(c1.tags.order_by('name'), ["<Tag: t1>", "<Tag: t2>"])
|
self.assertSequenceEqual(c1.tags.order_by('name'), [t1, t2])
|
||||||
|
|
||||||
def test_multiple_forwards_only_m2m(self):
|
def test_multiple_forwards_only_m2m(self):
|
||||||
# Regression for #24505 - Multiple ManyToManyFields to same "to"
|
# Regression for #24505 - Multiple ManyToManyFields to same "to"
|
||||||
|
@ -116,5 +116,5 @@ class M2MRegressionTests(TestCase):
|
||||||
post = Post.objects.create()
|
post = Post.objects.create()
|
||||||
post.primary_lines.add(foo)
|
post.primary_lines.add(foo)
|
||||||
post.secondary_lines.add(bar)
|
post.secondary_lines.add(bar)
|
||||||
self.assertQuerysetEqual(post.primary_lines.all(), ['<Line: foo>'])
|
self.assertSequenceEqual(post.primary_lines.all(), [foo])
|
||||||
self.assertQuerysetEqual(post.secondary_lines.all(), ['<Line: bar>'])
|
self.assertSequenceEqual(post.secondary_lines.all(), [bar])
|
||||||
|
|
|
@ -42,20 +42,12 @@ class M2mThroughTests(TestCase):
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_filter_on_intermediate_model(self):
|
def test_filter_on_intermediate_model(self):
|
||||||
Membership.objects.create(person=self.jim, group=self.rock)
|
m1 = Membership.objects.create(person=self.jim, group=self.rock)
|
||||||
Membership.objects.create(person=self.jane, group=self.rock)
|
m2 = Membership.objects.create(person=self.jane, group=self.rock)
|
||||||
|
|
||||||
queryset = Membership.objects.filter(group=self.rock)
|
queryset = Membership.objects.filter(group=self.rock)
|
||||||
|
|
||||||
expected = [
|
self.assertSequenceEqual(queryset, [m1, m2])
|
||||||
'<Membership: Jim is a member of Rock>',
|
|
||||||
'<Membership: Jane is a member of Rock>',
|
|
||||||
]
|
|
||||||
|
|
||||||
self.assertQuerysetEqual(
|
|
||||||
queryset,
|
|
||||||
expected
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_add_on_m2m_with_intermediate_model(self):
|
def test_add_on_m2m_with_intermediate_model(self):
|
||||||
self.rock.members.add(self.bob, through_defaults={'invite_reason': 'He is good.'})
|
self.rock.members.add(self.bob, through_defaults={'invite_reason': 'He is good.'})
|
||||||
|
@ -372,12 +364,8 @@ class M2mThroughTests(TestCase):
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_custom_related_name_doesnt_conflict_with_fky_related_name(self):
|
def test_custom_related_name_doesnt_conflict_with_fky_related_name(self):
|
||||||
CustomMembership.objects.create(person=self.bob, group=self.rock)
|
c = CustomMembership.objects.create(person=self.bob, group=self.rock)
|
||||||
|
self.assertSequenceEqual(self.bob.custom_person_related_name.all(), [c])
|
||||||
self.assertQuerysetEqual(
|
|
||||||
self.bob.custom_person_related_name.all(),
|
|
||||||
['<CustomMembership: Bob is a member of Rock>']
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_through_fields(self):
|
def test_through_fields(self):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -32,53 +32,31 @@ class M2MThroughTestCase(TestCase):
|
||||||
cls.jane_rock = UserMembership.objects.create(user=cls.jane, group=cls.rock)
|
cls.jane_rock = UserMembership.objects.create(user=cls.jane, group=cls.rock)
|
||||||
|
|
||||||
def test_retrieve_reverse_m2m_items(self):
|
def test_retrieve_reverse_m2m_items(self):
|
||||||
self.assertQuerysetEqual(
|
self.assertCountEqual(self.bob.group_set.all(), [self.rock, self.roll])
|
||||||
self.bob.group_set.all(), [
|
|
||||||
"<Group: Rock>",
|
|
||||||
"<Group: Roll>",
|
|
||||||
],
|
|
||||||
ordered=False
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_retrieve_forward_m2m_items(self):
|
def test_retrieve_forward_m2m_items(self):
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(self.roll.members.all(), [self.bob])
|
||||||
self.roll.members.all(), [
|
|
||||||
"<Person: Bob>",
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_retrieve_reverse_m2m_items_via_custom_id_intermediary(self):
|
def test_retrieve_reverse_m2m_items_via_custom_id_intermediary(self):
|
||||||
self.assertQuerysetEqual(
|
self.assertCountEqual(self.frank.group_set.all(), [self.rock, self.roll])
|
||||||
self.frank.group_set.all(), [
|
|
||||||
"<Group: Rock>",
|
|
||||||
"<Group: Roll>",
|
|
||||||
],
|
|
||||||
ordered=False
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_retrieve_forward_m2m_items_via_custom_id_intermediary(self):
|
def test_retrieve_forward_m2m_items_via_custom_id_intermediary(self):
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(self.roll.user_members.all(), [self.frank])
|
||||||
self.roll.user_members.all(), [
|
|
||||||
"<User: frank>",
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_join_trimming_forwards(self):
|
def test_join_trimming_forwards(self):
|
||||||
"""
|
"""
|
||||||
Too many copies of the intermediate table aren't involved when doing a
|
Too many copies of the intermediate table aren't involved when doing a
|
||||||
join (#8046, #8254).
|
join (#8046, #8254).
|
||||||
"""
|
"""
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
self.rock.members.filter(membership__price=50), [
|
self.rock.members.filter(membership__price=50),
|
||||||
"<Person: Jim>",
|
[self.jim],
|
||||||
]
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_join_trimming_reverse(self):
|
def test_join_trimming_reverse(self):
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
self.bob.group_set.filter(membership__price=50), [
|
self.bob.group_set.filter(membership__price=50),
|
||||||
"<Group: Roll>",
|
[self.roll],
|
||||||
]
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -139,26 +117,18 @@ class ToFieldThroughTests(TestCase):
|
||||||
cls.unused_car2 = Car.objects.create(make="Wartburg")
|
cls.unused_car2 = Car.objects.create(make="Wartburg")
|
||||||
|
|
||||||
def test_to_field(self):
|
def test_to_field(self):
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(self.car.drivers.all(), [self.driver])
|
||||||
self.car.drivers.all(),
|
|
||||||
["<Driver: Ryan Briscoe>"]
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_to_field_reverse(self):
|
def test_to_field_reverse(self):
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(self.driver.car_set.all(), [self.car])
|
||||||
self.driver.car_set.all(),
|
|
||||||
["<Car: Toyota>"]
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_to_field_clear_reverse(self):
|
def test_to_field_clear_reverse(self):
|
||||||
self.driver.car_set.clear()
|
self.driver.car_set.clear()
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(self.driver.car_set.all(), [])
|
||||||
self.driver.car_set.all(), [])
|
|
||||||
|
|
||||||
def test_to_field_clear(self):
|
def test_to_field_clear(self):
|
||||||
self.car.drivers.clear()
|
self.car.drivers.clear()
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(self.car.drivers.all(), [])
|
||||||
self.car.drivers.all(), [])
|
|
||||||
|
|
||||||
# Low level tests for _add_items and _remove_items. We test these methods
|
# Low level tests for _add_items and _remove_items. We test these methods
|
||||||
# because .add/.remove aren't available for m2m fields with through, but
|
# because .add/.remove aren't available for m2m fields with through, but
|
||||||
|
@ -166,15 +136,12 @@ class ToFieldThroughTests(TestCase):
|
||||||
# sure these methods are ready if the ability to use .add or .remove with
|
# sure these methods are ready if the ability to use .add or .remove with
|
||||||
# to_field relations is added some day.
|
# to_field relations is added some day.
|
||||||
def test_add(self):
|
def test_add(self):
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(self.car.drivers.all(), [self.driver])
|
||||||
self.car.drivers.all(),
|
|
||||||
["<Driver: Ryan Briscoe>"]
|
|
||||||
)
|
|
||||||
# Yikes - barney is going to drive...
|
# Yikes - barney is going to drive...
|
||||||
self.car.drivers._add_items('car', 'driver', self.unused_driver)
|
self.car.drivers._add_items('car', 'driver', self.unused_driver)
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
self.car.drivers.all(),
|
self.car.drivers.all(),
|
||||||
["<Driver: Barney Gumble>", "<Driver: Ryan Briscoe>"]
|
[self.unused_driver, self.driver],
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_m2m_relations_unusable_on_null_to_field(self):
|
def test_m2m_relations_unusable_on_null_to_field(self):
|
||||||
|
@ -202,16 +169,9 @@ class ToFieldThroughTests(TestCase):
|
||||||
|
|
||||||
def test_add_reverse(self):
|
def test_add_reverse(self):
|
||||||
car2 = Car.objects.create(make="Honda")
|
car2 = Car.objects.create(make="Honda")
|
||||||
self.assertQuerysetEqual(
|
self.assertCountEqual(self.driver.car_set.all(), [self.car])
|
||||||
self.driver.car_set.all(),
|
|
||||||
["<Car: Toyota>"]
|
|
||||||
)
|
|
||||||
self.driver.car_set._add_items('driver', 'car', car2)
|
self.driver.car_set._add_items('driver', 'car', car2)
|
||||||
self.assertQuerysetEqual(
|
self.assertCountEqual(self.driver.car_set.all(), [self.car, car2])
|
||||||
self.driver.car_set.all(),
|
|
||||||
["<Car: Toyota>", "<Car: Honda>"],
|
|
||||||
ordered=False
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_add_null_reverse(self):
|
def test_add_null_reverse(self):
|
||||||
nullcar = Car.objects.create(make=None)
|
nullcar = Car.objects.create(make=None)
|
||||||
|
@ -229,22 +189,14 @@ class ToFieldThroughTests(TestCase):
|
||||||
nulldriver.car_set._add_items('driver', 'car', self.car)
|
nulldriver.car_set._add_items('driver', 'car', self.car)
|
||||||
|
|
||||||
def test_remove(self):
|
def test_remove(self):
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(self.car.drivers.all(), [self.driver])
|
||||||
self.car.drivers.all(),
|
|
||||||
["<Driver: Ryan Briscoe>"]
|
|
||||||
)
|
|
||||||
self.car.drivers._remove_items('car', 'driver', self.driver)
|
self.car.drivers._remove_items('car', 'driver', self.driver)
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(self.car.drivers.all(), [])
|
||||||
self.car.drivers.all(), [])
|
|
||||||
|
|
||||||
def test_remove_reverse(self):
|
def test_remove_reverse(self):
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(self.driver.car_set.all(), [self.car])
|
||||||
self.driver.car_set.all(),
|
|
||||||
["<Car: Toyota>"]
|
|
||||||
)
|
|
||||||
self.driver.car_set._remove_items('driver', 'car', self.car)
|
self.driver.car_set._remove_items('driver', 'car', self.car)
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(self.driver.car_set.all(), [])
|
||||||
self.driver.car_set.all(), [])
|
|
||||||
|
|
||||||
|
|
||||||
class ThroughLoadDataTestCase(TestCase):
|
class ThroughLoadDataTestCase(TestCase):
|
||||||
|
|
|
@ -11,11 +11,10 @@ class ManyToOneRecursiveTests(TestCase):
|
||||||
cls.c = Category.objects.create(id=None, name='Child category', parent=cls.r)
|
cls.c = Category.objects.create(id=None, name='Child category', parent=cls.r)
|
||||||
|
|
||||||
def test_m2o_recursive(self):
|
def test_m2o_recursive(self):
|
||||||
self.assertQuerysetEqual(self.r.child_set.all(),
|
self.assertSequenceEqual(self.r.child_set.all(), [self.c])
|
||||||
['<Category: Child category>'])
|
|
||||||
self.assertEqual(self.r.child_set.get(name__startswith='Child').id, self.c.id)
|
self.assertEqual(self.r.child_set.get(name__startswith='Child').id, self.c.id)
|
||||||
self.assertIsNone(self.r.parent)
|
self.assertIsNone(self.r.parent)
|
||||||
self.assertQuerysetEqual(self.c.child_set.all(), [])
|
self.assertSequenceEqual(self.c.child_set.all(), [])
|
||||||
self.assertEqual(self.c.parent.id, self.r.id)
|
self.assertEqual(self.c.parent.id, self.r.id)
|
||||||
|
|
||||||
|
|
||||||
|
@ -30,9 +29,7 @@ class MultipleManyToOneRecursiveTests(TestCase):
|
||||||
def test_m2o_recursive2(self):
|
def test_m2o_recursive2(self):
|
||||||
self.assertEqual(self.kid.mother.id, self.mom.id)
|
self.assertEqual(self.kid.mother.id, self.mom.id)
|
||||||
self.assertEqual(self.kid.father.id, self.dad.id)
|
self.assertEqual(self.kid.father.id, self.dad.id)
|
||||||
self.assertQuerysetEqual(self.dad.fathers_child_set.all(),
|
self.assertSequenceEqual(self.dad.fathers_child_set.all(), [self.kid])
|
||||||
['<Person: John Smith Junior>'])
|
self.assertSequenceEqual(self.mom.mothers_child_set.all(), [self.kid])
|
||||||
self.assertQuerysetEqual(self.mom.mothers_child_set.all(),
|
self.assertSequenceEqual(self.kid.mothers_child_set.all(), [])
|
||||||
['<Person: John Smith Junior>'])
|
self.assertSequenceEqual(self.kid.fathers_child_set.all(), [])
|
||||||
self.assertQuerysetEqual(self.kid.mothers_child_set.all(), [])
|
|
||||||
self.assertQuerysetEqual(self.kid.fathers_child_set.all(), [])
|
|
||||||
|
|
|
@ -14,46 +14,44 @@ from .models import (
|
||||||
|
|
||||||
class ManagersRegressionTests(TestCase):
|
class ManagersRegressionTests(TestCase):
|
||||||
def test_managers(self):
|
def test_managers(self):
|
||||||
Child1.objects.create(name='fred', data='a1')
|
a1 = Child1.objects.create(name='fred', data='a1')
|
||||||
Child1.objects.create(name='barney', data='a2')
|
a2 = Child1.objects.create(name='barney', data='a2')
|
||||||
Child2.objects.create(name='fred', data='b1', value=1)
|
b1 = Child2.objects.create(name='fred', data='b1', value=1)
|
||||||
Child2.objects.create(name='barney', data='b2', value=42)
|
b2 = Child2.objects.create(name='barney', data='b2', value=42)
|
||||||
Child3.objects.create(name='fred', data='c1', comment='yes')
|
c1 = Child3.objects.create(name='fred', data='c1', comment='yes')
|
||||||
Child3.objects.create(name='barney', data='c2', comment='no')
|
c2 = Child3.objects.create(name='barney', data='c2', comment='no')
|
||||||
Child4.objects.create(name='fred', data='d1')
|
d1 = Child4.objects.create(name='fred', data='d1')
|
||||||
Child4.objects.create(name='barney', data='d2')
|
d2 = Child4.objects.create(name='barney', data='d2')
|
||||||
Child5.objects.create(name='fred', comment='yes')
|
fred1 = Child5.objects.create(name='fred', comment='yes')
|
||||||
Child5.objects.create(name='barney', comment='no')
|
Child5.objects.create(name='barney', comment='no')
|
||||||
Child6.objects.create(name='fred', data='f1', value=42)
|
f1 = Child6.objects.create(name='fred', data='f1', value=42)
|
||||||
Child6.objects.create(name='barney', data='f2', value=42)
|
f2 = Child6.objects.create(name='barney', data='f2', value=42)
|
||||||
Child7.objects.create(name='fred')
|
fred2 = Child7.objects.create(name='fred')
|
||||||
Child7.objects.create(name='barney')
|
barney = Child7.objects.create(name='barney')
|
||||||
|
|
||||||
self.assertQuerysetEqual(Child1.manager1.all(), ["<Child1: a1>"])
|
self.assertSequenceEqual(Child1.manager1.all(), [a1])
|
||||||
self.assertQuerysetEqual(Child1.manager2.all(), ["<Child1: a2>"])
|
self.assertSequenceEqual(Child1.manager2.all(), [a2])
|
||||||
self.assertQuerysetEqual(Child1._default_manager.all(), ["<Child1: a1>"])
|
self.assertSequenceEqual(Child1._default_manager.all(), [a1])
|
||||||
|
|
||||||
self.assertQuerysetEqual(Child2._default_manager.all(), ["<Child2: b1>"])
|
self.assertSequenceEqual(Child2._default_manager.all(), [b1])
|
||||||
self.assertQuerysetEqual(Child2.restricted.all(), ["<Child2: b2>"])
|
self.assertSequenceEqual(Child2.restricted.all(), [b2])
|
||||||
|
|
||||||
self.assertQuerysetEqual(Child3._default_manager.all(), ["<Child3: c1>"])
|
self.assertSequenceEqual(Child3._default_manager.all(), [c1])
|
||||||
self.assertQuerysetEqual(Child3.manager1.all(), ["<Child3: c1>"])
|
self.assertSequenceEqual(Child3.manager1.all(), [c1])
|
||||||
self.assertQuerysetEqual(Child3.manager2.all(), ["<Child3: c2>"])
|
self.assertSequenceEqual(Child3.manager2.all(), [c2])
|
||||||
|
|
||||||
# Since Child6 inherits from Child4, the corresponding rows from f1 and
|
# Since Child6 inherits from Child4, the corresponding rows from f1 and
|
||||||
# f2 also appear here. This is the expected result.
|
# f2 also appear here. This is the expected result.
|
||||||
self.assertQuerysetEqual(Child4._default_manager.order_by('data'), [
|
self.assertSequenceEqual(
|
||||||
"<Child4: d1>",
|
Child4._default_manager.order_by('data'),
|
||||||
"<Child4: d2>",
|
[d1, d2, f1.child4_ptr, f2.child4_ptr],
|
||||||
"<Child4: f1>",
|
)
|
||||||
"<Child4: f2>",
|
self.assertCountEqual(Child4.manager1.all(), [d1, f1.child4_ptr])
|
||||||
])
|
self.assertCountEqual(Child5._default_manager.all(), [fred1])
|
||||||
self.assertQuerysetEqual(Child4.manager1.all(), ["<Child4: d1>", "<Child4: f1>"], ordered=False)
|
self.assertCountEqual(Child6._default_manager.all(), [f1, f2])
|
||||||
self.assertQuerysetEqual(Child5._default_manager.all(), ["<Child5: fred>"])
|
self.assertSequenceEqual(
|
||||||
self.assertQuerysetEqual(Child6._default_manager.all(), ["<Child6: f1>", "<Child6: f2>"], ordered=False)
|
|
||||||
self.assertQuerysetEqual(
|
|
||||||
Child7._default_manager.order_by('name'),
|
Child7._default_manager.order_by('name'),
|
||||||
["<Child7: barney>", "<Child7: fred>"]
|
[barney, fred2],
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_abstract_manager(self):
|
def test_abstract_manager(self):
|
||||||
|
|
|
@ -44,7 +44,7 @@ class ManyToManyTests(TestCase):
|
||||||
a5.save()
|
a5.save()
|
||||||
# Associate the Article with a Publication.
|
# Associate the Article with a Publication.
|
||||||
a5.publications.add(self.p1)
|
a5.publications.add(self.p1)
|
||||||
self.assertQuerysetEqual(a5.publications.all(), ['<Publication: The Python Journal>'])
|
self.assertSequenceEqual(a5.publications.all(), [self.p1])
|
||||||
# Create another Article, and set it to appear in both Publications.
|
# Create another Article, and set it to appear in both Publications.
|
||||||
a6 = Article(headline='ESA uses Python')
|
a6 = Article(headline='ESA uses Python')
|
||||||
a6.save()
|
a6.save()
|
||||||
|
@ -52,13 +52,9 @@ class ManyToManyTests(TestCase):
|
||||||
a6.publications.add(self.p3)
|
a6.publications.add(self.p3)
|
||||||
# Adding a second time is OK
|
# Adding a second time is OK
|
||||||
a6.publications.add(self.p3)
|
a6.publications.add(self.p3)
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
a6.publications.all(),
|
a6.publications.all(),
|
||||||
[
|
[self.p2, self.p3, self.p1],
|
||||||
'<Publication: Science News>',
|
|
||||||
'<Publication: Science Weekly>',
|
|
||||||
'<Publication: The Python Journal>',
|
|
||||||
]
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Adding an object of the wrong type raises TypeError
|
# Adding an object of the wrong type raises TypeError
|
||||||
|
@ -68,42 +64,31 @@ class ManyToManyTests(TestCase):
|
||||||
a6.publications.add(a5)
|
a6.publications.add(a5)
|
||||||
|
|
||||||
# Add a Publication directly via publications.add by using keyword arguments.
|
# Add a Publication directly via publications.add by using keyword arguments.
|
||||||
a6.publications.create(title='Highlights for Adults')
|
p5 = a6.publications.create(title='Highlights for Adults')
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
a6.publications.all(),
|
a6.publications.all(),
|
||||||
[
|
[p5, self.p2, self.p3, self.p1],
|
||||||
'<Publication: Highlights for Adults>',
|
|
||||||
'<Publication: Science News>',
|
|
||||||
'<Publication: Science Weekly>',
|
|
||||||
'<Publication: The Python Journal>',
|
|
||||||
]
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_add_remove_set_by_pk(self):
|
def test_add_remove_set_by_pk(self):
|
||||||
a5 = Article.objects.create(headline='Django lets you create Web apps easily')
|
a5 = Article.objects.create(headline='Django lets you create Web apps easily')
|
||||||
a5.publications.add(self.p1.pk)
|
a5.publications.add(self.p1.pk)
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(a5.publications.all(), [self.p1])
|
||||||
a5.publications.all(),
|
|
||||||
['<Publication: The Python Journal>'],
|
|
||||||
)
|
|
||||||
a5.publications.set([self.p2.pk])
|
a5.publications.set([self.p2.pk])
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(a5.publications.all(), [self.p2])
|
||||||
a5.publications.all(),
|
|
||||||
['<Publication: Science News>'],
|
|
||||||
)
|
|
||||||
a5.publications.remove(self.p2.pk)
|
a5.publications.remove(self.p2.pk)
|
||||||
self.assertQuerysetEqual(a5.publications.all(), [])
|
self.assertSequenceEqual(a5.publications.all(), [])
|
||||||
|
|
||||||
def test_add_remove_set_by_to_field(self):
|
def test_add_remove_set_by_to_field(self):
|
||||||
user_1 = User.objects.create(username='Jean')
|
user_1 = User.objects.create(username='Jean')
|
||||||
user_2 = User.objects.create(username='Joe')
|
user_2 = User.objects.create(username='Joe')
|
||||||
a5 = Article.objects.create(headline='Django lets you create Web apps easily')
|
a5 = Article.objects.create(headline='Django lets you create Web apps easily')
|
||||||
a5.authors.add(user_1.username)
|
a5.authors.add(user_1.username)
|
||||||
self.assertQuerysetEqual(a5.authors.all(), ['<User: Jean>'])
|
self.assertSequenceEqual(a5.authors.all(), [user_1])
|
||||||
a5.authors.set([user_2.username])
|
a5.authors.set([user_2.username])
|
||||||
self.assertQuerysetEqual(a5.authors.all(), ['<User: Joe>'])
|
self.assertSequenceEqual(a5.authors.all(), [user_2])
|
||||||
a5.authors.remove(user_2.username)
|
a5.authors.remove(user_2.username)
|
||||||
self.assertQuerysetEqual(a5.authors.all(), [])
|
self.assertSequenceEqual(a5.authors.all(), [])
|
||||||
|
|
||||||
def test_add_remove_invalid_type(self):
|
def test_add_remove_invalid_type(self):
|
||||||
msg = "Field 'id' expected a number but got 'invalid'."
|
msg = "Field 'id' expected a number but got 'invalid'."
|
||||||
|
@ -116,37 +101,22 @@ class ManyToManyTests(TestCase):
|
||||||
a5 = Article(headline='NASA finds intelligent life on Mars')
|
a5 = Article(headline='NASA finds intelligent life on Mars')
|
||||||
a5.save()
|
a5.save()
|
||||||
self.p2.article_set.add(a5)
|
self.p2.article_set.add(a5)
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
self.p2.article_set.all(),
|
self.p2.article_set.all(),
|
||||||
[
|
[self.a3, a5, self.a2, self.a4],
|
||||||
'<Article: NASA finds intelligent life on Earth>',
|
|
||||||
'<Article: NASA finds intelligent life on Mars>',
|
|
||||||
'<Article: NASA uses Python>',
|
|
||||||
'<Article: Oxygen-free diet works wonders>',
|
|
||||||
]
|
|
||||||
)
|
)
|
||||||
self.assertQuerysetEqual(a5.publications.all(), ['<Publication: Science News>'])
|
self.assertSequenceEqual(a5.publications.all(), [self.p2])
|
||||||
|
|
||||||
# Adding via the other end using keywords
|
# Adding via the other end using keywords
|
||||||
self.p2.article_set.create(headline='Carbon-free diet works wonders')
|
a6 = self.p2.article_set.create(headline='Carbon-free diet works wonders')
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
self.p2.article_set.all(),
|
self.p2.article_set.all(),
|
||||||
[
|
[a6, self.a3, a5, self.a2, self.a4],
|
||||||
'<Article: Carbon-free diet works wonders>',
|
)
|
||||||
'<Article: NASA finds intelligent life on Earth>',
|
|
||||||
'<Article: NASA finds intelligent life on Mars>',
|
|
||||||
'<Article: NASA uses Python>',
|
|
||||||
'<Article: Oxygen-free diet works wonders>',
|
|
||||||
])
|
|
||||||
a6 = self.p2.article_set.all()[3]
|
a6 = self.p2.article_set.all()[3]
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
a6.publications.all(),
|
a6.publications.all(),
|
||||||
[
|
[self.p4, self.p2, self.p3, self.p1],
|
||||||
'<Publication: Highlights for Children>',
|
|
||||||
'<Publication: Science News>',
|
|
||||||
'<Publication: Science Weekly>',
|
|
||||||
'<Publication: The Python Journal>',
|
|
||||||
]
|
|
||||||
)
|
)
|
||||||
|
|
||||||
@skipUnlessDBFeature('supports_ignore_conflicts')
|
@skipUnlessDBFeature('supports_ignore_conflicts')
|
||||||
|
@ -182,293 +152,195 @@ class ManyToManyTests(TestCase):
|
||||||
|
|
||||||
def test_related_sets(self):
|
def test_related_sets(self):
|
||||||
# Article objects have access to their related Publication objects.
|
# Article objects have access to their related Publication objects.
|
||||||
self.assertQuerysetEqual(self.a1.publications.all(), ['<Publication: The Python Journal>'])
|
self.assertSequenceEqual(self.a1.publications.all(), [self.p1])
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
self.a2.publications.all(),
|
self.a2.publications.all(),
|
||||||
[
|
[self.p4, self.p2, self.p3, self.p1],
|
||||||
'<Publication: Highlights for Children>',
|
|
||||||
'<Publication: Science News>',
|
|
||||||
'<Publication: Science Weekly>',
|
|
||||||
'<Publication: The Python Journal>',
|
|
||||||
]
|
|
||||||
)
|
)
|
||||||
# Publication objects have access to their related Article objects.
|
# Publication objects have access to their related Article objects.
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
self.p2.article_set.all(),
|
self.p2.article_set.all(),
|
||||||
[
|
[self.a3, self.a2, self.a4],
|
||||||
'<Article: NASA finds intelligent life on Earth>',
|
|
||||||
'<Article: NASA uses Python>',
|
|
||||||
'<Article: Oxygen-free diet works wonders>',
|
|
||||||
]
|
|
||||||
)
|
)
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
self.p1.article_set.all(),
|
self.p1.article_set.all(),
|
||||||
[
|
[self.a1, self.a2],
|
||||||
'<Article: Django lets you build Web apps easily>',
|
|
||||||
'<Article: NASA uses Python>',
|
|
||||||
]
|
|
||||||
)
|
)
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
Publication.objects.get(id=self.p4.id).article_set.all(),
|
Publication.objects.get(id=self.p4.id).article_set.all(),
|
||||||
['<Article: NASA uses Python>']
|
[self.a2],
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_selects(self):
|
def test_selects(self):
|
||||||
# We can perform kwarg queries across m2m relationships
|
# We can perform kwarg queries across m2m relationships
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
Article.objects.filter(publications__id__exact=self.p1.id),
|
Article.objects.filter(publications__id__exact=self.p1.id),
|
||||||
[
|
[self.a1, self.a2],
|
||||||
'<Article: Django lets you build Web apps easily>',
|
)
|
||||||
'<Article: NASA uses Python>',
|
self.assertSequenceEqual(
|
||||||
])
|
|
||||||
self.assertQuerysetEqual(
|
|
||||||
Article.objects.filter(publications__pk=self.p1.id),
|
Article.objects.filter(publications__pk=self.p1.id),
|
||||||
[
|
[self.a1, self.a2],
|
||||||
'<Article: Django lets you build Web apps easily>',
|
|
||||||
'<Article: NASA uses Python>',
|
|
||||||
]
|
|
||||||
)
|
)
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
Article.objects.filter(publications=self.p1.id),
|
Article.objects.filter(publications=self.p1.id),
|
||||||
[
|
[self.a1, self.a2],
|
||||||
'<Article: Django lets you build Web apps easily>',
|
|
||||||
'<Article: NASA uses Python>',
|
|
||||||
]
|
|
||||||
)
|
)
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
Article.objects.filter(publications=self.p1),
|
Article.objects.filter(publications=self.p1),
|
||||||
[
|
[self.a1, self.a2],
|
||||||
'<Article: Django lets you build Web apps easily>',
|
|
||||||
'<Article: NASA uses Python>',
|
|
||||||
]
|
|
||||||
)
|
)
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
Article.objects.filter(publications__title__startswith="Science"),
|
Article.objects.filter(publications__title__startswith="Science"),
|
||||||
[
|
[self.a3, self.a2, self.a2, self.a4]
|
||||||
'<Article: NASA finds intelligent life on Earth>',
|
|
||||||
'<Article: NASA uses Python>',
|
|
||||||
'<Article: NASA uses Python>',
|
|
||||||
'<Article: Oxygen-free diet works wonders>',
|
|
||||||
]
|
|
||||||
)
|
)
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
Article.objects.filter(publications__title__startswith="Science").distinct(),
|
Article.objects.filter(publications__title__startswith="Science").distinct(),
|
||||||
[
|
[self.a3, self.a2, self.a4],
|
||||||
'<Article: NASA finds intelligent life on Earth>',
|
|
||||||
'<Article: NASA uses Python>',
|
|
||||||
'<Article: Oxygen-free diet works wonders>',
|
|
||||||
]
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# The count() function respects distinct() as well.
|
# The count() function respects distinct() as well.
|
||||||
self.assertEqual(Article.objects.filter(publications__title__startswith="Science").count(), 4)
|
self.assertEqual(Article.objects.filter(publications__title__startswith="Science").count(), 4)
|
||||||
self.assertEqual(Article.objects.filter(publications__title__startswith="Science").distinct().count(), 3)
|
self.assertEqual(Article.objects.filter(publications__title__startswith="Science").distinct().count(), 3)
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
Article.objects.filter(publications__in=[self.p1.id, self.p2.id]).distinct(),
|
Article.objects.filter(publications__in=[self.p1.id, self.p2.id]).distinct(),
|
||||||
[
|
[self.a1, self.a3, self.a2, self.a4],
|
||||||
'<Article: Django lets you build Web apps easily>',
|
|
||||||
'<Article: NASA finds intelligent life on Earth>',
|
|
||||||
'<Article: NASA uses Python>',
|
|
||||||
'<Article: Oxygen-free diet works wonders>',
|
|
||||||
])
|
|
||||||
self.assertQuerysetEqual(
|
|
||||||
Article.objects.filter(publications__in=[self.p1.id, self.p2]).distinct(),
|
|
||||||
[
|
|
||||||
'<Article: Django lets you build Web apps easily>',
|
|
||||||
'<Article: NASA finds intelligent life on Earth>',
|
|
||||||
'<Article: NASA uses Python>',
|
|
||||||
'<Article: Oxygen-free diet works wonders>',
|
|
||||||
]
|
|
||||||
)
|
)
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
|
Article.objects.filter(publications__in=[self.p1.id, self.p2]).distinct(),
|
||||||
|
[self.a1, self.a3, self.a2, self.a4],
|
||||||
|
)
|
||||||
|
self.assertSequenceEqual(
|
||||||
Article.objects.filter(publications__in=[self.p1, self.p2]).distinct(),
|
Article.objects.filter(publications__in=[self.p1, self.p2]).distinct(),
|
||||||
[
|
[self.a1, self.a3, self.a2, self.a4],
|
||||||
'<Article: Django lets you build Web apps easily>',
|
|
||||||
'<Article: NASA finds intelligent life on Earth>',
|
|
||||||
'<Article: NASA uses Python>',
|
|
||||||
'<Article: Oxygen-free diet works wonders>',
|
|
||||||
]
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Excluding a related item works as you would expect, too (although the SQL
|
# Excluding a related item works as you would expect, too (although the SQL
|
||||||
# involved is a little complex).
|
# involved is a little complex).
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
Article.objects.exclude(publications=self.p2),
|
Article.objects.exclude(publications=self.p2),
|
||||||
['<Article: Django lets you build Web apps easily>']
|
[self.a1],
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_reverse_selects(self):
|
def test_reverse_selects(self):
|
||||||
# Reverse m2m queries are supported (i.e., starting at the table that
|
# Reverse m2m queries are supported (i.e., starting at the table that
|
||||||
# doesn't have a ManyToManyField).
|
# doesn't have a ManyToManyField).
|
||||||
python_journal = ['<Publication: The Python Journal>']
|
python_journal = [self.p1]
|
||||||
self.assertQuerysetEqual(Publication.objects.filter(id__exact=self.p1.id), python_journal)
|
self.assertSequenceEqual(Publication.objects.filter(id__exact=self.p1.id), python_journal)
|
||||||
self.assertQuerysetEqual(Publication.objects.filter(pk=self.p1.id), python_journal)
|
self.assertSequenceEqual(Publication.objects.filter(pk=self.p1.id), python_journal)
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
Publication.objects.filter(article__headline__startswith="NASA"),
|
Publication.objects.filter(article__headline__startswith="NASA"),
|
||||||
[
|
[self.p4, self.p2, self.p2, self.p3, self.p1],
|
||||||
'<Publication: Highlights for Children>',
|
)
|
||||||
'<Publication: Science News>',
|
|
||||||
'<Publication: Science News>',
|
|
||||||
'<Publication: Science Weekly>',
|
|
||||||
'<Publication: The Python Journal>',
|
|
||||||
])
|
|
||||||
|
|
||||||
self.assertQuerysetEqual(Publication.objects.filter(article__id__exact=self.a1.id), python_journal)
|
self.assertSequenceEqual(Publication.objects.filter(article__id__exact=self.a1.id), python_journal)
|
||||||
self.assertQuerysetEqual(Publication.objects.filter(article__pk=self.a1.id), python_journal)
|
self.assertSequenceEqual(Publication.objects.filter(article__pk=self.a1.id), python_journal)
|
||||||
self.assertQuerysetEqual(Publication.objects.filter(article=self.a1.id), python_journal)
|
self.assertSequenceEqual(Publication.objects.filter(article=self.a1.id), python_journal)
|
||||||
self.assertQuerysetEqual(Publication.objects.filter(article=self.a1), python_journal)
|
self.assertSequenceEqual(Publication.objects.filter(article=self.a1), python_journal)
|
||||||
|
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
Publication.objects.filter(article__in=[self.a1.id, self.a2.id]).distinct(),
|
Publication.objects.filter(article__in=[self.a1.id, self.a2.id]).distinct(),
|
||||||
[
|
[self.p4, self.p2, self.p3, self.p1],
|
||||||
'<Publication: Highlights for Children>',
|
)
|
||||||
'<Publication: Science News>',
|
self.assertSequenceEqual(
|
||||||
'<Publication: Science Weekly>',
|
|
||||||
'<Publication: The Python Journal>',
|
|
||||||
])
|
|
||||||
self.assertQuerysetEqual(
|
|
||||||
Publication.objects.filter(article__in=[self.a1.id, self.a2]).distinct(),
|
Publication.objects.filter(article__in=[self.a1.id, self.a2]).distinct(),
|
||||||
[
|
[self.p4, self.p2, self.p3, self.p1],
|
||||||
'<Publication: Highlights for Children>',
|
)
|
||||||
'<Publication: Science News>',
|
self.assertSequenceEqual(
|
||||||
'<Publication: Science Weekly>',
|
|
||||||
'<Publication: The Python Journal>',
|
|
||||||
])
|
|
||||||
self.assertQuerysetEqual(
|
|
||||||
Publication.objects.filter(article__in=[self.a1, self.a2]).distinct(),
|
Publication.objects.filter(article__in=[self.a1, self.a2]).distinct(),
|
||||||
[
|
[self.p4, self.p2, self.p3, self.p1],
|
||||||
'<Publication: Highlights for Children>',
|
)
|
||||||
'<Publication: Science News>',
|
|
||||||
'<Publication: Science Weekly>',
|
|
||||||
'<Publication: The Python Journal>',
|
|
||||||
])
|
|
||||||
|
|
||||||
def test_delete(self):
|
def test_delete(self):
|
||||||
# If we delete a Publication, its Articles won't be able to access it.
|
# If we delete a Publication, its Articles won't be able to access it.
|
||||||
self.p1.delete()
|
self.p1.delete()
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
Publication.objects.all(),
|
Publication.objects.all(),
|
||||||
[
|
[self.p4, self.p2, self.p3],
|
||||||
'<Publication: Highlights for Children>',
|
|
||||||
'<Publication: Science News>',
|
|
||||||
'<Publication: Science Weekly>',
|
|
||||||
]
|
|
||||||
)
|
)
|
||||||
self.assertQuerysetEqual(self.a1.publications.all(), [])
|
self.assertSequenceEqual(self.a1.publications.all(), [])
|
||||||
# If we delete an Article, its Publications won't be able to access it.
|
# If we delete an Article, its Publications won't be able to access it.
|
||||||
self.a2.delete()
|
self.a2.delete()
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
Article.objects.all(),
|
Article.objects.all(),
|
||||||
[
|
[self.a1, self.a3, self.a4],
|
||||||
'<Article: Django lets you build Web apps easily>',
|
|
||||||
'<Article: NASA finds intelligent life on Earth>',
|
|
||||||
'<Article: Oxygen-free diet works wonders>',
|
|
||||||
]
|
|
||||||
)
|
)
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
self.p2.article_set.all(),
|
self.p2.article_set.all(),
|
||||||
[
|
[self.a3, self.a4],
|
||||||
'<Article: NASA finds intelligent life on Earth>',
|
|
||||||
'<Article: Oxygen-free diet works wonders>',
|
|
||||||
]
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_bulk_delete(self):
|
def test_bulk_delete(self):
|
||||||
# Bulk delete some Publications - references to deleted publications should go
|
# Bulk delete some Publications - references to deleted publications should go
|
||||||
Publication.objects.filter(title__startswith='Science').delete()
|
Publication.objects.filter(title__startswith='Science').delete()
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
Publication.objects.all(),
|
Publication.objects.all(),
|
||||||
[
|
[self.p4, self.p1],
|
||||||
'<Publication: Highlights for Children>',
|
|
||||||
'<Publication: The Python Journal>',
|
|
||||||
]
|
|
||||||
)
|
)
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
Article.objects.all(),
|
Article.objects.all(),
|
||||||
[
|
[self.a1, self.a3, self.a2, self.a4],
|
||||||
'<Article: Django lets you build Web apps easily>',
|
|
||||||
'<Article: NASA finds intelligent life on Earth>',
|
|
||||||
'<Article: NASA uses Python>',
|
|
||||||
'<Article: Oxygen-free diet works wonders>',
|
|
||||||
]
|
|
||||||
)
|
)
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
self.a2.publications.all(),
|
self.a2.publications.all(),
|
||||||
[
|
[self.p4, self.p1],
|
||||||
'<Publication: Highlights for Children>',
|
|
||||||
'<Publication: The Python Journal>',
|
|
||||||
]
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Bulk delete some articles - references to deleted objects should go
|
# Bulk delete some articles - references to deleted objects should go
|
||||||
q = Article.objects.filter(headline__startswith='Django')
|
q = Article.objects.filter(headline__startswith='Django')
|
||||||
self.assertQuerysetEqual(q, ['<Article: Django lets you build Web apps easily>'])
|
self.assertSequenceEqual(q, [self.a1])
|
||||||
q.delete()
|
q.delete()
|
||||||
# After the delete, the QuerySet cache needs to be cleared,
|
# After the delete, the QuerySet cache needs to be cleared,
|
||||||
# and the referenced objects should be gone
|
# and the referenced objects should be gone
|
||||||
self.assertQuerysetEqual(q, [])
|
self.assertSequenceEqual(q, [])
|
||||||
self.assertQuerysetEqual(self.p1.article_set.all(), ['<Article: NASA uses Python>'])
|
self.assertSequenceEqual(self.p1.article_set.all(), [self.a2])
|
||||||
|
|
||||||
def test_remove(self):
|
def test_remove(self):
|
||||||
# Removing publication from an article:
|
# Removing publication from an article:
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
self.p2.article_set.all(),
|
self.p2.article_set.all(),
|
||||||
[
|
[self.a3, self.a2, self.a4],
|
||||||
'<Article: NASA finds intelligent life on Earth>',
|
|
||||||
'<Article: NASA uses Python>',
|
|
||||||
'<Article: Oxygen-free diet works wonders>',
|
|
||||||
]
|
|
||||||
)
|
)
|
||||||
self.a4.publications.remove(self.p2)
|
self.a4.publications.remove(self.p2)
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
self.p2.article_set.all(),
|
self.p2.article_set.all(),
|
||||||
[
|
[self.a3, self.a2],
|
||||||
'<Article: NASA finds intelligent life on Earth>',
|
|
||||||
'<Article: NASA uses Python>',
|
|
||||||
]
|
|
||||||
)
|
)
|
||||||
self.assertQuerysetEqual(self.a4.publications.all(), [])
|
self.assertSequenceEqual(self.a4.publications.all(), [])
|
||||||
# And from the other end
|
# And from the other end
|
||||||
self.p2.article_set.remove(self.a3)
|
self.p2.article_set.remove(self.a3)
|
||||||
self.assertQuerysetEqual(self.p2.article_set.all(), ['<Article: NASA uses Python>'])
|
self.assertSequenceEqual(self.p2.article_set.all(), [self.a2])
|
||||||
self.assertQuerysetEqual(self.a3.publications.all(), [])
|
self.assertSequenceEqual(self.a3.publications.all(), [])
|
||||||
|
|
||||||
def test_set(self):
|
def test_set(self):
|
||||||
self.p2.article_set.set([self.a4, self.a3])
|
self.p2.article_set.set([self.a4, self.a3])
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
self.p2.article_set.all(),
|
self.p2.article_set.all(),
|
||||||
[
|
[self.a3, self.a4],
|
||||||
'<Article: NASA finds intelligent life on Earth>',
|
|
||||||
'<Article: Oxygen-free diet works wonders>',
|
|
||||||
]
|
|
||||||
)
|
)
|
||||||
self.assertQuerysetEqual(self.a4.publications.all(), ['<Publication: Science News>'])
|
self.assertSequenceEqual(self.a4.publications.all(), [self.p2])
|
||||||
self.a4.publications.set([self.p3.id])
|
self.a4.publications.set([self.p3.id])
|
||||||
self.assertQuerysetEqual(self.p2.article_set.all(), ['<Article: NASA finds intelligent life on Earth>'])
|
self.assertSequenceEqual(self.p2.article_set.all(), [self.a3])
|
||||||
self.assertQuerysetEqual(self.a4.publications.all(), ['<Publication: Science Weekly>'])
|
self.assertSequenceEqual(self.a4.publications.all(), [self.p3])
|
||||||
|
|
||||||
self.p2.article_set.set([])
|
self.p2.article_set.set([])
|
||||||
self.assertQuerysetEqual(self.p2.article_set.all(), [])
|
self.assertSequenceEqual(self.p2.article_set.all(), [])
|
||||||
self.a4.publications.set([])
|
self.a4.publications.set([])
|
||||||
self.assertQuerysetEqual(self.a4.publications.all(), [])
|
self.assertSequenceEqual(self.a4.publications.all(), [])
|
||||||
|
|
||||||
self.p2.article_set.set([self.a4, self.a3], clear=True)
|
self.p2.article_set.set([self.a4, self.a3], clear=True)
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
self.p2.article_set.all(),
|
self.p2.article_set.all(),
|
||||||
[
|
[self.a3, self.a4],
|
||||||
'<Article: NASA finds intelligent life on Earth>',
|
|
||||||
'<Article: Oxygen-free diet works wonders>',
|
|
||||||
]
|
|
||||||
)
|
)
|
||||||
self.assertQuerysetEqual(self.a4.publications.all(), ['<Publication: Science News>'])
|
self.assertSequenceEqual(self.a4.publications.all(), [self.p2])
|
||||||
self.a4.publications.set([self.p3.id], clear=True)
|
self.a4.publications.set([self.p3.id], clear=True)
|
||||||
self.assertQuerysetEqual(self.p2.article_set.all(), ['<Article: NASA finds intelligent life on Earth>'])
|
self.assertSequenceEqual(self.p2.article_set.all(), [self.a3])
|
||||||
self.assertQuerysetEqual(self.a4.publications.all(), ['<Publication: Science Weekly>'])
|
self.assertSequenceEqual(self.a4.publications.all(), [self.p3])
|
||||||
|
|
||||||
self.p2.article_set.set([], clear=True)
|
self.p2.article_set.set([], clear=True)
|
||||||
self.assertQuerysetEqual(self.p2.article_set.all(), [])
|
self.assertSequenceEqual(self.p2.article_set.all(), [])
|
||||||
self.a4.publications.set([], clear=True)
|
self.a4.publications.set([], clear=True)
|
||||||
self.assertQuerysetEqual(self.a4.publications.all(), [])
|
self.assertSequenceEqual(self.a4.publications.all(), [])
|
||||||
|
|
||||||
def test_set_existing_different_type(self):
|
def test_set_existing_different_type(self):
|
||||||
# Existing many-to-many relations remain the same for values provided
|
# Existing many-to-many relations remain the same for values provided
|
||||||
|
@ -502,37 +374,32 @@ class ManyToManyTests(TestCase):
|
||||||
def test_assign(self):
|
def test_assign(self):
|
||||||
# Relation sets can be assigned using set().
|
# Relation sets can be assigned using set().
|
||||||
self.p2.article_set.set([self.a4, self.a3])
|
self.p2.article_set.set([self.a4, self.a3])
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
self.p2.article_set.all(), [
|
self.p2.article_set.all(),
|
||||||
'<Article: NASA finds intelligent life on Earth>',
|
[self.a3, self.a4],
|
||||||
'<Article: Oxygen-free diet works wonders>',
|
|
||||||
]
|
|
||||||
)
|
)
|
||||||
self.assertQuerysetEqual(self.a4.publications.all(), ['<Publication: Science News>'])
|
self.assertSequenceEqual(self.a4.publications.all(), [self.p2])
|
||||||
self.a4.publications.set([self.p3.id])
|
self.a4.publications.set([self.p3.id])
|
||||||
self.assertQuerysetEqual(self.p2.article_set.all(), ['<Article: NASA finds intelligent life on Earth>'])
|
self.assertSequenceEqual(self.p2.article_set.all(), [self.a3])
|
||||||
self.assertQuerysetEqual(self.a4.publications.all(), ['<Publication: Science Weekly>'])
|
self.assertSequenceEqual(self.a4.publications.all(), [self.p3])
|
||||||
|
|
||||||
# An alternate to calling clear() is to set an empty set.
|
# An alternate to calling clear() is to set an empty set.
|
||||||
self.p2.article_set.set([])
|
self.p2.article_set.set([])
|
||||||
self.assertQuerysetEqual(self.p2.article_set.all(), [])
|
self.assertSequenceEqual(self.p2.article_set.all(), [])
|
||||||
self.a4.publications.set([])
|
self.a4.publications.set([])
|
||||||
self.assertQuerysetEqual(self.a4.publications.all(), [])
|
self.assertSequenceEqual(self.a4.publications.all(), [])
|
||||||
|
|
||||||
def test_assign_ids(self):
|
def test_assign_ids(self):
|
||||||
# Relation sets can also be set using primary key values
|
# Relation sets can also be set using primary key values
|
||||||
self.p2.article_set.set([self.a4.id, self.a3.id])
|
self.p2.article_set.set([self.a4.id, self.a3.id])
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
self.p2.article_set.all(),
|
self.p2.article_set.all(),
|
||||||
[
|
[self.a3, self.a4],
|
||||||
'<Article: NASA finds intelligent life on Earth>',
|
|
||||||
'<Article: Oxygen-free diet works wonders>',
|
|
||||||
]
|
|
||||||
)
|
)
|
||||||
self.assertQuerysetEqual(self.a4.publications.all(), ['<Publication: Science News>'])
|
self.assertSequenceEqual(self.a4.publications.all(), [self.p2])
|
||||||
self.a4.publications.set([self.p3.id])
|
self.a4.publications.set([self.p3.id])
|
||||||
self.assertQuerysetEqual(self.p2.article_set.all(), ['<Article: NASA finds intelligent life on Earth>'])
|
self.assertSequenceEqual(self.p2.article_set.all(), [self.a3])
|
||||||
self.assertQuerysetEqual(self.a4.publications.all(), ['<Publication: Science Weekly>'])
|
self.assertSequenceEqual(self.a4.publications.all(), [self.p3])
|
||||||
|
|
||||||
def test_forward_assign_with_queryset(self):
|
def test_forward_assign_with_queryset(self):
|
||||||
# Querysets used in m2m assignments are pre-evaluated so their value
|
# Querysets used in m2m assignments are pre-evaluated so their value
|
||||||
|
@ -561,34 +428,31 @@ class ManyToManyTests(TestCase):
|
||||||
def test_clear(self):
|
def test_clear(self):
|
||||||
# Relation sets can be cleared:
|
# Relation sets can be cleared:
|
||||||
self.p2.article_set.clear()
|
self.p2.article_set.clear()
|
||||||
self.assertQuerysetEqual(self.p2.article_set.all(), [])
|
self.assertSequenceEqual(self.p2.article_set.all(), [])
|
||||||
self.assertQuerysetEqual(self.a4.publications.all(), [])
|
self.assertSequenceEqual(self.a4.publications.all(), [])
|
||||||
|
|
||||||
# And you can clear from the other end
|
# And you can clear from the other end
|
||||||
self.p2.article_set.add(self.a3, self.a4)
|
self.p2.article_set.add(self.a3, self.a4)
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
self.p2.article_set.all(),
|
self.p2.article_set.all(),
|
||||||
[
|
[self.a3, self.a4],
|
||||||
'<Article: NASA finds intelligent life on Earth>',
|
|
||||||
'<Article: Oxygen-free diet works wonders>',
|
|
||||||
]
|
|
||||||
)
|
)
|
||||||
self.assertQuerysetEqual(self.a4.publications.all(), ['<Publication: Science News>'])
|
self.assertSequenceEqual(self.a4.publications.all(), [self.p2])
|
||||||
self.a4.publications.clear()
|
self.a4.publications.clear()
|
||||||
self.assertQuerysetEqual(self.a4.publications.all(), [])
|
self.assertSequenceEqual(self.a4.publications.all(), [])
|
||||||
self.assertQuerysetEqual(self.p2.article_set.all(), ['<Article: NASA finds intelligent life on Earth>'])
|
self.assertSequenceEqual(self.p2.article_set.all(), [self.a3])
|
||||||
|
|
||||||
def test_clear_after_prefetch(self):
|
def test_clear_after_prefetch(self):
|
||||||
a4 = Article.objects.prefetch_related('publications').get(id=self.a4.id)
|
a4 = Article.objects.prefetch_related('publications').get(id=self.a4.id)
|
||||||
self.assertQuerysetEqual(a4.publications.all(), ['<Publication: Science News>'])
|
self.assertSequenceEqual(a4.publications.all(), [self.p2])
|
||||||
a4.publications.clear()
|
a4.publications.clear()
|
||||||
self.assertQuerysetEqual(a4.publications.all(), [])
|
self.assertSequenceEqual(a4.publications.all(), [])
|
||||||
|
|
||||||
def test_remove_after_prefetch(self):
|
def test_remove_after_prefetch(self):
|
||||||
a4 = Article.objects.prefetch_related('publications').get(id=self.a4.id)
|
a4 = Article.objects.prefetch_related('publications').get(id=self.a4.id)
|
||||||
self.assertQuerysetEqual(a4.publications.all(), ['<Publication: Science News>'])
|
self.assertSequenceEqual(a4.publications.all(), [self.p2])
|
||||||
a4.publications.remove(self.p2)
|
a4.publications.remove(self.p2)
|
||||||
self.assertQuerysetEqual(a4.publications.all(), [])
|
self.assertSequenceEqual(a4.publications.all(), [])
|
||||||
|
|
||||||
def test_add_after_prefetch(self):
|
def test_add_after_prefetch(self):
|
||||||
a4 = Article.objects.prefetch_related('publications').get(id=self.a4.id)
|
a4 = Article.objects.prefetch_related('publications').get(id=self.a4.id)
|
||||||
|
@ -610,7 +474,7 @@ class ManyToManyTests(TestCase):
|
||||||
a4.publications.add(self.p1)
|
a4.publications.add(self.p1)
|
||||||
self.assertEqual(a4.publications.count(), 2)
|
self.assertEqual(a4.publications.count(), 2)
|
||||||
a4.publications.remove(self.p1)
|
a4.publications.remove(self.p1)
|
||||||
self.assertQuerysetEqual(a4.publications.all(), ['<Publication: Science News>'])
|
self.assertSequenceEqual(a4.publications.all(), [self.p2])
|
||||||
|
|
||||||
def test_inherited_models_selects(self):
|
def test_inherited_models_selects(self):
|
||||||
"""
|
"""
|
||||||
|
@ -620,22 +484,17 @@ class ManyToManyTests(TestCase):
|
||||||
a = InheritedArticleA.objects.create()
|
a = InheritedArticleA.objects.create()
|
||||||
b = InheritedArticleB.objects.create()
|
b = InheritedArticleB.objects.create()
|
||||||
a.publications.add(self.p1, self.p2)
|
a.publications.add(self.p1, self.p2)
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
a.publications.all(),
|
a.publications.all(),
|
||||||
[
|
[self.p2, self.p1],
|
||||||
'<Publication: Science News>',
|
|
||||||
'<Publication: The Python Journal>',
|
|
||||||
])
|
|
||||||
self.assertQuerysetEqual(b.publications.all(), [])
|
|
||||||
b.publications.add(self.p3)
|
|
||||||
self.assertQuerysetEqual(
|
|
||||||
a.publications.all(),
|
|
||||||
[
|
|
||||||
'<Publication: Science News>',
|
|
||||||
'<Publication: The Python Journal>',
|
|
||||||
]
|
|
||||||
)
|
)
|
||||||
self.assertQuerysetEqual(b.publications.all(), ['<Publication: Science Weekly>'])
|
self.assertSequenceEqual(b.publications.all(), [])
|
||||||
|
b.publications.add(self.p3)
|
||||||
|
self.assertSequenceEqual(
|
||||||
|
a.publications.all(),
|
||||||
|
[self.p2, self.p1],
|
||||||
|
)
|
||||||
|
self.assertSequenceEqual(b.publications.all(), [self.p3])
|
||||||
|
|
||||||
def test_custom_default_manager_exists_count(self):
|
def test_custom_default_manager_exists_count(self):
|
||||||
a5 = Article.objects.create(headline='deleted')
|
a5 = Article.objects.create(headline='deleted')
|
||||||
|
|
|
@ -57,23 +57,23 @@ class ManyToOneTests(TestCase):
|
||||||
|
|
||||||
self.r.article_set.add(new_article2, bulk=False)
|
self.r.article_set.add(new_article2, bulk=False)
|
||||||
self.assertEqual(new_article2.reporter.id, self.r.id)
|
self.assertEqual(new_article2.reporter.id, self.r.id)
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
self.r.article_set.all(),
|
self.r.article_set.all(),
|
||||||
["<Article: John's second story>", "<Article: Paul's story>", "<Article: This is a test>"]
|
[new_article, new_article2, self.a],
|
||||||
)
|
)
|
||||||
|
|
||||||
# Add the same article to a different article set - check that it moves.
|
# Add the same article to a different article set - check that it moves.
|
||||||
self.r2.article_set.add(new_article2)
|
self.r2.article_set.add(new_article2)
|
||||||
self.assertEqual(new_article2.reporter.id, self.r2.id)
|
self.assertEqual(new_article2.reporter.id, self.r2.id)
|
||||||
self.assertQuerysetEqual(self.r2.article_set.all(), ["<Article: Paul's story>"])
|
self.assertSequenceEqual(self.r2.article_set.all(), [new_article2])
|
||||||
|
|
||||||
# Adding an object of the wrong type raises TypeError.
|
# Adding an object of the wrong type raises TypeError.
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
with self.assertRaisesMessage(TypeError, "'Article' instance expected, got <Reporter:"):
|
with self.assertRaisesMessage(TypeError, "'Article' instance expected, got <Reporter:"):
|
||||||
self.r.article_set.add(self.r2)
|
self.r.article_set.add(self.r2)
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
self.r.article_set.all(),
|
self.r.article_set.all(),
|
||||||
["<Article: John's second story>", "<Article: This is a test>"]
|
[new_article, self.a],
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_set(self):
|
def test_set(self):
|
||||||
|
@ -85,29 +85,28 @@ class ManyToOneTests(TestCase):
|
||||||
new_article2.save()
|
new_article2.save()
|
||||||
self.assertEqual(repr(new_article2.reporter), "<Reporter: John Smith>")
|
self.assertEqual(repr(new_article2.reporter), "<Reporter: John Smith>")
|
||||||
self.assertEqual(new_article2.reporter.id, self.r.id)
|
self.assertEqual(new_article2.reporter.id, self.r.id)
|
||||||
self.assertQuerysetEqual(self.r.article_set.all(), [
|
self.assertSequenceEqual(
|
||||||
"<Article: John's second story>",
|
self.r.article_set.all(),
|
||||||
"<Article: Paul's story>",
|
[new_article, new_article2, self.a],
|
||||||
"<Article: This is a test>",
|
)
|
||||||
])
|
self.assertSequenceEqual(self.r2.article_set.all(), [])
|
||||||
self.assertQuerysetEqual(self.r2.article_set.all(), [])
|
|
||||||
|
|
||||||
# Set the article back again.
|
# Set the article back again.
|
||||||
self.r2.article_set.set([new_article, new_article2])
|
self.r2.article_set.set([new_article, new_article2])
|
||||||
self.assertQuerysetEqual(self.r.article_set.all(), ["<Article: This is a test>"])
|
self.assertSequenceEqual(self.r.article_set.all(), [self.a])
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
self.r2.article_set.all(),
|
self.r2.article_set.all(),
|
||||||
["<Article: John's second story>", "<Article: Paul's story>"]
|
[new_article, new_article2],
|
||||||
)
|
)
|
||||||
|
|
||||||
# Funny case - because the ForeignKey cannot be null,
|
# Funny case - because the ForeignKey cannot be null,
|
||||||
# existing members of the set must remain.
|
# existing members of the set must remain.
|
||||||
self.r.article_set.set([new_article])
|
self.r.article_set.set([new_article])
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
self.r.article_set.all(),
|
self.r.article_set.all(),
|
||||||
["<Article: John's second story>", "<Article: This is a test>"]
|
[new_article, self.a],
|
||||||
)
|
)
|
||||||
self.assertQuerysetEqual(self.r2.article_set.all(), ["<Article: Paul's story>"])
|
self.assertSequenceEqual(self.r2.article_set.all(), [new_article2])
|
||||||
|
|
||||||
def test_reverse_assignment_deprecation(self):
|
def test_reverse_assignment_deprecation(self):
|
||||||
msg = (
|
msg = (
|
||||||
|
@ -126,29 +125,28 @@ class ManyToOneTests(TestCase):
|
||||||
new_article2.save()
|
new_article2.save()
|
||||||
self.assertEqual(repr(new_article2.reporter), "<Reporter: John Smith>")
|
self.assertEqual(repr(new_article2.reporter), "<Reporter: John Smith>")
|
||||||
self.assertEqual(new_article2.reporter.id, self.r.id)
|
self.assertEqual(new_article2.reporter.id, self.r.id)
|
||||||
self.assertQuerysetEqual(self.r.article_set.all(), [
|
self.assertSequenceEqual(
|
||||||
"<Article: John's second story>",
|
self.r.article_set.all(),
|
||||||
"<Article: Paul's story>",
|
[new_article, new_article2, self.a],
|
||||||
"<Article: This is a test>",
|
)
|
||||||
])
|
self.assertSequenceEqual(self.r2.article_set.all(), [])
|
||||||
self.assertQuerysetEqual(self.r2.article_set.all(), [])
|
|
||||||
|
|
||||||
# Set the article back again using set() method.
|
# Set the article back again using set() method.
|
||||||
self.r2.article_set.set([new_article, new_article2])
|
self.r2.article_set.set([new_article, new_article2])
|
||||||
self.assertQuerysetEqual(self.r.article_set.all(), ["<Article: This is a test>"])
|
self.assertSequenceEqual(self.r.article_set.all(), [self.a])
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
self.r2.article_set.all(),
|
self.r2.article_set.all(),
|
||||||
["<Article: John's second story>", "<Article: Paul's story>"]
|
[new_article, new_article2],
|
||||||
)
|
)
|
||||||
|
|
||||||
# Because the ForeignKey cannot be null, existing members of the set
|
# Because the ForeignKey cannot be null, existing members of the set
|
||||||
# must remain.
|
# must remain.
|
||||||
self.r.article_set.set([new_article])
|
self.r.article_set.set([new_article])
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
self.r.article_set.all(),
|
self.r.article_set.all(),
|
||||||
["<Article: John's second story>", "<Article: This is a test>"]
|
[new_article, self.a],
|
||||||
)
|
)
|
||||||
self.assertQuerysetEqual(self.r2.article_set.all(), ["<Article: Paul's story>"])
|
self.assertSequenceEqual(self.r2.article_set.all(), [new_article2])
|
||||||
# Reporter cannot be null - there should not be a clear or remove method
|
# Reporter cannot be null - there should not be a clear or remove method
|
||||||
self.assertFalse(hasattr(self.r2.article_set, 'remove'))
|
self.assertFalse(hasattr(self.r2.article_set, 'remove'))
|
||||||
self.assertFalse(hasattr(self.r2.article_set, 'clear'))
|
self.assertFalse(hasattr(self.r2.article_set, 'clear'))
|
||||||
|
@ -182,38 +180,44 @@ class ManyToOneTests(TestCase):
|
||||||
self.assertTrue(Parent.bestchild.is_cached(parent))
|
self.assertTrue(Parent.bestchild.is_cached(parent))
|
||||||
|
|
||||||
def test_selects(self):
|
def test_selects(self):
|
||||||
self.r.article_set.create(headline="John's second story", pub_date=datetime.date(2005, 7, 29))
|
new_article1 = self.r.article_set.create(
|
||||||
self.r2.article_set.create(headline="Paul's story", pub_date=datetime.date(2006, 1, 17))
|
headline="John's second story",
|
||||||
|
pub_date=datetime.date(2005, 7, 29),
|
||||||
|
)
|
||||||
|
new_article2 = self.r2.article_set.create(
|
||||||
|
headline="Paul's story",
|
||||||
|
pub_date=datetime.date(2006, 1, 17),
|
||||||
|
)
|
||||||
# Reporter objects have access to their related Article objects.
|
# Reporter objects have access to their related Article objects.
|
||||||
self.assertQuerysetEqual(self.r.article_set.all(), [
|
self.assertSequenceEqual(
|
||||||
"<Article: John's second story>",
|
self.r.article_set.all(),
|
||||||
"<Article: This is a test>",
|
[new_article1, self.a],
|
||||||
])
|
)
|
||||||
self.assertQuerysetEqual(self.r.article_set.filter(headline__startswith='This'), ["<Article: This is a test>"])
|
self.assertSequenceEqual(self.r.article_set.filter(headline__startswith='This'), [self.a])
|
||||||
self.assertEqual(self.r.article_set.count(), 2)
|
self.assertEqual(self.r.article_set.count(), 2)
|
||||||
self.assertEqual(self.r2.article_set.count(), 1)
|
self.assertEqual(self.r2.article_set.count(), 1)
|
||||||
# Get articles by id
|
# Get articles by id
|
||||||
self.assertQuerysetEqual(Article.objects.filter(id__exact=self.a.id), ["<Article: This is a test>"])
|
self.assertSequenceEqual(Article.objects.filter(id__exact=self.a.id), [self.a])
|
||||||
self.assertQuerysetEqual(Article.objects.filter(pk=self.a.id), ["<Article: This is a test>"])
|
self.assertSequenceEqual(Article.objects.filter(pk=self.a.id), [self.a])
|
||||||
# Query on an article property
|
# Query on an article property
|
||||||
self.assertQuerysetEqual(Article.objects.filter(headline__startswith='This'), ["<Article: This is a test>"])
|
self.assertSequenceEqual(Article.objects.filter(headline__startswith='This'), [self.a])
|
||||||
# The API automatically follows relationships as far as you need.
|
# The API automatically follows relationships as far as you need.
|
||||||
# Use double underscores to separate relationships.
|
# Use double underscores to separate relationships.
|
||||||
# This works as many levels deep as you want. There's no limit.
|
# This works as many levels deep as you want. There's no limit.
|
||||||
# Find all Articles for any Reporter whose first name is "John".
|
# Find all Articles for any Reporter whose first name is "John".
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
Article.objects.filter(reporter__first_name__exact='John'),
|
Article.objects.filter(reporter__first_name__exact='John'),
|
||||||
["<Article: John's second story>", "<Article: This is a test>"]
|
[new_article1, self.a],
|
||||||
)
|
)
|
||||||
# Implied __exact also works
|
# Implied __exact also works
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
Article.objects.filter(reporter__first_name='John'),
|
Article.objects.filter(reporter__first_name='John'),
|
||||||
["<Article: John's second story>", "<Article: This is a test>"]
|
[new_article1, self.a],
|
||||||
)
|
)
|
||||||
# Query twice over the related field.
|
# Query twice over the related field.
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
Article.objects.filter(reporter__first_name__exact='John', reporter__last_name__exact='Smith'),
|
Article.objects.filter(reporter__first_name__exact='John', reporter__last_name__exact='Smith'),
|
||||||
["<Article: John's second story>", "<Article: This is a test>"]
|
[new_article1, self.a],
|
||||||
)
|
)
|
||||||
# The underlying query only makes one join when a related table is referenced twice.
|
# The underlying query only makes one join when a related table is referenced twice.
|
||||||
queryset = Article.objects.filter(reporter__first_name__exact='John', reporter__last_name__exact='Smith')
|
queryset = Article.objects.filter(reporter__first_name__exact='John', reporter__last_name__exact='Smith')
|
||||||
|
@ -221,69 +225,53 @@ class ManyToOneTests(TestCase):
|
||||||
self.assertEqual(queryset.query.get_compiler(queryset.db).as_sql()[0].count('INNER JOIN'), 1)
|
self.assertEqual(queryset.query.get_compiler(queryset.db).as_sql()[0].count('INNER JOIN'), 1)
|
||||||
|
|
||||||
# The automatically joined table has a predictable name.
|
# The automatically joined table has a predictable name.
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
Article.objects.filter(reporter__first_name__exact='John').extra(
|
Article.objects.filter(reporter__first_name__exact='John').extra(
|
||||||
where=["many_to_one_reporter.last_name='Smith'"]),
|
where=["many_to_one_reporter.last_name='Smith'"]),
|
||||||
["<Article: John's second story>", "<Article: This is a test>"]
|
[new_article1, self.a],
|
||||||
)
|
)
|
||||||
# ... and should work fine with the string that comes out of forms.Form.cleaned_data
|
# ... and should work fine with the string that comes out of forms.Form.cleaned_data
|
||||||
self.assertQuerysetEqual(
|
self.assertQuerysetEqual(
|
||||||
(Article.objects
|
(Article.objects
|
||||||
.filter(reporter__first_name__exact='John')
|
.filter(reporter__first_name__exact='John')
|
||||||
.extra(where=["many_to_one_reporter.last_name='%s'" % 'Smith'])),
|
.extra(where=["many_to_one_reporter.last_name='%s'" % 'Smith'])),
|
||||||
["<Article: John's second story>", "<Article: This is a test>"]
|
[new_article1, self.a]
|
||||||
)
|
)
|
||||||
# Find all Articles for a Reporter.
|
# Find all Articles for a Reporter.
|
||||||
# Use direct ID check, pk check, and object comparison
|
# Use direct ID check, pk check, and object comparison
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
Article.objects.filter(reporter__id__exact=self.r.id),
|
Article.objects.filter(reporter__id__exact=self.r.id),
|
||||||
[
|
[new_article1, self.a],
|
||||||
"<Article: John's second story>",
|
)
|
||||||
"<Article: This is a test>",
|
self.assertSequenceEqual(
|
||||||
])
|
|
||||||
self.assertQuerysetEqual(
|
|
||||||
Article.objects.filter(reporter__pk=self.r.id),
|
Article.objects.filter(reporter__pk=self.r.id),
|
||||||
[
|
[new_article1, self.a],
|
||||||
"<Article: John's second story>",
|
)
|
||||||
"<Article: This is a test>",
|
self.assertSequenceEqual(
|
||||||
])
|
|
||||||
self.assertQuerysetEqual(
|
|
||||||
Article.objects.filter(reporter=self.r.id),
|
Article.objects.filter(reporter=self.r.id),
|
||||||
[
|
[new_article1, self.a],
|
||||||
"<Article: John's second story>",
|
)
|
||||||
"<Article: This is a test>",
|
self.assertSequenceEqual(
|
||||||
])
|
|
||||||
self.assertQuerysetEqual(
|
|
||||||
Article.objects.filter(reporter=self.r),
|
Article.objects.filter(reporter=self.r),
|
||||||
[
|
[new_article1, self.a],
|
||||||
"<Article: John's second story>",
|
)
|
||||||
"<Article: This is a test>",
|
self.assertSequenceEqual(
|
||||||
])
|
|
||||||
self.assertQuerysetEqual(
|
|
||||||
Article.objects.filter(reporter__in=[self.r.id, self.r2.id]).distinct(),
|
Article.objects.filter(reporter__in=[self.r.id, self.r2.id]).distinct(),
|
||||||
[
|
[new_article1, new_article2, self.a],
|
||||||
"<Article: John's second story>",
|
)
|
||||||
"<Article: Paul's story>",
|
self.assertSequenceEqual(
|
||||||
"<Article: This is a test>",
|
|
||||||
])
|
|
||||||
self.assertQuerysetEqual(
|
|
||||||
Article.objects.filter(reporter__in=[self.r, self.r2]).distinct(),
|
Article.objects.filter(reporter__in=[self.r, self.r2]).distinct(),
|
||||||
[
|
[new_article1, new_article2, self.a],
|
||||||
"<Article: John's second story>",
|
)
|
||||||
"<Article: Paul's story>",
|
|
||||||
"<Article: This is a test>",
|
|
||||||
])
|
|
||||||
# You can also use a queryset instead of a literal list of instances.
|
# You can also use a queryset instead of a literal list of instances.
|
||||||
# The queryset must be reduced to a list of values using values(),
|
# The queryset must be reduced to a list of values using values(),
|
||||||
# then converted into a query
|
# then converted into a query
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
Article.objects.filter(
|
Article.objects.filter(
|
||||||
reporter__in=Reporter.objects.filter(first_name='John').values('pk').query
|
reporter__in=Reporter.objects.filter(first_name='John').values('pk').query
|
||||||
).distinct(),
|
).distinct(),
|
||||||
[
|
[new_article1, self.a],
|
||||||
"<Article: John's second story>",
|
)
|
||||||
"<Article: This is a test>",
|
|
||||||
])
|
|
||||||
|
|
||||||
def test_reverse_selects(self):
|
def test_reverse_selects(self):
|
||||||
a3 = Article.objects.create(
|
a3 = Article.objects.create(
|
||||||
|
@ -296,48 +284,42 @@ class ManyToOneTests(TestCase):
|
||||||
pub_date=datetime.date(2005, 7, 27),
|
pub_date=datetime.date(2005, 7, 27),
|
||||||
reporter_id=self.r.id,
|
reporter_id=self.r.id,
|
||||||
)
|
)
|
||||||
john_smith = ["<Reporter: John Smith>"]
|
john_smith = [self.r]
|
||||||
# Reporters can be queried
|
# Reporters can be queried
|
||||||
self.assertQuerysetEqual(Reporter.objects.filter(id__exact=self.r.id), john_smith)
|
self.assertSequenceEqual(Reporter.objects.filter(id__exact=self.r.id), john_smith)
|
||||||
self.assertQuerysetEqual(Reporter.objects.filter(pk=self.r.id), john_smith)
|
self.assertSequenceEqual(Reporter.objects.filter(pk=self.r.id), john_smith)
|
||||||
self.assertQuerysetEqual(Reporter.objects.filter(first_name__startswith='John'), john_smith)
|
self.assertSequenceEqual(Reporter.objects.filter(first_name__startswith='John'), john_smith)
|
||||||
# Reporters can query in opposite direction of ForeignKey definition
|
# Reporters can query in opposite direction of ForeignKey definition
|
||||||
self.assertQuerysetEqual(Reporter.objects.filter(article__id__exact=self.a.id), john_smith)
|
self.assertSequenceEqual(Reporter.objects.filter(article__id__exact=self.a.id), john_smith)
|
||||||
self.assertQuerysetEqual(Reporter.objects.filter(article__pk=self.a.id), john_smith)
|
self.assertSequenceEqual(Reporter.objects.filter(article__pk=self.a.id), john_smith)
|
||||||
self.assertQuerysetEqual(Reporter.objects.filter(article=self.a.id), john_smith)
|
self.assertSequenceEqual(Reporter.objects.filter(article=self.a.id), john_smith)
|
||||||
self.assertQuerysetEqual(Reporter.objects.filter(article=self.a), john_smith)
|
self.assertSequenceEqual(Reporter.objects.filter(article=self.a), john_smith)
|
||||||
self.assertQuerysetEqual(Reporter.objects.filter(article__in=[self.a.id, a3.id]).distinct(), john_smith)
|
self.assertSequenceEqual(Reporter.objects.filter(article__in=[self.a.id, a3.id]).distinct(), john_smith)
|
||||||
self.assertQuerysetEqual(Reporter.objects.filter(article__in=[self.a.id, a3]).distinct(), john_smith)
|
self.assertSequenceEqual(Reporter.objects.filter(article__in=[self.a.id, a3]).distinct(), john_smith)
|
||||||
self.assertQuerysetEqual(Reporter.objects.filter(article__in=[self.a, a3]).distinct(), john_smith)
|
self.assertSequenceEqual(Reporter.objects.filter(article__in=[self.a, a3]).distinct(), john_smith)
|
||||||
self.assertQuerysetEqual(
|
self.assertCountEqual(
|
||||||
Reporter.objects.filter(article__headline__startswith='T'),
|
Reporter.objects.filter(article__headline__startswith='T'),
|
||||||
["<Reporter: John Smith>", "<Reporter: John Smith>"],
|
[self.r, self.r],
|
||||||
ordered=False
|
|
||||||
)
|
)
|
||||||
self.assertQuerysetEqual(Reporter.objects.filter(article__headline__startswith='T').distinct(), john_smith)
|
self.assertSequenceEqual(Reporter.objects.filter(article__headline__startswith='T').distinct(), john_smith)
|
||||||
|
|
||||||
# Counting in the opposite direction works in conjunction with distinct()
|
# Counting in the opposite direction works in conjunction with distinct()
|
||||||
self.assertEqual(Reporter.objects.filter(article__headline__startswith='T').count(), 2)
|
self.assertEqual(Reporter.objects.filter(article__headline__startswith='T').count(), 2)
|
||||||
self.assertEqual(Reporter.objects.filter(article__headline__startswith='T').distinct().count(), 1)
|
self.assertEqual(Reporter.objects.filter(article__headline__startswith='T').distinct().count(), 1)
|
||||||
|
|
||||||
# Queries can go round in circles.
|
# Queries can go round in circles.
|
||||||
self.assertQuerysetEqual(
|
self.assertCountEqual(
|
||||||
Reporter.objects.filter(article__reporter__first_name__startswith='John'),
|
Reporter.objects.filter(article__reporter__first_name__startswith='John'),
|
||||||
[
|
[self.r, self.r, self.r],
|
||||||
"<Reporter: John Smith>",
|
|
||||||
"<Reporter: John Smith>",
|
|
||||||
"<Reporter: John Smith>",
|
|
||||||
],
|
|
||||||
ordered=False
|
|
||||||
)
|
)
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
Reporter.objects.filter(article__reporter__first_name__startswith='John').distinct(),
|
Reporter.objects.filter(article__reporter__first_name__startswith='John').distinct(),
|
||||||
john_smith
|
john_smith
|
||||||
)
|
)
|
||||||
self.assertQuerysetEqual(Reporter.objects.filter(article__reporter__exact=self.r).distinct(), john_smith)
|
self.assertSequenceEqual(Reporter.objects.filter(article__reporter__exact=self.r).distinct(), john_smith)
|
||||||
|
|
||||||
# Implied __exact also works.
|
# Implied __exact also works.
|
||||||
self.assertQuerysetEqual(Reporter.objects.filter(article__reporter=self.r).distinct(), john_smith)
|
self.assertSequenceEqual(Reporter.objects.filter(article__reporter=self.r).distinct(), john_smith)
|
||||||
|
|
||||||
# It's possible to use values() calls across many-to-one relations.
|
# It's possible to use values() calls across many-to-one relations.
|
||||||
# (Note, too, that we clear the ordering here so as not to drag the
|
# (Note, too, that we clear the ordering here so as not to drag the
|
||||||
|
@ -370,44 +352,43 @@ class ManyToOneTests(TestCase):
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_delete(self):
|
def test_delete(self):
|
||||||
self.r.article_set.create(headline="John's second story", pub_date=datetime.date(2005, 7, 29))
|
new_article1 = self.r.article_set.create(
|
||||||
self.r2.article_set.create(headline="Paul's story", pub_date=datetime.date(2006, 1, 17))
|
headline="John's second story",
|
||||||
Article.objects.create(headline="Third article", pub_date=datetime.date(2005, 7, 27), reporter_id=self.r.id)
|
pub_date=datetime.date(2005, 7, 29),
|
||||||
Article.objects.create(
|
)
|
||||||
|
new_article2 = self.r2.article_set.create(
|
||||||
|
headline="Paul's story",
|
||||||
|
pub_date=datetime.date(2006, 1, 17),
|
||||||
|
)
|
||||||
|
new_article3 = Article.objects.create(
|
||||||
|
headline="Third article",
|
||||||
|
pub_date=datetime.date(2005, 7, 27),
|
||||||
|
reporter_id=self.r.id,
|
||||||
|
)
|
||||||
|
new_article4 = Article.objects.create(
|
||||||
headline="Fourth article",
|
headline="Fourth article",
|
||||||
pub_date=datetime.date(2005, 7, 27),
|
pub_date=datetime.date(2005, 7, 27),
|
||||||
reporter_id=str(self.r.id),
|
reporter_id=str(self.r.id),
|
||||||
)
|
)
|
||||||
# If you delete a reporter, his articles will be deleted.
|
# If you delete a reporter, his articles will be deleted.
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
Article.objects.all(),
|
Article.objects.all(),
|
||||||
[
|
[new_article4, new_article1, new_article2, new_article3, self.a],
|
||||||
"<Article: Fourth article>",
|
|
||||||
"<Article: John's second story>",
|
|
||||||
"<Article: Paul's story>",
|
|
||||||
"<Article: Third article>",
|
|
||||||
"<Article: This is a test>",
|
|
||||||
]
|
|
||||||
)
|
)
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
Reporter.objects.order_by('first_name'),
|
Reporter.objects.order_by('first_name'),
|
||||||
["<Reporter: John Smith>", "<Reporter: Paul Jones>"]
|
[self.r, self.r2],
|
||||||
)
|
)
|
||||||
self.r2.delete()
|
self.r2.delete()
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
Article.objects.all(),
|
Article.objects.all(),
|
||||||
[
|
[new_article4, new_article1, new_article3, self.a],
|
||||||
"<Article: Fourth article>",
|
|
||||||
"<Article: John's second story>",
|
|
||||||
"<Article: Third article>",
|
|
||||||
"<Article: This is a test>",
|
|
||||||
]
|
|
||||||
)
|
)
|
||||||
self.assertQuerysetEqual(Reporter.objects.order_by('first_name'), ["<Reporter: John Smith>"])
|
self.assertSequenceEqual(Reporter.objects.order_by('first_name'), [self.r])
|
||||||
# You can delete using a JOIN in the query.
|
# You can delete using a JOIN in the query.
|
||||||
Reporter.objects.filter(article__headline__startswith='This').delete()
|
Reporter.objects.filter(article__headline__startswith='This').delete()
|
||||||
self.assertQuerysetEqual(Reporter.objects.all(), [])
|
self.assertSequenceEqual(Reporter.objects.all(), [])
|
||||||
self.assertQuerysetEqual(Article.objects.all(), [])
|
self.assertSequenceEqual(Article.objects.all(), [])
|
||||||
|
|
||||||
def test_explicit_fk(self):
|
def test_explicit_fk(self):
|
||||||
# Create a new Article with get_or_create using an explicit value
|
# Create a new Article with get_or_create using an explicit value
|
||||||
|
@ -421,9 +402,9 @@ class ManyToOneTests(TestCase):
|
||||||
self.assertEqual(a2.reporter.id, self.r.id)
|
self.assertEqual(a2.reporter.id, self.r.id)
|
||||||
|
|
||||||
# You can specify filters containing the explicit FK value.
|
# You can specify filters containing the explicit FK value.
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
Article.objects.filter(reporter_id__exact=self.r.id),
|
Article.objects.filter(reporter_id__exact=self.r.id),
|
||||||
["<Article: John's second test>", "<Article: This is a test>"]
|
[a2, self.a],
|
||||||
)
|
)
|
||||||
|
|
||||||
# Create an Article by Paul for the same date.
|
# Create an Article by Paul for the same date.
|
||||||
|
@ -598,15 +579,15 @@ class ManyToOneTests(TestCase):
|
||||||
r5 = Record.objects.create(category=c3)
|
r5 = Record.objects.create(category=c3)
|
||||||
Relation.objects.create(left=r1, right=r2)
|
Relation.objects.create(left=r1, right=r2)
|
||||||
Relation.objects.create(left=r3, right=r4)
|
Relation.objects.create(left=r3, right=r4)
|
||||||
Relation.objects.create(left=r1, right=r3)
|
rel = Relation.objects.create(left=r1, right=r3)
|
||||||
Relation.objects.create(left=r5, right=r2)
|
Relation.objects.create(left=r5, right=r2)
|
||||||
Relation.objects.create(left=r3, right=r2)
|
Relation.objects.create(left=r3, right=r2)
|
||||||
|
|
||||||
q1 = Relation.objects.filter(left__category__name__in=['First'], right__category__name__in=['Second'])
|
q1 = Relation.objects.filter(left__category__name__in=['First'], right__category__name__in=['Second'])
|
||||||
self.assertQuerysetEqual(q1, ["<Relation: First - Second>"])
|
self.assertSequenceEqual(q1, [rel])
|
||||||
|
|
||||||
q2 = Category.objects.filter(record__left_set__right__category__name='Second').order_by('name')
|
q2 = Category.objects.filter(record__left_set__right__category__name='Second').order_by('name')
|
||||||
self.assertQuerysetEqual(q2, ["<Category: First>", "<Category: Second>"])
|
self.assertSequenceEqual(q2, [c1, c2])
|
||||||
|
|
||||||
p = Parent.objects.create(name="Parent")
|
p = Parent.objects.create(name="Parent")
|
||||||
c = Child.objects.create(name="Child", parent=p)
|
c = Child.objects.create(name="Child", parent=p)
|
||||||
|
@ -669,19 +650,19 @@ class ManyToOneTests(TestCase):
|
||||||
|
|
||||||
def test_clear_after_prefetch(self):
|
def test_clear_after_prefetch(self):
|
||||||
c = City.objects.create(name='Musical City')
|
c = City.objects.create(name='Musical City')
|
||||||
District.objects.create(name='Ladida', city=c)
|
d = District.objects.create(name='Ladida', city=c)
|
||||||
city = City.objects.prefetch_related('districts').get(id=c.id)
|
city = City.objects.prefetch_related('districts').get(id=c.id)
|
||||||
self.assertQuerysetEqual(city.districts.all(), ['<District: Ladida>'])
|
self.assertSequenceEqual(city.districts.all(), [d])
|
||||||
city.districts.clear()
|
city.districts.clear()
|
||||||
self.assertQuerysetEqual(city.districts.all(), [])
|
self.assertSequenceEqual(city.districts.all(), [])
|
||||||
|
|
||||||
def test_remove_after_prefetch(self):
|
def test_remove_after_prefetch(self):
|
||||||
c = City.objects.create(name='Musical City')
|
c = City.objects.create(name='Musical City')
|
||||||
d = District.objects.create(name='Ladida', city=c)
|
d = District.objects.create(name='Ladida', city=c)
|
||||||
city = City.objects.prefetch_related('districts').get(id=c.id)
|
city = City.objects.prefetch_related('districts').get(id=c.id)
|
||||||
self.assertQuerysetEqual(city.districts.all(), ['<District: Ladida>'])
|
self.assertSequenceEqual(city.districts.all(), [d])
|
||||||
city.districts.remove(d)
|
city.districts.remove(d)
|
||||||
self.assertQuerysetEqual(city.districts.all(), [])
|
self.assertSequenceEqual(city.districts.all(), [])
|
||||||
|
|
||||||
def test_add_after_prefetch(self):
|
def test_add_after_prefetch(self):
|
||||||
c = City.objects.create(name='Musical City')
|
c = City.objects.create(name='Musical City')
|
||||||
|
@ -699,7 +680,7 @@ class ManyToOneTests(TestCase):
|
||||||
city = City.objects.prefetch_related('districts').get(id=c.id)
|
city = City.objects.prefetch_related('districts').get(id=c.id)
|
||||||
self.assertEqual(city.districts.count(), 1)
|
self.assertEqual(city.districts.count(), 1)
|
||||||
city.districts.set([d2])
|
city.districts.set([d2])
|
||||||
self.assertQuerysetEqual(city.districts.all(), ['<District: Ladidu>'])
|
self.assertSequenceEqual(city.districts.all(), [d2])
|
||||||
|
|
||||||
def test_add_then_remove_after_prefetch(self):
|
def test_add_then_remove_after_prefetch(self):
|
||||||
c = City.objects.create(name='Musical City')
|
c = City.objects.create(name='Musical City')
|
||||||
|
|
|
@ -33,8 +33,8 @@ class ManyToOneNullTests(TestCase):
|
||||||
|
|
||||||
def test_related_set(self):
|
def test_related_set(self):
|
||||||
# Reporter objects have access to their related Article objects.
|
# Reporter objects have access to their related Article objects.
|
||||||
self.assertQuerysetEqual(self.r.article_set.all(), ['<Article: First>', '<Article: Second>'])
|
self.assertSequenceEqual(self.r.article_set.all(), [self.a, self.a2])
|
||||||
self.assertQuerysetEqual(self.r.article_set.filter(headline__startswith='Fir'), ['<Article: First>'])
|
self.assertSequenceEqual(self.r.article_set.filter(headline__startswith='Fir'), [self.a])
|
||||||
self.assertEqual(self.r.article_set.count(), 2)
|
self.assertEqual(self.r.article_set.count(), 2)
|
||||||
|
|
||||||
def test_created_without_related(self):
|
def test_created_without_related(self):
|
||||||
|
@ -47,43 +47,43 @@ class ManyToOneNullTests(TestCase):
|
||||||
# if the reporter is set to None.
|
# if the reporter is set to None.
|
||||||
self.assertIsNone(a3.reporter)
|
self.assertIsNone(a3.reporter)
|
||||||
# To retrieve the articles with no reporters set, use "reporter__isnull=True".
|
# To retrieve the articles with no reporters set, use "reporter__isnull=True".
|
||||||
self.assertQuerysetEqual(Article.objects.filter(reporter__isnull=True), ['<Article: Third>'])
|
self.assertSequenceEqual(Article.objects.filter(reporter__isnull=True), [self.a3])
|
||||||
# We can achieve the same thing by filtering for the case where the
|
# We can achieve the same thing by filtering for the case where the
|
||||||
# reporter is None.
|
# reporter is None.
|
||||||
self.assertQuerysetEqual(Article.objects.filter(reporter=None), ['<Article: Third>'])
|
self.assertSequenceEqual(Article.objects.filter(reporter=None), [self.a3])
|
||||||
# Set the reporter for the Third article
|
# Set the reporter for the Third article
|
||||||
self.assertQuerysetEqual(self.r.article_set.all(), ['<Article: First>', '<Article: Second>'])
|
self.assertSequenceEqual(self.r.article_set.all(), [self.a, self.a2])
|
||||||
self.r.article_set.add(a3)
|
self.r.article_set.add(a3)
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
self.r.article_set.all(),
|
self.r.article_set.all(),
|
||||||
['<Article: First>', '<Article: Second>', '<Article: Third>']
|
[self.a, self.a2, self.a3],
|
||||||
)
|
)
|
||||||
# Remove an article from the set, and check that it was removed.
|
# Remove an article from the set, and check that it was removed.
|
||||||
self.r.article_set.remove(a3)
|
self.r.article_set.remove(a3)
|
||||||
self.assertQuerysetEqual(self.r.article_set.all(), ['<Article: First>', '<Article: Second>'])
|
self.assertSequenceEqual(self.r.article_set.all(), [self.a, self.a2])
|
||||||
self.assertQuerysetEqual(Article.objects.filter(reporter__isnull=True), ['<Article: Third>'])
|
self.assertSequenceEqual(Article.objects.filter(reporter__isnull=True), [self.a3])
|
||||||
|
|
||||||
def test_remove_from_wrong_set(self):
|
def test_remove_from_wrong_set(self):
|
||||||
self.assertQuerysetEqual(self.r2.article_set.all(), ['<Article: Fourth>'])
|
self.assertSequenceEqual(self.r2.article_set.all(), [self.a4])
|
||||||
# Try to remove a4 from a set it does not belong to
|
# Try to remove a4 from a set it does not belong to
|
||||||
with self.assertRaises(Reporter.DoesNotExist):
|
with self.assertRaises(Reporter.DoesNotExist):
|
||||||
self.r.article_set.remove(self.a4)
|
self.r.article_set.remove(self.a4)
|
||||||
self.assertQuerysetEqual(self.r2.article_set.all(), ['<Article: Fourth>'])
|
self.assertSequenceEqual(self.r2.article_set.all(), [self.a4])
|
||||||
|
|
||||||
def test_set(self):
|
def test_set(self):
|
||||||
# Use manager.set() to allocate ForeignKey. Null is legal, so existing
|
# Use manager.set() to allocate ForeignKey. Null is legal, so existing
|
||||||
# members of the set that are not in the assignment set are set to null.
|
# members of the set that are not in the assignment set are set to null.
|
||||||
self.r2.article_set.set([self.a2, self.a3])
|
self.r2.article_set.set([self.a2, self.a3])
|
||||||
self.assertQuerysetEqual(self.r2.article_set.all(), ['<Article: Second>', '<Article: Third>'])
|
self.assertSequenceEqual(self.r2.article_set.all(), [self.a2, self.a3])
|
||||||
# Use manager.set(clear=True)
|
# Use manager.set(clear=True)
|
||||||
self.r2.article_set.set([self.a3, self.a4], clear=True)
|
self.r2.article_set.set([self.a3, self.a4], clear=True)
|
||||||
self.assertQuerysetEqual(self.r2.article_set.all(), ['<Article: Fourth>', '<Article: Third>'])
|
self.assertSequenceEqual(self.r2.article_set.all(), [self.a4, self.a3])
|
||||||
# Clear the rest of the set
|
# Clear the rest of the set
|
||||||
self.r2.article_set.set([])
|
self.r2.article_set.set([])
|
||||||
self.assertQuerysetEqual(self.r2.article_set.all(), [])
|
self.assertSequenceEqual(self.r2.article_set.all(), [])
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
Article.objects.filter(reporter__isnull=True),
|
Article.objects.filter(reporter__isnull=True),
|
||||||
['<Article: Fourth>', '<Article: Second>', '<Article: Third>']
|
[self.a4, self.a2, self.a3],
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_set_clear_non_bulk(self):
|
def test_set_clear_non_bulk(self):
|
||||||
|
@ -96,13 +96,13 @@ class ManyToOneNullTests(TestCase):
|
||||||
# existing members of the set that are not in the assignment set are
|
# existing members of the set that are not in the assignment set are
|
||||||
# set to null.
|
# set to null.
|
||||||
self.r2.article_set.set([self.a2, self.a3])
|
self.r2.article_set.set([self.a2, self.a3])
|
||||||
self.assertQuerysetEqual(self.r2.article_set.all(), ['<Article: Second>', '<Article: Third>'])
|
self.assertSequenceEqual(self.r2.article_set.all(), [self.a2, self.a3])
|
||||||
# Clear the rest of the set
|
# Clear the rest of the set
|
||||||
self.r.article_set.clear()
|
self.r.article_set.clear()
|
||||||
self.assertQuerysetEqual(self.r.article_set.all(), [])
|
self.assertSequenceEqual(self.r.article_set.all(), [])
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
Article.objects.filter(reporter__isnull=True),
|
Article.objects.filter(reporter__isnull=True),
|
||||||
['<Article: First>', '<Article: Fourth>']
|
[self.a, self.a4],
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_assign_with_queryset(self):
|
def test_assign_with_queryset(self):
|
||||||
|
|
|
@ -59,14 +59,13 @@ class DateTimeFieldTests(TestCase):
|
||||||
m1 = DateTimeModel.objects.create(d=d, dt=dt1, t=t)
|
m1 = DateTimeModel.objects.create(d=d, dt=dt1, t=t)
|
||||||
m2 = DateTimeModel.objects.create(d=d, dt=dt2, t=t)
|
m2 = DateTimeModel.objects.create(d=d, dt=dt2, t=t)
|
||||||
# In Vancouver, we expect both results.
|
# In Vancouver, we expect both results.
|
||||||
self.assertQuerysetEqual(
|
self.assertCountEqual(
|
||||||
DateTimeModel.objects.filter(dt__date=d),
|
DateTimeModel.objects.filter(dt__date=d),
|
||||||
[repr(m1), repr(m2)],
|
[m1, m2],
|
||||||
ordered=False
|
|
||||||
)
|
)
|
||||||
with self.settings(TIME_ZONE='UTC'):
|
with self.settings(TIME_ZONE='UTC'):
|
||||||
# But in UTC, the __date only matches one of them.
|
# But in UTC, the __date only matches one of them.
|
||||||
self.assertQuerysetEqual(DateTimeModel.objects.filter(dt__date=d), [repr(m1)])
|
self.assertCountEqual(DateTimeModel.objects.filter(dt__date=d), [m1])
|
||||||
|
|
||||||
|
|
||||||
class ValidationTest(SimpleTestCase):
|
class ValidationTest(SimpleTestCase):
|
||||||
|
|
|
@ -1444,7 +1444,7 @@ class ModelFormBasicTests(TestCase):
|
||||||
article="Hello.", headline="New headline", slug="new-headline",
|
article="Hello.", headline="New headline", slug="new-headline",
|
||||||
pub_date=datetime.date(1988, 1, 4), writer=self.w_royko)
|
pub_date=datetime.date(1988, 1, 4), writer=self.w_royko)
|
||||||
new_art.categories.add(Category.objects.get(name='Entertainment'))
|
new_art.categories.add(Category.objects.get(name='Entertainment'))
|
||||||
self.assertQuerysetEqual(new_art.categories.all(), ["Entertainment"])
|
self.assertSequenceEqual(new_art.categories.all(), [self.c1])
|
||||||
f = ArticleForm(auto_id=False, instance=new_art)
|
f = ArticleForm(auto_id=False, instance=new_art)
|
||||||
self.assertHTMLEqual(
|
self.assertHTMLEqual(
|
||||||
f.as_ul(),
|
f.as_ul(),
|
||||||
|
@ -1528,7 +1528,7 @@ class ModelFormBasicTests(TestCase):
|
||||||
new_art = f.save()
|
new_art = f.save()
|
||||||
new_art = Article.objects.get(id=new_art.id)
|
new_art = Article.objects.get(id=new_art.id)
|
||||||
art_id_1 = new_art.id
|
art_id_1 = new_art.id
|
||||||
self.assertQuerysetEqual(new_art.categories.order_by('name'), ["Entertainment", "It's a test"])
|
self.assertSequenceEqual(new_art.categories.order_by('name'), [self.c1, self.c2])
|
||||||
|
|
||||||
# Now, submit form data with no categories. This deletes the existing categories.
|
# Now, submit form data with no categories. This deletes the existing categories.
|
||||||
form_data['categories'] = []
|
form_data['categories'] = []
|
||||||
|
@ -1536,7 +1536,7 @@ class ModelFormBasicTests(TestCase):
|
||||||
new_art = f.save()
|
new_art = f.save()
|
||||||
self.assertEqual(new_art.id, art_id_1)
|
self.assertEqual(new_art.id, art_id_1)
|
||||||
new_art = Article.objects.get(id=art_id_1)
|
new_art = Article.objects.get(id=art_id_1)
|
||||||
self.assertQuerysetEqual(new_art.categories.all(), [])
|
self.assertSequenceEqual(new_art.categories.all(), [])
|
||||||
|
|
||||||
# Create a new article, with no categories, via the form.
|
# Create a new article, with no categories, via the form.
|
||||||
f = ArticleForm(form_data)
|
f = ArticleForm(form_data)
|
||||||
|
@ -1544,7 +1544,7 @@ class ModelFormBasicTests(TestCase):
|
||||||
art_id_2 = new_art.id
|
art_id_2 = new_art.id
|
||||||
self.assertNotIn(art_id_2, (None, art_id_1))
|
self.assertNotIn(art_id_2, (None, art_id_1))
|
||||||
new_art = Article.objects.get(id=art_id_2)
|
new_art = Article.objects.get(id=art_id_2)
|
||||||
self.assertQuerysetEqual(new_art.categories.all(), [])
|
self.assertSequenceEqual(new_art.categories.all(), [])
|
||||||
|
|
||||||
# Create a new article, with categories, via the form, but use commit=False.
|
# Create a new article, with categories, via the form, but use commit=False.
|
||||||
# The m2m data won't be saved until save_m2m() is invoked on the form.
|
# The m2m data won't be saved until save_m2m() is invoked on the form.
|
||||||
|
@ -1559,11 +1559,11 @@ class ModelFormBasicTests(TestCase):
|
||||||
|
|
||||||
# The instance doesn't have m2m data yet
|
# The instance doesn't have m2m data yet
|
||||||
new_art = Article.objects.get(id=art_id_3)
|
new_art = Article.objects.get(id=art_id_3)
|
||||||
self.assertQuerysetEqual(new_art.categories.all(), [])
|
self.assertSequenceEqual(new_art.categories.all(), [])
|
||||||
|
|
||||||
# Save the m2m data on the form
|
# Save the m2m data on the form
|
||||||
f.save_m2m()
|
f.save_m2m()
|
||||||
self.assertQuerysetEqual(new_art.categories.order_by('name'), ["Entertainment", "It's a test"])
|
self.assertSequenceEqual(new_art.categories.order_by('name'), [self.c1, self.c2])
|
||||||
|
|
||||||
def test_custom_form_fields(self):
|
def test_custom_form_fields(self):
|
||||||
# Here, we define a custom ModelForm. Because it happens to have the same fields as
|
# Here, we define a custom ModelForm. Because it happens to have the same fields as
|
||||||
|
@ -1720,20 +1720,20 @@ class ModelMultipleChoiceFieldTests(TestCase):
|
||||||
f.clean(None)
|
f.clean(None)
|
||||||
with self.assertRaises(ValidationError):
|
with self.assertRaises(ValidationError):
|
||||||
f.clean([])
|
f.clean([])
|
||||||
self.assertQuerysetEqual(f.clean([self.c1.id]), ["Entertainment"])
|
self.assertCountEqual(f.clean([self.c1.id]), [self.c1])
|
||||||
self.assertQuerysetEqual(f.clean([self.c2.id]), ["It's a test"])
|
self.assertCountEqual(f.clean([self.c2.id]), [self.c2])
|
||||||
self.assertQuerysetEqual(f.clean([str(self.c1.id)]), ["Entertainment"])
|
self.assertCountEqual(f.clean([str(self.c1.id)]), [self.c1])
|
||||||
self.assertQuerysetEqual(
|
self.assertCountEqual(
|
||||||
f.clean([str(self.c1.id), str(self.c2.id)]),
|
f.clean([str(self.c1.id), str(self.c2.id)]),
|
||||||
["Entertainment", "It's a test"], ordered=False
|
[self.c1, self.c2],
|
||||||
)
|
)
|
||||||
self.assertQuerysetEqual(
|
self.assertCountEqual(
|
||||||
f.clean([self.c1.id, str(self.c2.id)]),
|
f.clean([self.c1.id, str(self.c2.id)]),
|
||||||
["Entertainment", "It's a test"], ordered=False
|
[self.c1, self.c2],
|
||||||
)
|
)
|
||||||
self.assertQuerysetEqual(
|
self.assertCountEqual(
|
||||||
f.clean((self.c1.id, str(self.c2.id))),
|
f.clean((self.c1.id, str(self.c2.id))),
|
||||||
["Entertainment", "It's a test"], ordered=False
|
[self.c1, self.c2],
|
||||||
)
|
)
|
||||||
with self.assertRaises(ValidationError):
|
with self.assertRaises(ValidationError):
|
||||||
f.clean(['100'])
|
f.clean(['100'])
|
||||||
|
@ -1755,7 +1755,7 @@ class ModelMultipleChoiceFieldTests(TestCase):
|
||||||
# this may create categories with primary keys up to 6. Use
|
# this may create categories with primary keys up to 6. Use
|
||||||
# a number that will not conflict.
|
# a number that will not conflict.
|
||||||
c6 = Category.objects.create(id=1006, name='Sixth', url='6th')
|
c6 = Category.objects.create(id=1006, name='Sixth', url='6th')
|
||||||
self.assertQuerysetEqual(f.clean([c6.id]), ["Sixth"])
|
self.assertCountEqual(f.clean([c6.id]), [c6])
|
||||||
|
|
||||||
# Delete a Category object *after* the ModelMultipleChoiceField has already been
|
# Delete a Category object *after* the ModelMultipleChoiceField has already been
|
||||||
# instantiated. This proves clean() checks the database during clean() rather
|
# instantiated. This proves clean() checks the database during clean() rather
|
||||||
|
@ -1780,7 +1780,7 @@ class ModelMultipleChoiceFieldTests(TestCase):
|
||||||
self.assertEqual(list(f.choices), [
|
self.assertEqual(list(f.choices), [
|
||||||
(self.c1.pk, 'Entertainment'),
|
(self.c1.pk, 'Entertainment'),
|
||||||
(self.c2.pk, "It's a test")])
|
(self.c2.pk, "It's a test")])
|
||||||
self.assertQuerysetEqual(f.clean([self.c2.id]), ["It's a test"])
|
self.assertSequenceEqual(f.clean([self.c2.id]), [self.c2])
|
||||||
with self.assertRaises(ValidationError):
|
with self.assertRaises(ValidationError):
|
||||||
f.clean([self.c3.id])
|
f.clean([self.c3.id])
|
||||||
with self.assertRaises(ValidationError):
|
with self.assertRaises(ValidationError):
|
||||||
|
@ -2512,7 +2512,7 @@ class OtherModelFormTests(TestCase):
|
||||||
|
|
||||||
def test_foreignkeys_which_use_to_field(self):
|
def test_foreignkeys_which_use_to_field(self):
|
||||||
apple = Inventory.objects.create(barcode=86, name='Apple')
|
apple = Inventory.objects.create(barcode=86, name='Apple')
|
||||||
Inventory.objects.create(barcode=22, name='Pear')
|
pear = Inventory.objects.create(barcode=22, name='Pear')
|
||||||
core = Inventory.objects.create(barcode=87, name='Core', parent=apple)
|
core = Inventory.objects.create(barcode=87, name='Core', parent=apple)
|
||||||
|
|
||||||
field = forms.ModelChoiceField(Inventory.objects.all(), to_field_name='barcode')
|
field = forms.ModelChoiceField(Inventory.objects.all(), to_field_name='barcode')
|
||||||
|
@ -2555,12 +2555,12 @@ class OtherModelFormTests(TestCase):
|
||||||
|
|
||||||
field = forms.ModelMultipleChoiceField(Inventory.objects.all(), to_field_name='barcode')
|
field = forms.ModelMultipleChoiceField(Inventory.objects.all(), to_field_name='barcode')
|
||||||
self.assertEqual(tuple(field.choices), ((86, 'Apple'), (87, 'Core'), (22, 'Pear')))
|
self.assertEqual(tuple(field.choices), ((86, 'Apple'), (87, 'Core'), (22, 'Pear')))
|
||||||
self.assertQuerysetEqual(field.clean([86]), ['Apple'])
|
self.assertSequenceEqual(field.clean([86]), [apple])
|
||||||
|
|
||||||
form = SelectInventoryForm({'items': [87, 22]})
|
form = SelectInventoryForm({'items': [87, 22]})
|
||||||
self.assertTrue(form.is_valid())
|
self.assertTrue(form.is_valid())
|
||||||
self.assertEqual(len(form.cleaned_data), 1)
|
self.assertEqual(len(form.cleaned_data), 1)
|
||||||
self.assertQuerysetEqual(form.cleaned_data['items'], ['Core', 'Pear'])
|
self.assertSequenceEqual(form.cleaned_data['items'], [core, pear])
|
||||||
|
|
||||||
def test_model_field_that_returns_none_to_exclude_itself_with_explicit_fields(self):
|
def test_model_field_that_returns_none_to_exclude_itself_with_explicit_fields(self):
|
||||||
self.assertEqual(list(CustomFieldForExclusionForm.base_fields), ['name'])
|
self.assertEqual(list(CustomFieldForExclusionForm.base_fields), ['name'])
|
||||||
|
|
|
@ -368,21 +368,19 @@ class ModelFormsetTest(TestCase):
|
||||||
instance.created = date.today()
|
instance.created = date.today()
|
||||||
instance.save()
|
instance.save()
|
||||||
formset.save_m2m()
|
formset.save_m2m()
|
||||||
self.assertQuerysetEqual(instances[0].authors.all(), [
|
self.assertSequenceEqual(
|
||||||
'<Author: Charles Baudelaire>',
|
instances[0].authors.all(),
|
||||||
'<Author: John Steinbeck>',
|
[author1, author4, author2, author3],
|
||||||
'<Author: Paul Verlaine>',
|
)
|
||||||
'<Author: Walt Whitman>',
|
|
||||||
])
|
|
||||||
|
|
||||||
def test_max_num(self):
|
def test_max_num(self):
|
||||||
# Test the behavior of max_num with model formsets. It should allow
|
# Test the behavior of max_num with model formsets. It should allow
|
||||||
# all existing related objects/inlines for a given object to be
|
# all existing related objects/inlines for a given object to be
|
||||||
# displayed, but not allow the creation of new inlines beyond max_num.
|
# displayed, but not allow the creation of new inlines beyond max_num.
|
||||||
|
|
||||||
Author.objects.create(name='Charles Baudelaire')
|
a1 = Author.objects.create(name='Charles Baudelaire')
|
||||||
Author.objects.create(name='Paul Verlaine')
|
a2 = Author.objects.create(name='Paul Verlaine')
|
||||||
Author.objects.create(name='Walt Whitman')
|
a3 = Author.objects.create(name='Walt Whitman')
|
||||||
|
|
||||||
qs = Author.objects.order_by('name')
|
qs = Author.objects.order_by('name')
|
||||||
|
|
||||||
|
@ -403,27 +401,15 @@ class ModelFormsetTest(TestCase):
|
||||||
|
|
||||||
AuthorFormSet = modelformset_factory(Author, fields="__all__", max_num=None)
|
AuthorFormSet = modelformset_factory(Author, fields="__all__", max_num=None)
|
||||||
formset = AuthorFormSet(queryset=qs)
|
formset = AuthorFormSet(queryset=qs)
|
||||||
self.assertQuerysetEqual(formset.get_queryset(), [
|
self.assertSequenceEqual(formset.get_queryset(), [a1, a2, a3])
|
||||||
'<Author: Charles Baudelaire>',
|
|
||||||
'<Author: Paul Verlaine>',
|
|
||||||
'<Author: Walt Whitman>',
|
|
||||||
])
|
|
||||||
|
|
||||||
AuthorFormSet = modelformset_factory(Author, fields="__all__", max_num=0)
|
AuthorFormSet = modelformset_factory(Author, fields="__all__", max_num=0)
|
||||||
formset = AuthorFormSet(queryset=qs)
|
formset = AuthorFormSet(queryset=qs)
|
||||||
self.assertQuerysetEqual(formset.get_queryset(), [
|
self.assertSequenceEqual(formset.get_queryset(), [a1, a2, a3])
|
||||||
'<Author: Charles Baudelaire>',
|
|
||||||
'<Author: Paul Verlaine>',
|
|
||||||
'<Author: Walt Whitman>',
|
|
||||||
])
|
|
||||||
|
|
||||||
AuthorFormSet = modelformset_factory(Author, fields="__all__", max_num=4)
|
AuthorFormSet = modelformset_factory(Author, fields="__all__", max_num=4)
|
||||||
formset = AuthorFormSet(queryset=qs)
|
formset = AuthorFormSet(queryset=qs)
|
||||||
self.assertQuerysetEqual(formset.get_queryset(), [
|
self.assertSequenceEqual(formset.get_queryset(), [a1, a2, a3])
|
||||||
'<Author: Charles Baudelaire>',
|
|
||||||
'<Author: Paul Verlaine>',
|
|
||||||
'<Author: Walt Whitman>',
|
|
||||||
])
|
|
||||||
|
|
||||||
def test_min_num(self):
|
def test_min_num(self):
|
||||||
# Test the behavior of min_num with model formsets. It should be
|
# Test the behavior of min_num with model formsets. It should be
|
||||||
|
@ -633,7 +619,7 @@ class ModelFormsetTest(TestCase):
|
||||||
self.assertEqual(len(saved), 1)
|
self.assertEqual(len(saved), 1)
|
||||||
book1, = saved
|
book1, = saved
|
||||||
self.assertEqual(book1, Book.objects.get(title='Les Fleurs du Mal'))
|
self.assertEqual(book1, Book.objects.get(title='Les Fleurs du Mal'))
|
||||||
self.assertQuerysetEqual(author.book_set.all(), ['<Book: Les Fleurs du Mal>'])
|
self.assertSequenceEqual(author.book_set.all(), [book1])
|
||||||
|
|
||||||
# Now that we've added a book to Charles Baudelaire, let's try adding
|
# Now that we've added a book to Charles Baudelaire, let's try adding
|
||||||
# another one. This time though, an edit form will be available for
|
# another one. This time though, an edit form will be available for
|
||||||
|
@ -689,10 +675,7 @@ class ModelFormsetTest(TestCase):
|
||||||
|
|
||||||
# As you can see, 'Les Paradis Artificiels' is now a book belonging to
|
# As you can see, 'Les Paradis Artificiels' is now a book belonging to
|
||||||
# Charles Baudelaire.
|
# Charles Baudelaire.
|
||||||
self.assertQuerysetEqual(author.book_set.order_by('title'), [
|
self.assertSequenceEqual(author.book_set.order_by('title'), [book1, book2])
|
||||||
'<Book: Les Fleurs du Mal>',
|
|
||||||
'<Book: Les Paradis Artificiels>',
|
|
||||||
])
|
|
||||||
|
|
||||||
def test_inline_formsets_save_as_new(self):
|
def test_inline_formsets_save_as_new(self):
|
||||||
# The save_as_new parameter lets you re-associate the data to a new
|
# The save_as_new parameter lets you re-associate the data to a new
|
||||||
|
@ -1722,7 +1705,7 @@ class ModelFormsetTest(TestCase):
|
||||||
formset.save()
|
formset.save()
|
||||||
# The name of other_author shouldn't be changed and new models aren't
|
# The name of other_author shouldn't be changed and new models aren't
|
||||||
# created.
|
# created.
|
||||||
self.assertQuerysetEqual(Author.objects.all(), ['<Author: Charles>', '<Author: Walt>'])
|
self.assertSequenceEqual(Author.objects.all(), [author, other_author])
|
||||||
|
|
||||||
def test_validation_without_id(self):
|
def test_validation_without_id(self):
|
||||||
AuthorFormSet = modelformset_factory(Author, fields='__all__')
|
AuthorFormSet = modelformset_factory(Author, fields='__all__')
|
||||||
|
|
|
@ -246,7 +246,10 @@ class InlineFormsetTests(TestCase):
|
||||||
formset.save()
|
formset.save()
|
||||||
self.assertQuerysetEqual(
|
self.assertQuerysetEqual(
|
||||||
dalnet.host_set.order_by("hostname"),
|
dalnet.host_set.order_by("hostname"),
|
||||||
["<Host: matrix.de.eu.dal.net>", "<Host: tranquility.hub.dal.net>"]
|
Host.objects.filter(hostname__in=[
|
||||||
|
'matrix.de.eu.dal.net',
|
||||||
|
'tranquility.hub.dal.net',
|
||||||
|
]).order_by('hostname'),
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_initial_data(self):
|
def test_initial_data(self):
|
||||||
|
|
|
@ -46,15 +46,10 @@ class OneToOneTests(TestCase):
|
||||||
|
|
||||||
def test_manager_all(self):
|
def test_manager_all(self):
|
||||||
# Restaurant.objects.all() just returns the Restaurants, not the Places.
|
# Restaurant.objects.all() just returns the Restaurants, not the Places.
|
||||||
self.assertQuerysetEqual(Restaurant.objects.all(), [
|
self.assertSequenceEqual(Restaurant.objects.all(), [self.r1])
|
||||||
'<Restaurant: Demon Dogs the restaurant>',
|
|
||||||
])
|
|
||||||
# Place.objects.all() returns all Places, regardless of whether they
|
# Place.objects.all() returns all Places, regardless of whether they
|
||||||
# have Restaurants.
|
# have Restaurants.
|
||||||
self.assertQuerysetEqual(Place.objects.order_by('name'), [
|
self.assertSequenceEqual(Place.objects.order_by('name'), [self.p2, self.p1])
|
||||||
'<Place: Ace Hardware the place>',
|
|
||||||
'<Place: Demon Dogs the place>',
|
|
||||||
])
|
|
||||||
|
|
||||||
def test_manager_get(self):
|
def test_manager_get(self):
|
||||||
def assert_get_restaurant(**params):
|
def assert_get_restaurant(**params):
|
||||||
|
@ -92,9 +87,7 @@ class OneToOneTests(TestCase):
|
||||||
|
|
||||||
# Query the waiters
|
# Query the waiters
|
||||||
def assert_filter_waiters(**params):
|
def assert_filter_waiters(**params):
|
||||||
self.assertQuerysetEqual(Waiter.objects.filter(**params), [
|
self.assertSequenceEqual(Waiter.objects.filter(**params), [w])
|
||||||
'<Waiter: Joe the waiter at Demon Dogs the restaurant>'
|
|
||||||
])
|
|
||||||
assert_filter_waiters(restaurant__place__exact=self.p1.pk)
|
assert_filter_waiters(restaurant__place__exact=self.p1.pk)
|
||||||
assert_filter_waiters(restaurant__place__exact=self.p1)
|
assert_filter_waiters(restaurant__place__exact=self.p1)
|
||||||
assert_filter_waiters(restaurant__place__pk=self.p1.pk)
|
assert_filter_waiters(restaurant__place__pk=self.p1.pk)
|
||||||
|
@ -169,10 +162,7 @@ class OneToOneTests(TestCase):
|
||||||
f = Favorites(name='Fred')
|
f = Favorites(name='Fred')
|
||||||
f.save()
|
f.save()
|
||||||
f.restaurants.set([self.r1])
|
f.restaurants.set([self.r1])
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(f.restaurants.all(), [self.r1])
|
||||||
f.restaurants.all(),
|
|
||||||
['<Restaurant: Demon Dogs the restaurant>']
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_reverse_object_cache(self):
|
def test_reverse_object_cache(self):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -433,21 +433,17 @@ class ModelPaginationTests(TestCase):
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
# Prepare a list of objects for pagination.
|
# Prepare a list of objects for pagination.
|
||||||
for x in range(1, 10):
|
pub_date = datetime(2005, 7, 29)
|
||||||
a = Article(headline='Article %s' % x, pub_date=datetime(2005, 7, 29))
|
cls.articles = [
|
||||||
a.save()
|
Article.objects.create(headline=f'Article {x}', pub_date=pub_date)
|
||||||
|
for x in range(1, 10)
|
||||||
|
]
|
||||||
|
|
||||||
def test_first_page(self):
|
def test_first_page(self):
|
||||||
paginator = Paginator(Article.objects.order_by('id'), 5)
|
paginator = Paginator(Article.objects.order_by('id'), 5)
|
||||||
p = paginator.page(1)
|
p = paginator.page(1)
|
||||||
self.assertEqual("<Page 1 of 2>", str(p))
|
self.assertEqual("<Page 1 of 2>", str(p))
|
||||||
self.assertQuerysetEqual(p.object_list, [
|
self.assertSequenceEqual(p.object_list, self.articles[:5])
|
||||||
"<Article: Article 1>",
|
|
||||||
"<Article: Article 2>",
|
|
||||||
"<Article: Article 3>",
|
|
||||||
"<Article: Article 4>",
|
|
||||||
"<Article: Article 5>"
|
|
||||||
])
|
|
||||||
self.assertTrue(p.has_next())
|
self.assertTrue(p.has_next())
|
||||||
self.assertFalse(p.has_previous())
|
self.assertFalse(p.has_previous())
|
||||||
self.assertTrue(p.has_other_pages())
|
self.assertTrue(p.has_other_pages())
|
||||||
|
@ -461,12 +457,7 @@ class ModelPaginationTests(TestCase):
|
||||||
paginator = Paginator(Article.objects.order_by('id'), 5)
|
paginator = Paginator(Article.objects.order_by('id'), 5)
|
||||||
p = paginator.page(2)
|
p = paginator.page(2)
|
||||||
self.assertEqual("<Page 2 of 2>", str(p))
|
self.assertEqual("<Page 2 of 2>", str(p))
|
||||||
self.assertQuerysetEqual(p.object_list, [
|
self.assertSequenceEqual(p.object_list, self.articles[5:])
|
||||||
"<Article: Article 6>",
|
|
||||||
"<Article: Article 7>",
|
|
||||||
"<Article: Article 8>",
|
|
||||||
"<Article: Article 9>"
|
|
||||||
])
|
|
||||||
self.assertFalse(p.has_next())
|
self.assertFalse(p.has_next())
|
||||||
self.assertTrue(p.has_previous())
|
self.assertTrue(p.has_previous())
|
||||||
self.assertTrue(p.has_other_pages())
|
self.assertTrue(p.has_other_pages())
|
||||||
|
@ -494,12 +485,8 @@ class ModelPaginationTests(TestCase):
|
||||||
self.assertNotIsInstance(p.object_list, list)
|
self.assertNotIsInstance(p.object_list, list)
|
||||||
|
|
||||||
# Make sure slicing the Page object with numbers and slice objects work.
|
# Make sure slicing the Page object with numbers and slice objects work.
|
||||||
self.assertEqual(p[0], Article.objects.get(headline='Article 1'))
|
self.assertEqual(p[0], self.articles[0])
|
||||||
self.assertQuerysetEqual(p[slice(2)], [
|
self.assertSequenceEqual(p[slice(2)], self.articles[:2])
|
||||||
"<Article: Article 1>",
|
|
||||||
"<Article: Article 2>",
|
|
||||||
]
|
|
||||||
)
|
|
||||||
# After __getitem__ is called, object_list is a list
|
# After __getitem__ is called, object_list is a list
|
||||||
self.assertIsInstance(p.object_list, list)
|
self.assertIsInstance(p.object_list, list)
|
||||||
|
|
||||||
|
|
|
@ -76,7 +76,7 @@ class PrefetchRelatedTests(TestDataMixin, TestCase):
|
||||||
[list(b.first_time_authors.all())
|
[list(b.first_time_authors.all())
|
||||||
for b in Book.objects.prefetch_related('first_time_authors')]
|
for b in Book.objects.prefetch_related('first_time_authors')]
|
||||||
|
|
||||||
self.assertQuerysetEqual(self.book2.authors.all(), ["<Author: Charlotte>"])
|
self.assertSequenceEqual(self.book2.authors.all(), [self.author1])
|
||||||
|
|
||||||
def test_onetoone_reverse_no_match(self):
|
def test_onetoone_reverse_no_match(self):
|
||||||
# Regression for #17439
|
# Regression for #17439
|
||||||
|
@ -1580,4 +1580,4 @@ class ReadPrefetchedObjectsCacheTests(TestCase):
|
||||||
)
|
)
|
||||||
with self.assertNumQueries(4):
|
with self.assertNumQueries(4):
|
||||||
# AuthorWithAge -> Author -> FavoriteAuthors, Book
|
# AuthorWithAge -> Author -> FavoriteAuthors, Book
|
||||||
self.assertQuerysetEqual(authors, ['<AuthorWithAge: Rousseau>', '<AuthorWithAge: Voltaire>'])
|
self.assertSequenceEqual(authors, [self.author1, self.author2])
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -100,12 +100,12 @@ class SelectRelatedRegressTests(TestCase):
|
||||||
def test_multi_table_inheritance(self):
|
def test_multi_table_inheritance(self):
|
||||||
""" Exercising select_related() with multi-table model inheritance. """
|
""" Exercising select_related() with multi-table model inheritance. """
|
||||||
c1 = Child.objects.create(name="child1", value=42)
|
c1 = Child.objects.create(name="child1", value=42)
|
||||||
Item.objects.create(name="item1", child=c1)
|
i1 = Item.objects.create(name="item1", child=c1)
|
||||||
Item.objects.create(name="item2")
|
i2 = Item.objects.create(name="item2")
|
||||||
|
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(
|
||||||
Item.objects.select_related("child").order_by("name"),
|
Item.objects.select_related("child").order_by("name"),
|
||||||
["<Item: item1>", "<Item: item2>"]
|
[i1, i2],
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_regression_12851(self):
|
def test_regression_12851(self):
|
||||||
|
|
|
@ -16,8 +16,8 @@ from django.forms import EmailField, IntegerField
|
||||||
from django.http import HttpResponse
|
from django.http import HttpResponse
|
||||||
from django.template.loader import render_to_string
|
from django.template.loader import render_to_string
|
||||||
from django.test import (
|
from django.test import (
|
||||||
SimpleTestCase, TestCase, TransactionTestCase, skipIfDBFeature,
|
SimpleTestCase, TestCase, TransactionTestCase, ignore_warnings,
|
||||||
skipUnlessDBFeature,
|
skipIfDBFeature, skipUnlessDBFeature,
|
||||||
)
|
)
|
||||||
from django.test.html import HTMLParseError, parse_html
|
from django.test.html import HTMLParseError, parse_html
|
||||||
from django.test.utils import (
|
from django.test.utils import (
|
||||||
|
@ -25,6 +25,7 @@ from django.test.utils import (
|
||||||
override_settings, setup_test_environment,
|
override_settings, setup_test_environment,
|
||||||
)
|
)
|
||||||
from django.urls import NoReverseMatch, path, reverse, reverse_lazy
|
from django.urls import NoReverseMatch, path, reverse, reverse_lazy
|
||||||
|
from django.utils.deprecation import RemovedInDjango41Warning
|
||||||
|
|
||||||
from .models import Car, Person, PossessedCar
|
from .models import Car, Person, PossessedCar
|
||||||
from .views import empty_response
|
from .views import empty_response
|
||||||
|
@ -243,19 +244,34 @@ class AssertQuerysetEqualTests(TestCase):
|
||||||
cls.p1 = Person.objects.create(name='p1')
|
cls.p1 = Person.objects.create(name='p1')
|
||||||
cls.p2 = Person.objects.create(name='p2')
|
cls.p2 = Person.objects.create(name='p2')
|
||||||
|
|
||||||
|
def test_empty(self):
|
||||||
|
self.assertQuerysetEqual(Person.objects.filter(name='p3'), [])
|
||||||
|
|
||||||
def test_ordered(self):
|
def test_ordered(self):
|
||||||
self.assertQuerysetEqual(
|
self.assertQuerysetEqual(
|
||||||
Person.objects.all().order_by('name'),
|
Person.objects.all().order_by('name'),
|
||||||
[repr(self.p1), repr(self.p2)]
|
[self.p1, self.p2],
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_unordered(self):
|
def test_unordered(self):
|
||||||
self.assertQuerysetEqual(
|
self.assertQuerysetEqual(
|
||||||
Person.objects.all().order_by('name'),
|
Person.objects.all().order_by('name'),
|
||||||
[repr(self.p2), repr(self.p1)],
|
[self.p2, self.p1],
|
||||||
ordered=False
|
ordered=False
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_queryset(self):
|
||||||
|
self.assertQuerysetEqual(
|
||||||
|
Person.objects.all().order_by('name'),
|
||||||
|
Person.objects.all().order_by('name'),
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_flat_values_list(self):
|
||||||
|
self.assertQuerysetEqual(
|
||||||
|
Person.objects.all().order_by('name').values_list('name', flat=True),
|
||||||
|
['p1', 'p2'],
|
||||||
|
)
|
||||||
|
|
||||||
def test_transform(self):
|
def test_transform(self):
|
||||||
self.assertQuerysetEqual(
|
self.assertQuerysetEqual(
|
||||||
Person.objects.all().order_by('name'),
|
Person.objects.all().order_by('name'),
|
||||||
|
@ -263,6 +279,13 @@ class AssertQuerysetEqualTests(TestCase):
|
||||||
transform=lambda x: x.pk
|
transform=lambda x: x.pk
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_repr_transform(self):
|
||||||
|
self.assertQuerysetEqual(
|
||||||
|
Person.objects.all().order_by('name'),
|
||||||
|
[repr(self.p1), repr(self.p2)],
|
||||||
|
transform=repr,
|
||||||
|
)
|
||||||
|
|
||||||
def test_undefined_order(self):
|
def test_undefined_order(self):
|
||||||
# Using an unordered queryset with more than one ordered value
|
# Using an unordered queryset with more than one ordered value
|
||||||
# is an error.
|
# is an error.
|
||||||
|
@ -270,13 +293,10 @@ class AssertQuerysetEqualTests(TestCase):
|
||||||
with self.assertRaisesMessage(ValueError, msg):
|
with self.assertRaisesMessage(ValueError, msg):
|
||||||
self.assertQuerysetEqual(
|
self.assertQuerysetEqual(
|
||||||
Person.objects.all(),
|
Person.objects.all(),
|
||||||
[repr(self.p1), repr(self.p2)]
|
[self.p1, self.p2],
|
||||||
)
|
)
|
||||||
# No error for one value.
|
# No error for one value.
|
||||||
self.assertQuerysetEqual(
|
self.assertQuerysetEqual(Person.objects.filter(name='p1'), [self.p1])
|
||||||
Person.objects.filter(name='p1'),
|
|
||||||
[repr(self.p1)]
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_repeated_values(self):
|
def test_repeated_values(self):
|
||||||
"""
|
"""
|
||||||
|
@ -296,16 +316,42 @@ class AssertQuerysetEqualTests(TestCase):
|
||||||
with self.assertRaises(AssertionError):
|
with self.assertRaises(AssertionError):
|
||||||
self.assertQuerysetEqual(
|
self.assertQuerysetEqual(
|
||||||
self.p1.cars.all(),
|
self.p1.cars.all(),
|
||||||
[repr(batmobile), repr(k2000)],
|
[batmobile, k2000],
|
||||||
ordered=False
|
ordered=False
|
||||||
)
|
)
|
||||||
self.assertQuerysetEqual(
|
self.assertQuerysetEqual(
|
||||||
self.p1.cars.all(),
|
self.p1.cars.all(),
|
||||||
[repr(batmobile)] * 2 + [repr(k2000)] * 4,
|
[batmobile] * 2 + [k2000] * 4,
|
||||||
ordered=False
|
ordered=False
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class AssertQuerysetEqualDeprecationTests(TestCase):
|
||||||
|
@classmethod
|
||||||
|
def setUpTestData(cls):
|
||||||
|
cls.p1 = Person.objects.create(name='p1')
|
||||||
|
cls.p2 = Person.objects.create(name='p2')
|
||||||
|
|
||||||
|
@ignore_warnings(category=RemovedInDjango41Warning)
|
||||||
|
def test_str_values(self):
|
||||||
|
self.assertQuerysetEqual(
|
||||||
|
Person.objects.all().order_by('name'),
|
||||||
|
[repr(self.p1), repr(self.p2)],
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_str_values_warning(self):
|
||||||
|
msg = (
|
||||||
|
"In Django 4.1, repr() will not be called automatically on a "
|
||||||
|
"queryset when compared to string values. Set an explicit "
|
||||||
|
"'transform' to silence this warning."
|
||||||
|
)
|
||||||
|
with self.assertRaisesMessage(RemovedInDjango41Warning, msg):
|
||||||
|
self.assertQuerysetEqual(
|
||||||
|
Person.objects.all().order_by('name'),
|
||||||
|
[repr(self.p1), repr(self.p2)],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@override_settings(ROOT_URLCONF='test_utils.urls')
|
@override_settings(ROOT_URLCONF='test_utils.urls')
|
||||||
class CaptureQueriesContextManagerTests(TestCase):
|
class CaptureQueriesContextManagerTests(TestCase):
|
||||||
|
|
||||||
|
|
|
@ -32,9 +32,9 @@ class AtomicTests(TransactionTestCase):
|
||||||
def test_decorator_syntax_commit(self):
|
def test_decorator_syntax_commit(self):
|
||||||
@transaction.atomic
|
@transaction.atomic
|
||||||
def make_reporter():
|
def make_reporter():
|
||||||
Reporter.objects.create(first_name="Tintin")
|
return Reporter.objects.create(first_name="Tintin")
|
||||||
make_reporter()
|
reporter = make_reporter()
|
||||||
self.assertQuerysetEqual(Reporter.objects.all(), ['<Reporter: Tintin>'])
|
self.assertSequenceEqual(Reporter.objects.all(), [reporter])
|
||||||
|
|
||||||
def test_decorator_syntax_rollback(self):
|
def test_decorator_syntax_rollback(self):
|
||||||
@transaction.atomic
|
@transaction.atomic
|
||||||
|
@ -43,14 +43,14 @@ class AtomicTests(TransactionTestCase):
|
||||||
raise Exception("Oops, that's his last name")
|
raise Exception("Oops, that's his last name")
|
||||||
with self.assertRaisesMessage(Exception, "Oops"):
|
with self.assertRaisesMessage(Exception, "Oops"):
|
||||||
make_reporter()
|
make_reporter()
|
||||||
self.assertQuerysetEqual(Reporter.objects.all(), [])
|
self.assertSequenceEqual(Reporter.objects.all(), [])
|
||||||
|
|
||||||
def test_alternate_decorator_syntax_commit(self):
|
def test_alternate_decorator_syntax_commit(self):
|
||||||
@transaction.atomic()
|
@transaction.atomic()
|
||||||
def make_reporter():
|
def make_reporter():
|
||||||
Reporter.objects.create(first_name="Tintin")
|
return Reporter.objects.create(first_name="Tintin")
|
||||||
make_reporter()
|
reporter = make_reporter()
|
||||||
self.assertQuerysetEqual(Reporter.objects.all(), ['<Reporter: Tintin>'])
|
self.assertSequenceEqual(Reporter.objects.all(), [reporter])
|
||||||
|
|
||||||
def test_alternate_decorator_syntax_rollback(self):
|
def test_alternate_decorator_syntax_rollback(self):
|
||||||
@transaction.atomic()
|
@transaction.atomic()
|
||||||
|
@ -59,38 +59,35 @@ class AtomicTests(TransactionTestCase):
|
||||||
raise Exception("Oops, that's his last name")
|
raise Exception("Oops, that's his last name")
|
||||||
with self.assertRaisesMessage(Exception, "Oops"):
|
with self.assertRaisesMessage(Exception, "Oops"):
|
||||||
make_reporter()
|
make_reporter()
|
||||||
self.assertQuerysetEqual(Reporter.objects.all(), [])
|
self.assertSequenceEqual(Reporter.objects.all(), [])
|
||||||
|
|
||||||
def test_commit(self):
|
def test_commit(self):
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
Reporter.objects.create(first_name="Tintin")
|
reporter = Reporter.objects.create(first_name="Tintin")
|
||||||
self.assertQuerysetEqual(Reporter.objects.all(), ['<Reporter: Tintin>'])
|
self.assertSequenceEqual(Reporter.objects.all(), [reporter])
|
||||||
|
|
||||||
def test_rollback(self):
|
def test_rollback(self):
|
||||||
with self.assertRaisesMessage(Exception, "Oops"):
|
with self.assertRaisesMessage(Exception, "Oops"):
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
Reporter.objects.create(first_name="Haddock")
|
Reporter.objects.create(first_name="Haddock")
|
||||||
raise Exception("Oops, that's his last name")
|
raise Exception("Oops, that's his last name")
|
||||||
self.assertQuerysetEqual(Reporter.objects.all(), [])
|
self.assertSequenceEqual(Reporter.objects.all(), [])
|
||||||
|
|
||||||
def test_nested_commit_commit(self):
|
def test_nested_commit_commit(self):
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
Reporter.objects.create(first_name="Tintin")
|
reporter1 = Reporter.objects.create(first_name="Tintin")
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
Reporter.objects.create(first_name="Archibald", last_name="Haddock")
|
reporter2 = Reporter.objects.create(first_name="Archibald", last_name="Haddock")
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(Reporter.objects.all(), [reporter2, reporter1])
|
||||||
Reporter.objects.all(),
|
|
||||||
['<Reporter: Archibald Haddock>', '<Reporter: Tintin>']
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_nested_commit_rollback(self):
|
def test_nested_commit_rollback(self):
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
Reporter.objects.create(first_name="Tintin")
|
reporter = Reporter.objects.create(first_name="Tintin")
|
||||||
with self.assertRaisesMessage(Exception, "Oops"):
|
with self.assertRaisesMessage(Exception, "Oops"):
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
Reporter.objects.create(first_name="Haddock")
|
Reporter.objects.create(first_name="Haddock")
|
||||||
raise Exception("Oops, that's his last name")
|
raise Exception("Oops, that's his last name")
|
||||||
self.assertQuerysetEqual(Reporter.objects.all(), ['<Reporter: Tintin>'])
|
self.assertSequenceEqual(Reporter.objects.all(), [reporter])
|
||||||
|
|
||||||
def test_nested_rollback_commit(self):
|
def test_nested_rollback_commit(self):
|
||||||
with self.assertRaisesMessage(Exception, "Oops"):
|
with self.assertRaisesMessage(Exception, "Oops"):
|
||||||
|
@ -99,7 +96,7 @@ class AtomicTests(TransactionTestCase):
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
Reporter.objects.create(last_name="Haddock")
|
Reporter.objects.create(last_name="Haddock")
|
||||||
raise Exception("Oops, that's his first name")
|
raise Exception("Oops, that's his first name")
|
||||||
self.assertQuerysetEqual(Reporter.objects.all(), [])
|
self.assertSequenceEqual(Reporter.objects.all(), [])
|
||||||
|
|
||||||
def test_nested_rollback_rollback(self):
|
def test_nested_rollback_rollback(self):
|
||||||
with self.assertRaisesMessage(Exception, "Oops"):
|
with self.assertRaisesMessage(Exception, "Oops"):
|
||||||
|
@ -110,17 +107,14 @@ class AtomicTests(TransactionTestCase):
|
||||||
Reporter.objects.create(first_name="Haddock")
|
Reporter.objects.create(first_name="Haddock")
|
||||||
raise Exception("Oops, that's his last name")
|
raise Exception("Oops, that's his last name")
|
||||||
raise Exception("Oops, that's his first name")
|
raise Exception("Oops, that's his first name")
|
||||||
self.assertQuerysetEqual(Reporter.objects.all(), [])
|
self.assertSequenceEqual(Reporter.objects.all(), [])
|
||||||
|
|
||||||
def test_merged_commit_commit(self):
|
def test_merged_commit_commit(self):
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
Reporter.objects.create(first_name="Tintin")
|
reporter1 = Reporter.objects.create(first_name="Tintin")
|
||||||
with transaction.atomic(savepoint=False):
|
with transaction.atomic(savepoint=False):
|
||||||
Reporter.objects.create(first_name="Archibald", last_name="Haddock")
|
reporter2 = Reporter.objects.create(first_name="Archibald", last_name="Haddock")
|
||||||
self.assertQuerysetEqual(
|
self.assertSequenceEqual(Reporter.objects.all(), [reporter2, reporter1])
|
||||||
Reporter.objects.all(),
|
|
||||||
['<Reporter: Archibald Haddock>', '<Reporter: Tintin>']
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_merged_commit_rollback(self):
|
def test_merged_commit_rollback(self):
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
|
@ -130,7 +124,7 @@ class AtomicTests(TransactionTestCase):
|
||||||
Reporter.objects.create(first_name="Haddock")
|
Reporter.objects.create(first_name="Haddock")
|
||||||
raise Exception("Oops, that's his last name")
|
raise Exception("Oops, that's his last name")
|
||||||
# Writes in the outer block are rolled back too.
|
# Writes in the outer block are rolled back too.
|
||||||
self.assertQuerysetEqual(Reporter.objects.all(), [])
|
self.assertSequenceEqual(Reporter.objects.all(), [])
|
||||||
|
|
||||||
def test_merged_rollback_commit(self):
|
def test_merged_rollback_commit(self):
|
||||||
with self.assertRaisesMessage(Exception, "Oops"):
|
with self.assertRaisesMessage(Exception, "Oops"):
|
||||||
|
@ -139,7 +133,7 @@ class AtomicTests(TransactionTestCase):
|
||||||
with transaction.atomic(savepoint=False):
|
with transaction.atomic(savepoint=False):
|
||||||
Reporter.objects.create(last_name="Haddock")
|
Reporter.objects.create(last_name="Haddock")
|
||||||
raise Exception("Oops, that's his first name")
|
raise Exception("Oops, that's his first name")
|
||||||
self.assertQuerysetEqual(Reporter.objects.all(), [])
|
self.assertSequenceEqual(Reporter.objects.all(), [])
|
||||||
|
|
||||||
def test_merged_rollback_rollback(self):
|
def test_merged_rollback_rollback(self):
|
||||||
with self.assertRaisesMessage(Exception, "Oops"):
|
with self.assertRaisesMessage(Exception, "Oops"):
|
||||||
|
@ -150,25 +144,25 @@ class AtomicTests(TransactionTestCase):
|
||||||
Reporter.objects.create(first_name="Haddock")
|
Reporter.objects.create(first_name="Haddock")
|
||||||
raise Exception("Oops, that's his last name")
|
raise Exception("Oops, that's his last name")
|
||||||
raise Exception("Oops, that's his first name")
|
raise Exception("Oops, that's his first name")
|
||||||
self.assertQuerysetEqual(Reporter.objects.all(), [])
|
self.assertSequenceEqual(Reporter.objects.all(), [])
|
||||||
|
|
||||||
def test_reuse_commit_commit(self):
|
def test_reuse_commit_commit(self):
|
||||||
atomic = transaction.atomic()
|
atomic = transaction.atomic()
|
||||||
with atomic:
|
with atomic:
|
||||||
Reporter.objects.create(first_name="Tintin")
|
reporter1 = Reporter.objects.create(first_name="Tintin")
|
||||||
with atomic:
|
with atomic:
|
||||||
Reporter.objects.create(first_name="Archibald", last_name="Haddock")
|
reporter2 = Reporter.objects.create(first_name="Archibald", last_name="Haddock")
|
||||||
self.assertQuerysetEqual(Reporter.objects.all(), ['<Reporter: Archibald Haddock>', '<Reporter: Tintin>'])
|
self.assertSequenceEqual(Reporter.objects.all(), [reporter2, reporter1])
|
||||||
|
|
||||||
def test_reuse_commit_rollback(self):
|
def test_reuse_commit_rollback(self):
|
||||||
atomic = transaction.atomic()
|
atomic = transaction.atomic()
|
||||||
with atomic:
|
with atomic:
|
||||||
Reporter.objects.create(first_name="Tintin")
|
reporter = Reporter.objects.create(first_name="Tintin")
|
||||||
with self.assertRaisesMessage(Exception, "Oops"):
|
with self.assertRaisesMessage(Exception, "Oops"):
|
||||||
with atomic:
|
with atomic:
|
||||||
Reporter.objects.create(first_name="Haddock")
|
Reporter.objects.create(first_name="Haddock")
|
||||||
raise Exception("Oops, that's his last name")
|
raise Exception("Oops, that's his last name")
|
||||||
self.assertQuerysetEqual(Reporter.objects.all(), ['<Reporter: Tintin>'])
|
self.assertSequenceEqual(Reporter.objects.all(), [reporter])
|
||||||
|
|
||||||
def test_reuse_rollback_commit(self):
|
def test_reuse_rollback_commit(self):
|
||||||
atomic = transaction.atomic()
|
atomic = transaction.atomic()
|
||||||
|
@ -178,7 +172,7 @@ class AtomicTests(TransactionTestCase):
|
||||||
with atomic:
|
with atomic:
|
||||||
Reporter.objects.create(last_name="Haddock")
|
Reporter.objects.create(last_name="Haddock")
|
||||||
raise Exception("Oops, that's his first name")
|
raise Exception("Oops, that's his first name")
|
||||||
self.assertQuerysetEqual(Reporter.objects.all(), [])
|
self.assertSequenceEqual(Reporter.objects.all(), [])
|
||||||
|
|
||||||
def test_reuse_rollback_rollback(self):
|
def test_reuse_rollback_rollback(self):
|
||||||
atomic = transaction.atomic()
|
atomic = transaction.atomic()
|
||||||
|
@ -190,7 +184,7 @@ class AtomicTests(TransactionTestCase):
|
||||||
Reporter.objects.create(first_name="Haddock")
|
Reporter.objects.create(first_name="Haddock")
|
||||||
raise Exception("Oops, that's his last name")
|
raise Exception("Oops, that's his last name")
|
||||||
raise Exception("Oops, that's his first name")
|
raise Exception("Oops, that's his first name")
|
||||||
self.assertQuerysetEqual(Reporter.objects.all(), [])
|
self.assertSequenceEqual(Reporter.objects.all(), [])
|
||||||
|
|
||||||
def test_force_rollback(self):
|
def test_force_rollback(self):
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
|
@ -198,11 +192,11 @@ class AtomicTests(TransactionTestCase):
|
||||||
# atomic block shouldn't rollback, but force it.
|
# atomic block shouldn't rollback, but force it.
|
||||||
self.assertFalse(transaction.get_rollback())
|
self.assertFalse(transaction.get_rollback())
|
||||||
transaction.set_rollback(True)
|
transaction.set_rollback(True)
|
||||||
self.assertQuerysetEqual(Reporter.objects.all(), [])
|
self.assertSequenceEqual(Reporter.objects.all(), [])
|
||||||
|
|
||||||
def test_prevent_rollback(self):
|
def test_prevent_rollback(self):
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
Reporter.objects.create(first_name="Tintin")
|
reporter = Reporter.objects.create(first_name="Tintin")
|
||||||
sid = transaction.savepoint()
|
sid = transaction.savepoint()
|
||||||
# trigger a database error inside an inner atomic without savepoint
|
# trigger a database error inside an inner atomic without savepoint
|
||||||
with self.assertRaises(DatabaseError):
|
with self.assertRaises(DatabaseError):
|
||||||
|
@ -214,7 +208,7 @@ class AtomicTests(TransactionTestCase):
|
||||||
self.assertTrue(transaction.get_rollback())
|
self.assertTrue(transaction.get_rollback())
|
||||||
transaction.set_rollback(False)
|
transaction.set_rollback(False)
|
||||||
transaction.savepoint_rollback(sid)
|
transaction.savepoint_rollback(sid)
|
||||||
self.assertQuerysetEqual(Reporter.objects.all(), ['<Reporter: Tintin>'])
|
self.assertSequenceEqual(Reporter.objects.all(), [reporter])
|
||||||
|
|
||||||
|
|
||||||
class AtomicInsideTransactionTests(AtomicTests):
|
class AtomicInsideTransactionTests(AtomicTests):
|
||||||
|
@ -269,11 +263,11 @@ class AtomicMergeTests(TransactionTestCase):
|
||||||
self.assertEqual(Reporter.objects.count(), 3)
|
self.assertEqual(Reporter.objects.count(), 3)
|
||||||
transaction.set_rollback(True)
|
transaction.set_rollback(True)
|
||||||
# The first block has a savepoint and must roll back.
|
# The first block has a savepoint and must roll back.
|
||||||
self.assertQuerysetEqual(Reporter.objects.all(), [])
|
self.assertSequenceEqual(Reporter.objects.all(), [])
|
||||||
|
|
||||||
def test_merged_inner_savepoint_rollback(self):
|
def test_merged_inner_savepoint_rollback(self):
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
Reporter.objects.create(first_name="Tintin")
|
reporter = Reporter.objects.create(first_name="Tintin")
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
Reporter.objects.create(first_name="Archibald", last_name="Haddock")
|
Reporter.objects.create(first_name="Archibald", last_name="Haddock")
|
||||||
with self.assertRaisesMessage(Exception, "Oops"):
|
with self.assertRaisesMessage(Exception, "Oops"):
|
||||||
|
@ -288,7 +282,7 @@ class AtomicMergeTests(TransactionTestCase):
|
||||||
transaction.set_rollback(True)
|
transaction.set_rollback(True)
|
||||||
# The second block has a savepoint and must roll back.
|
# The second block has a savepoint and must roll back.
|
||||||
self.assertEqual(Reporter.objects.count(), 1)
|
self.assertEqual(Reporter.objects.count(), 1)
|
||||||
self.assertQuerysetEqual(Reporter.objects.all(), ['<Reporter: Tintin>'])
|
self.assertSequenceEqual(Reporter.objects.all(), [reporter])
|
||||||
|
|
||||||
|
|
||||||
@skipUnlessDBFeature('uses_savepoints')
|
@skipUnlessDBFeature('uses_savepoints')
|
||||||
|
|
Loading…
Reference in New Issue