Skip to content

Commit ed8eb88

Browse files
authored
Merge pull request #80 from clokep/distinct-tests
Improve the tests for distinct.
2 parents 5b0f409 + f8c1ed6 commit ed8eb88

File tree

4 files changed

+65
-47
lines changed

4 files changed

+65
-47
lines changed

tests/models.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ class BlogPost(models.Model):
5151
class Book(models.Model):
5252
title = models.CharField(max_length=50)
5353
author = models.ForeignKey(Author, on_delete=models.CASCADE)
54-
publisher = models.ForeignKey(Publisher, related_name='published', on_delete=models.CASCADE)
54+
publishers = models.ManyToManyField(Publisher, related_name='published')
5555
release = models.DateField()
5656
pages = models.PositiveSmallIntegerField()
5757

tests/test_pagination.py

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,13 @@ def setUp(self):
4646
address="123 Publishing Street")
4747

4848
for d in range(1, 15):
49-
Book.objects.create(title='Book %s' % (d % 2),
50-
author=self.author,
51-
publisher=self.publisher,
52-
pages=d,
53-
release=date(2018, 10, 5))
49+
book = Book.objects.create(
50+
title='Book %s' % (d % 2),
51+
author=self.author,
52+
pages=d,
53+
release=date(2018, 10, 5),
54+
)
55+
book.publishers.set([self.publisher])
5456

5557
self.pagination = _TestPagination()
5658
self.queryset = QuerySetSequence(Book.objects.filter(pages__lte=7),
@@ -225,11 +227,13 @@ def test_duplicates(self):
225227

226228
# Create a bunch of books that are the same.
227229
for i in range(15):
228-
Book.objects.create(title=str(i),
229-
author=self.author,
230-
publisher=self.publisher,
231-
pages=PAGES,
232-
release=date(2018, 10, 5))
230+
book = Book.objects.create(
231+
title=str(i),
232+
author=self.author,
233+
pages=PAGES,
234+
release=date(2018, 10, 5),
235+
)
236+
book.publishers.set([self.publisher])
233237

234238
# And use only those duplicate books.
235239
self.queryset = QuerySetSequence(Book.objects.filter(pages=PAGES))

tests/test_querysetsequence.py

Lines changed: 46 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,12 @@ def setUp(self):
5050
publisher=mad_magazine, release=date(1990, 8, 14))
5151

5252
# Bob wrote a couple of books, an article, and a blog post.
53-
Book.objects.create(title="Fiction", author=bob, publisher=big_books,
54-
pages=10, release=date(2001, 6, 12))
55-
Book.objects.create(title="Biography", author=bob, publisher=big_books,
56-
pages=20, release=date(2002, 12, 24))
53+
book = Book.objects.create(title="Fiction", author=bob,
54+
pages=10, release=date(2001, 6, 12))
55+
book.publishers.set([big_books])
56+
book = Book.objects.create(title="Biography", author=bob,
57+
pages=20, release=date(2002, 12, 24))
58+
book.publishers.set([big_books])
5759
Article.objects.create(title="Some Article", author=bob,
5860
publisher=mad_magazine, release=date(1979, 1, 1))
5961
BlogPost.objects.create(title="Post", author=bob,
@@ -387,7 +389,7 @@ def test_empty_defer(self):
387389
def test_only(self):
388390
"""Only causes other fields to load on access (opposite of defer)."""
389391
with self.assertNumQueries(2):
390-
books = list(self.all.only('publisher'))
392+
books = list(self.all.only('author'))
391393
with self.assertNumQueries(5):
392394
titles = [b.title for b in books]
393395
self.assertEqual(titles, self.TITLES_BY_PK)
@@ -399,7 +401,7 @@ def test_order_by(self):
399401
# Additional queries are due to the field needing to be pulled
400402
# individually during sorting.
401403
with self.assertNumQueries(7):
402-
books = list(self.all.only('publisher').order_by('title'))
404+
books = list(self.all.only('author').order_by('title'))
403405
# No additional queries are necessary since the titles were used in
404406
# sorting.
405407
with self.assertNumQueries(0):
@@ -421,14 +423,34 @@ def test_using(self):
421423

422424
class TestDistinct(TestBase):
423425
def test_distinct(self):
424-
for qs in self.all._querysets:
425-
assert not qs.query.distinct
426+
"""
427+
Distinct gets applied to each QuerySet, but not the overall QuerySetSequence.
428+
"""
429+
# Create another publisher and add an existing book to it.
430+
publisher = Publisher.objects.create(name="Bigger Books")
431+
book = Book.objects.get(title="Biography")
432+
book.publishers.add(publisher)
433+
434+
# Make a QuerySetSequence that would include non-distinct items.
435+
big_books = Book.objects.filter(publishers__name__startswith="Big")
436+
qss = QuerySetSequence(big_books, Article.objects.filter(publisher__name__startswith="Big"))
437+
438+
# There should be more items than unique items.
439+
titles = [b.title for b in qss]
440+
self.assertGreater(len(titles), len(set(titles)))
441+
426442
with self.assertNumQueries(0):
427-
distinct = self.all.distinct()
428-
for qs in distinct._querysets:
429-
assert qs.query.distinct
443+
qss = qss.distinct()
444+
445+
# After calling distinct there should not be duplicated entries.
446+
titles = [b.title for b in qss]
447+
self.assertEqual(len(titles), len(set(titles)))
430448

431449
def test_multiple_querysets_same_model(self):
450+
"""
451+
Calling distinct on a QuerySetSequence made up of multiple QuerySet instances
452+
of the same model is not supported.
453+
"""
432454
qss = QuerySetSequence(Book.objects.all(), Book.objects.all())
433455
with self.assertRaises(NotImplementedError):
434456
qss.distinct()
@@ -877,8 +899,7 @@ def test_order_by_multi(self):
877899
"""Test ordering by multiple fields."""
878900
# Add another object with the same title, but a later release date.
879901
Book.objects.create(title="Fiction", author=self.alice,
880-
publisher=self.big_books, pages=1,
881-
release=date(2018, 10, 3))
902+
pages=1, release=date(2018, 10, 3))
882903

883904
with self.assertNumQueries(0):
884905
qss = self.all.order_by('title', '-release')
@@ -937,20 +958,22 @@ def test_order_by_relation_pk(self):
937958
Apply order_by() with a field that returns a model without a default
938959
ordering (i.e. using the pk).
939960
"""
940-
# Order by publisher and ensure it takes.
961+
# Order by author and ensure it takes.
941962
with self.assertNumQueries(0):
942-
qss = self.all.order_by('publisher')
963+
qss = self.all.order_by('author')
943964

944965
# Ensure that the test has any hope of passing.
945-
self.assertLess(self.mad_magazine.pk, self.big_books.pk)
966+
self.assertLess(self.alice.pk, self.bob.pk)
946967

947968
# The first three should be from Mad Magazine, followed by three from
948969
# Big Books.
949970
# Note that the QuerySetSequence itself needs the publisher objects to
950971
# compare them, so they all get pulled in.
951972
with self.assertNumQueries(2 + 5):
952-
for expected, element in zip([self.mad_magazine.id] * 3 + [self.big_books.id] * 2, qss):
953-
self.assertEqual(element.publisher.id, expected)
973+
self.assertEqual(
974+
[self.alice.id] * 2 + [self.bob.id] * 3,
975+
[b.author.id for b in qss],
976+
)
954977

955978
def test_order_by_relation_with_ordering(self):
956979
"""
@@ -997,14 +1020,6 @@ def test_order_by_relation_field(self):
9971020
for expected, element in zip([self.alice.id] * 2 + [self.bob.id] * 3, qss):
9981021
self.assertEqual(element.author.id, expected)
9991022

1000-
def test_order_by_relation_no_existent_field(self):
1001-
"""Apply order_by() with a field through a model relationship that doesn't exist."""
1002-
with self.assertNumQueries(0):
1003-
qss = self.all.order_by('publisher__address')
1004-
1005-
with self.assertRaises(FieldError):
1006-
list(qss)
1007-
10081023
def test_order_by_queryset(self):
10091024
"""Ensure we can order by QuerySet and then other fields."""
10101025
# Order by title, but don't interleave each QuerySet.
@@ -1470,10 +1485,12 @@ def test_empty(self):
14701485
class TestDelete(TestBase):
14711486
def test_delete_all(self):
14721487
"""Ensure that delete() works properly."""
1473-
with self.assertNumQueries(2):
1488+
# 4 queries is due to the models themselves and then the many-to-many
1489+
# relationships.
1490+
with self.assertNumQueries(4):
14741491
result = self.all.delete()
1475-
self.assertEqual(result[0], 5)
1476-
self.assertEqual(result[1], {'tests.Article': 3, 'tests.Book': 2})
1492+
self.assertEqual(result[0], 7)
1493+
self.assertEqual(result[1], {'tests.Article': 3, 'tests.Book': 2, 'tests.Book_publishers': 2})
14771494

14781495
with self.assertNumQueries(2):
14791496
self.assertEqual(self.all.count(), 0)
@@ -1483,10 +1500,7 @@ def test_delete_filter(self):
14831500
with self.assertNumQueries(2):
14841501
result = self.all.filter(author=self.alice).delete()
14851502
self.assertEqual(result[0], 2)
1486-
# Django 3.1 no longer returns 0 as the number of objects deleted.
14871503
expected = {'tests.Article': 2}
1488-
if django.VERSION < (3, 1):
1489-
expected['tests.Book'] = 0
14901504
self.assertEqual(result[1], expected)
14911505

14921506
with self.assertNumQueries(2):

tests/test_values.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ def test_values(self):
1313
authors = [it['author_id'] for it in values]
1414
self.assertEqual(titles, self.TITLES_BY_PK)
1515
self.assertEqual(authors, [2, 2, 1, 1, 2])
16-
self.assertCountEqual(values[0].keys(), ['#', 'id', 'author_id', 'pages', 'publisher_id', 'release', 'title'])
16+
self.assertCountEqual(values[0].keys(), ['#', 'id', 'author_id', 'pages', 'release', 'title'])
1717

1818
def test_fields(self):
1919
"""Ensure the proper fields are returned."""
@@ -93,7 +93,7 @@ def test_values_list(self):
9393
"""Ensure the values conversion works as expected."""
9494
with self.assertNumQueries(2):
9595
values = list(self.all.values_list())
96-
self.assertEqual(values[0], (1, 'Fiction', 2, 2, datetime.date(2001, 6, 12), 10))
96+
self.assertEqual(values[0], (1, 'Fiction', 2, datetime.date(2001, 6, 12), 10))
9797

9898
def test_fields(self):
9999
"""Ensure the proper fields are returned."""
@@ -240,8 +240,8 @@ def test_values_list(self):
240240
"""Ensure the values conversion works as expected."""
241241
with self.assertNumQueries(2):
242242
values = list(self.all.values_list(named=True))
243-
self.assertEqual(values[0], (1, 'Fiction', 2, 2, datetime.date(2001, 6, 12), 10))
244-
self.assertEqual(values[0]._fields, ('id', 'title', 'author_id', 'publisher_id', 'release', 'pages'))
243+
self.assertEqual(values[0], (1, 'Fiction', 2, datetime.date(2001, 6, 12), 10))
244+
self.assertEqual(values[0]._fields, ('id', 'title', 'author_id', 'release', 'pages'))
245245
# Also check one of the other types.
246246
self.assertEqual(values[2]._fields, ('id', 'title', 'author_id', 'publisher_id', 'release'))
247247

0 commit comments

Comments
 (0)