summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorFrancesco Panico <panico.francesco@gmail.com>2023-03-04 17:59:53 +0000
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2023-08-11 12:32:18 +0200
commit59f475470494ce5b8cbff816b1e5dafcbd10a3a3 (patch)
treea708c8a3287ba296e5ea38eabd10e42de798991d /tests
parent1506f498fe42b65730ece809300c2c0963e38c5a (diff)
Fixed #34362 -- Fixed FilteredRelation() crash on conditional expressions.
Thanks zhu for the report and Simon Charette for reviews.
Diffstat (limited to 'tests')
-rw-r--r--tests/filtered_relation/tests.py85
1 files changed, 85 insertions, 0 deletions
diff --git a/tests/filtered_relation/tests.py b/tests/filtered_relation/tests.py
index f9735ca371..5a21a47f36 100644
--- a/tests/filtered_relation/tests.py
+++ b/tests/filtered_relation/tests.py
@@ -4,9 +4,11 @@ from unittest import mock
from django.db import connection, transaction
from django.db.models import (
+ BooleanField,
Case,
Count,
DecimalField,
+ ExpressionWrapper,
F,
FilteredRelation,
Q,
@@ -15,6 +17,7 @@ from django.db.models import (
When,
)
from django.db.models.functions import Concat
+from django.db.models.lookups import Exact, IStartsWith
from django.test import TestCase
from django.test.testcases import skipUnlessDBFeature
@@ -707,6 +710,88 @@ class FilteredRelationTests(TestCase):
FilteredRelation("book", condition=Q(book__title="b")), mock.ANY
)
+ def test_conditional_expression(self):
+ qs = Author.objects.annotate(
+ the_book=FilteredRelation("book", condition=Q(Value(False))),
+ ).filter(the_book__isnull=False)
+ self.assertSequenceEqual(qs, [])
+
+ def test_expression_outside_relation_name(self):
+ qs = Author.objects.annotate(
+ book_editor=FilteredRelation(
+ "book__editor",
+ condition=Q(
+ Exact(F("book__author__name"), "Alice"),
+ Value(True),
+ book__title__startswith="Poem",
+ ),
+ ),
+ ).filter(book_editor__isnull=False)
+ self.assertSequenceEqual(qs, [self.author1])
+
+ def test_conditional_expression_with_case(self):
+ qs = Book.objects.annotate(
+ alice_author=FilteredRelation(
+ "author",
+ condition=Q(
+ Case(When(author__name="Alice", then=True), default=False),
+ ),
+ ),
+ ).filter(alice_author__isnull=False)
+ self.assertCountEqual(qs, [self.book1, self.book4])
+
+ def test_conditional_expression_outside_relation_name(self):
+ tests = [
+ Q(Case(When(book__author__name="Alice", then=True), default=False)),
+ Q(
+ ExpressionWrapper(
+ Q(Value(True), Exact(F("book__author__name"), "Alice")),
+ output_field=BooleanField(),
+ ),
+ ),
+ ]
+ for condition in tests:
+ with self.subTest(condition=condition):
+ qs = Author.objects.annotate(
+ book_editor=FilteredRelation("book__editor", condition=condition),
+ ).filter(book_editor__isnull=True)
+ self.assertSequenceEqual(qs, [self.author2, self.author2])
+
+ def test_conditional_expression_with_lookup(self):
+ lookups = [
+ Q(book__title__istartswith="poem"),
+ Q(IStartsWith(F("book__title"), "poem")),
+ ]
+ for condition in lookups:
+ with self.subTest(condition=condition):
+ qs = Author.objects.annotate(
+ poem_book=FilteredRelation("book", condition=condition)
+ ).filter(poem_book__isnull=False)
+ self.assertSequenceEqual(qs, [self.author1])
+
+ def test_conditional_expression_with_expressionwrapper(self):
+ qs = Author.objects.annotate(
+ poem_book=FilteredRelation(
+ "book",
+ condition=Q(
+ ExpressionWrapper(
+ Q(Exact(F("book__title"), "Poem by Alice")),
+ output_field=BooleanField(),
+ ),
+ ),
+ ),
+ ).filter(poem_book__isnull=False)
+ self.assertSequenceEqual(qs, [self.author1])
+
+ def test_conditional_expression_with_multiple_fields(self):
+ qs = Author.objects.annotate(
+ my_books=FilteredRelation(
+ "book__author",
+ condition=Q(Exact(F("book__author__name"), F("book__author__name"))),
+ ),
+ ).filter(my_books__isnull=True)
+ self.assertSequenceEqual(qs, [])
+
class FilteredRelationAggregationTests(TestCase):
@classmethod