Skip to content

Commit 6f43abc

Browse files
committed
Add subquery and foreign field unit tests.
1 parent a4a00bd commit 6f43abc

File tree

2 files changed

+91
-13
lines changed

2 files changed

+91
-13
lines changed

tests/model_fields_/models.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,3 +61,10 @@ class Author(models.Model):
6161
class Book(models.Model):
6262
name = models.CharField(max_length=100)
6363
author = EmbeddedModelField(Author)
64+
65+
66+
class Library(models.Model):
67+
name = models.CharField(max_length=100)
68+
books = models.ManyToManyField("Book", related_name="libraries")
69+
location = models.CharField(max_length=100, null=True, blank=True)
70+
best_seller = models.CharField(max_length=100, null=True, blank=True)

tests/model_fields_/test_embedded_model.py

Lines changed: 84 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,17 @@
11
import operator
2-
from datetime import timedelta
32
from decimal import Decimal
43

54
from django.core.exceptions import FieldDoesNotExist, ValidationError
6-
from django.db.models import ExpressionWrapper, F, IntegerField, Max, Sum
5+
from django.db.models import (
6+
Exists,
7+
ExpressionWrapper,
8+
F,
9+
IntegerField,
10+
Max,
11+
OuterRef,
12+
Subquery,
13+
Sum,
14+
)
715
from django.test import SimpleTestCase, TestCase
816

917
from django_mongodb.fields import EmbeddedModelField
@@ -15,6 +23,7 @@
1523
DecimalKey,
1624
EmbeddedModel,
1725
EmbeddedModelFieldModel,
26+
Library,
1827
)
1928

2029

@@ -175,9 +184,9 @@ def test_embedded_with_json_field(self):
175184
models[1:3],
176185
)
177186

178-
@staticmethod
179-
def _truncate_ms(time):
180-
return time - timedelta(microseconds=time.microsecond)
187+
def truncate_ms(self, value):
188+
"""Truncate microsends to millisecond precision as supported by MongoDB."""
189+
return value.replace(microsecond=(value.microsecond // 1000) * 1000)
181190

182191
def test_ordering_by_embedded_field(self):
183192
query = (
@@ -189,23 +198,26 @@ def test_ordering_by_embedded_field(self):
189198
self.assertSequenceEqual(query, expected)
190199

191200
def test_ordering_grouping_by_embedded_field(self):
201+
expected = sorted(
202+
(
203+
EmbeddedModelFieldModel.objects.create(simple=EmbeddedModel(someint=x))
204+
for x in range(6)
205+
),
206+
key=lambda x: x.simple.someint,
207+
)
192208
query = (
193209
EmbeddedModelFieldModel.objects.annotate(
194210
group=ExpressionWrapper(F("simple__someint") + 5, output_field=IntegerField())
195211
)
196212
.values("group")
197-
.annotate(max_pk=Max("simple__auto_now"))
213+
.annotate(max_auto_now=Max("simple__auto_now"))
198214
.order_by("simple__someint")
199215
)
200-
query = [{**e, "max_pk": self._truncate_ms(e["max_pk"])} for e in query]
201-
expected = [
202-
EmbeddedModelFieldModel.objects.create(simple=EmbeddedModel(someint=x))
203-
for x in range(6)
204-
]
216+
query_response = [{**e, "max_auto_now": self.truncate_ms(e["max_auto_now"])} for e in query]
205217
self.assertSequenceEqual(
206-
query,
218+
query_response,
207219
[
208-
{"group": e.simple.someint + 5, "max_pk": self._truncate_ms(e.simple.auto_now)}
220+
{"group": e.simple.someint + 5, "max_auto_now": self.truncate_ms(e.simple.auto_now)}
209221
for e in expected
210222
],
211223
)
@@ -218,3 +230,62 @@ def test_ordering_grouping_by_sum(self):
218230
.order_by("sum")
219231
)
220232
self.assertQuerySetEqual(qs, [0, 2, 4, 6, 8, 10], operator.itemgetter("sum"))
233+
234+
235+
class SubqueryExistsTestCase(TestCase):
236+
def setUp(self):
237+
# Create test data
238+
address1 = Address.objects.create(city="New York", state="NY", zip_code=10001)
239+
address2 = Address.objects.create(city="Boston", state="MA", zip_code=20002)
240+
author1 = Author.objects.create(name="Alice", age=30, address=address1)
241+
author2 = Author.objects.create(name="Bob", age=40, address=address2)
242+
book1 = Book.objects.create(name="Book A", author=author1)
243+
book2 = Book.objects.create(name="Book B", author=author2)
244+
Book.objects.create(name="Book C", author=author2)
245+
Book.objects.create(name="Book D", author=author2)
246+
Book.objects.create(name="Book E", author=author1)
247+
248+
library1 = Library.objects.create(
249+
name="Central Library", location="Downtown", best_seller="Book A"
250+
)
251+
library2 = Library.objects.create(
252+
name="Community Library", location="Suburbs", best_seller="Book A"
253+
)
254+
255+
# Add books to libraries
256+
library1.books.add(book1, book2)
257+
library2.books.add(book2)
258+
259+
def test_exists_subquery(self):
260+
subquery = Book.objects.filter(
261+
author__name=OuterRef("name"), author__address__city="Boston"
262+
)
263+
queryset = Author.objects.filter(Exists(subquery))
264+
265+
self.assertEqual(queryset.count(), 1)
266+
267+
def test_in_subquery(self):
268+
subquery = Author.objects.filter(age__gt=35).values("name")
269+
queryset = Book.objects.filter(author__name__in=Subquery(subquery)).order_by("name")
270+
271+
self.assertEqual(queryset.count(), 3)
272+
self.assertQuerySetEqual(queryset, ["Book B", "Book C", "Book D"], lambda book: book.name)
273+
274+
def test_range_query(self):
275+
queryset = Author.objects.filter(age__range=(25, 45)).order_by("name")
276+
277+
self.assertEqual(queryset.count(), 2)
278+
self.assertQuerySetEqual(queryset, ["Alice", "Bob"], lambda author: author.name)
279+
280+
def test_exists_with_foreign_object(self):
281+
subquery = Library.objects.filter(best_seller=OuterRef("name"))
282+
queryset = Book.objects.filter(Exists(subquery))
283+
284+
self.assertEqual(queryset.count(), 1)
285+
self.assertEqual(queryset.first().name, "Book A")
286+
287+
def test_foreign_field_with_ranges(self):
288+
queryset = Library.objects.filter(books__author__age__range=(25, 35))
289+
290+
self.assertEqual(queryset.count(), 1)
291+
self.assertEqual(queryset.first().name, "Central Library")

0 commit comments

Comments
 (0)