diff options
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/composite_pk/models/tenant.py | 1 | ||||
| -rw-r--r-- | tests/composite_pk/test_filter.py | 58 | ||||
| -rw-r--r-- | tests/composite_pk/tests.py | 9 | ||||
| -rw-r--r-- | tests/foreign_object/test_tuple_lookups.py | 18 | ||||
| -rw-r--r-- | tests/lookup/tests.py | 16 | ||||
| -rw-r--r-- | tests/queries/tests.py | 14 |
6 files changed, 83 insertions, 33 deletions
diff --git a/tests/composite_pk/models/tenant.py b/tests/composite_pk/models/tenant.py index 6286ed2354..c85869afa7 100644 --- a/tests/composite_pk/models/tenant.py +++ b/tests/composite_pk/models/tenant.py @@ -44,6 +44,7 @@ class Comment(models.Model): related_name="comments", ) text = models.TextField(default="", blank=True) + integer = models.IntegerField(default=0) class Post(models.Model): diff --git a/tests/composite_pk/test_filter.py b/tests/composite_pk/test_filter.py index fe942b9e5b..d4c6ef13e0 100644 --- a/tests/composite_pk/test_filter.py +++ b/tests/composite_pk/test_filter.py @@ -10,7 +10,7 @@ from django.db.models import ( ) from django.db.models.functions import Cast from django.db.models.lookups import Exact -from django.test import TestCase +from django.test import TestCase, skipUnlessDBFeature from .models import Comment, Tenant, User @@ -182,6 +182,30 @@ class CompositePKFilterTests(TestCase): Comment.objects.filter(pk__in=pks).order_by("pk"), objs ) + def test_filter_comments_by_pk_in_subquery(self): + self.assertSequenceEqual( + Comment.objects.filter( + pk__in=Comment.objects.filter(pk=self.comment_1.pk), + ), + [self.comment_1], + ) + self.assertSequenceEqual( + Comment.objects.filter( + pk__in=Comment.objects.filter(pk=self.comment_1.pk).values( + "tenant_id", "id" + ), + ), + [self.comment_1], + ) + self.comment_2.integer = self.comment_1.id + self.comment_2.save() + self.assertSequenceEqual( + Comment.objects.filter( + pk__in=Comment.objects.values("tenant_id", "integer"), + ), + [self.comment_1], + ) + def test_filter_comments_by_user_and_order_by_pk_asc(self): self.assertSequenceEqual( Comment.objects.filter(user=self.user_1).order_by("pk"), @@ -440,16 +464,40 @@ class CompositePKFilterTests(TestCase): queryset = Comment.objects.filter(**{f"id{lookup}": subquery}) self.assertEqual(queryset.count(), expected_count) - def test_non_outer_ref_subquery(self): - # If rhs is any non-OuterRef object with an as_sql() function. + def test_unsupported_rhs(self): pk = Exact(F("tenant_id"), 1) msg = ( - "'exact' subquery lookup of 'pk' only supports OuterRef objects " - "(received 'Exact')" + "'exact' subquery lookup of 'pk' only supports OuterRef " + "and QuerySet objects (received 'Exact')" ) with self.assertRaisesMessage(ValueError, msg): Comment.objects.filter(pk=pk) + @skipUnlessDBFeature("allow_sliced_subqueries_with_in") + def test_filter_comments_by_pk_exact_subquery(self): + self.assertSequenceEqual( + Comment.objects.filter( + pk=Comment.objects.filter(pk=self.comment_1.pk)[:1], + ), + [self.comment_1], + ) + self.assertSequenceEqual( + Comment.objects.filter( + pk__in=Comment.objects.filter(pk=self.comment_1.pk).values( + "tenant_id", "id" + )[:1], + ), + [self.comment_1], + ) + self.comment_2.integer = self.comment_1.id + self.comment_2.save() + self.assertSequenceEqual( + Comment.objects.filter( + pk__in=Comment.objects.values("tenant_id", "integer"), + )[:1], + [self.comment_1], + ) + def test_outer_ref_not_composite_pk(self): subquery = Comment.objects.filter(pk=OuterRef("id")).values("id") queryset = Comment.objects.filter(id=Subquery(subquery)) diff --git a/tests/composite_pk/tests.py b/tests/composite_pk/tests.py index 6b09480fb0..18fa53d9c0 100644 --- a/tests/composite_pk/tests.py +++ b/tests/composite_pk/tests.py @@ -109,13 +109,10 @@ class CompositePKTests(TestCase): def test_composite_pk_in_fields(self): user_fields = {f.name for f in User._meta.get_fields()} - self.assertEqual(user_fields, {"pk", "tenant", "id", "email", "comments"}) + self.assertTrue({"pk", "tenant", "id"}.issubset(user_fields)) comment_fields = {f.name for f in Comment._meta.get_fields()} - self.assertEqual( - comment_fields, - {"pk", "tenant", "id", "user_id", "user", "text"}, - ) + self.assertTrue({"pk", "tenant", "id"}.issubset(comment_fields)) def test_pk_field(self): pk = User._meta.get_field("pk") @@ -174,7 +171,7 @@ class CompositePKTests(TestCase): self.assertEqual(user.email, self.user.email) def test_model_forms(self): - fields = ["tenant", "id", "user_id", "text"] + fields = ["tenant", "id", "user_id", "text", "integer"] self.assertEqual(list(CommentForm.base_fields), fields) form = modelform_factory(Comment, fields="__all__") diff --git a/tests/foreign_object/test_tuple_lookups.py b/tests/foreign_object/test_tuple_lookups.py index 42717c4f11..008f118994 100644 --- a/tests/foreign_object/test_tuple_lookups.py +++ b/tests/foreign_object/test_tuple_lookups.py @@ -63,9 +63,11 @@ class TupleLookupsTests(TestCase): ) def test_exact_subquery(self): - with self.assertRaisesMessage( - ValueError, "'exact' doesn't support multi-column subqueries." - ): + msg = ( + "The QuerySet value for the exact lookup must have 2 selected " + "fields (received 1)" + ) + with self.assertRaisesMessage(ValueError, msg): subquery = Customer.objects.filter(id=self.customer_1.id)[:1] self.assertSequenceEqual( Contact.objects.filter(customer=subquery).order_by("id"), () @@ -140,11 +142,11 @@ class TupleLookupsTests(TestCase): def test_tuple_in_subquery_must_have_2_fields(self): lhs = (F("customer_code"), F("company_code")) rhs = Customer.objects.values_list("customer_id").query - with self.assertRaisesMessage( - ValueError, - "'in' subquery lookup of ('customer_code', 'company_code') " - "must have 2 fields (received 1)", - ): + msg = ( + "The QuerySet value for the 'in' lookup must have 2 selected " + "fields (received 1)" + ) + with self.assertRaisesMessage(ValueError, msg): TupleIn(lhs, rhs) def test_tuple_in_subquery(self): diff --git a/tests/lookup/tests.py b/tests/lookup/tests.py index df96546d04..e19fbca521 100644 --- a/tests/lookup/tests.py +++ b/tests/lookup/tests.py @@ -789,6 +789,14 @@ class LookupTests(TestCase): sql = ctx.captured_queries[0]["sql"] self.assertIn("IN (%s)" % self.a1.pk, sql) + def test_in_select_mismatch(self): + msg = ( + "The QuerySet value for the 'in' lookup must have 1 " + "selected fields (received 2)" + ) + with self.assertRaisesMessage(ValueError, msg): + Article.objects.filter(id__in=Article.objects.values("id", "headline")) + def test_error_messages(self): # Programming errors are pointed out with nice error messages with self.assertRaisesMessage( @@ -1364,6 +1372,14 @@ class LookupTests(TestCase): authors = Author.objects.filter(id=authors_max_ids[:1]) self.assertEqual(authors.get(), newest_author) + def test_exact_query_rhs_with_selected_columns_mismatch(self): + msg = ( + "The QuerySet value for the exact lookup must have 1 " + "selected fields (received 2)" + ) + with self.assertRaisesMessage(ValueError, msg): + Author.objects.filter(id=Author.objects.values("id", "name")[:1]) + def test_isnull_non_boolean_value(self): msg = "The QuerySet value for an isnull lookup must be True or False." tests = [ diff --git a/tests/queries/tests.py b/tests/queries/tests.py index 45866fd50f..c429a93af3 100644 --- a/tests/queries/tests.py +++ b/tests/queries/tests.py @@ -922,20 +922,6 @@ class Queries1Tests(TestCase): [self.t2, self.t3], ) - # Multi-valued values() and values_list() querysets should raise errors. - with self.assertRaisesMessage( - TypeError, "Cannot use multi-field values as a filter value." - ): - Tag.objects.filter( - name__in=Tag.objects.filter(parent=self.t1).values("name", "id") - ) - with self.assertRaisesMessage( - TypeError, "Cannot use multi-field values as a filter value." - ): - Tag.objects.filter( - name__in=Tag.objects.filter(parent=self.t1).values_list("name", "id") - ) - def test_ticket9985(self): # qs.values_list(...).values(...) combinations should work. self.assertSequenceEqual( |
