diff options
| author | Francesco Panico <panico.francesco@gmail.com> | 2023-03-04 17:59:53 +0000 |
|---|---|---|
| committer | Mariusz Felisiak <felisiak.mariusz@gmail.com> | 2023-08-11 12:32:18 +0200 |
| commit | 59f475470494ce5b8cbff816b1e5dafcbd10a3a3 (patch) | |
| tree | a708c8a3287ba296e5ea38eabd10e42de798991d /tests/filtered_relation | |
| parent | 1506f498fe42b65730ece809300c2c0963e38c5a (diff) | |
Fixed #34362 -- Fixed FilteredRelation() crash on conditional expressions.
Thanks zhu for the report and Simon Charette for reviews.
Diffstat (limited to 'tests/filtered_relation')
| -rw-r--r-- | tests/filtered_relation/tests.py | 85 |
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 |
