#36149: Composite primary key subquery lookup prevent usage or specify fields 
and
are not implemented for exact
-------------------------------------+-------------------------------------
               Reporter:  Simon      |          Owner:  (none)
  Charette                           |
                   Type:  Bug        |         Status:  assigned
              Component:  Database   |        Version:  5.2
  layer (models, ORM)                |
               Severity:  Release    |       Keywords:
  blocker                            |
           Triage Stage:             |      Has patch:  1
  Unreviewed                         |
    Needs documentation:  0          |    Needs tests:  0
Patch needs improvement:  0          |  Easy pickings:  0
                  UI/UX:  0          |
-------------------------------------+-------------------------------------
 I started playing with tuple lookup support for composite primary key and
 I noticed two main problems.

 First `pk__in=query` lookups completely disallow specifying which fields
 should be used  in the select clause of the right-hand-side and implicitly
 set them to the left-hand-side name which assumes the same set of left-
 hand-side field name is shared by the right-hand-side which is a bad
 assumption

 {{{#!diff
 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..78383655a0 100644
 --- a/tests/composite_pk/test_filter.py
 +++ b/tests/composite_pk/test_filter.py
 @@ -182,6 +182,30 @@ def test_filter_comments_by_pk_in(self):
                      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"),
 }}}

 Allowing fields to be specified requires lifting a `QuerySet`
 
[https://github.com/django/django/blob/8eca4077f60fa0705ecfd9437c9ceaeef7a3808b/django/db/models/query.py#L1967-L1970
 resolving time constraint] which was entirely by-passable by passing
 `queryset.query` instead as the right-hand-side.

 The tuple exact lookup should also allow querysets with a single element
 to be specified as right-hand-side which is currently disallowed

 {{{#!diff
 diff --git a/tests/composite_pk/test_filter.py
 b/tests/composite_pk/test_filter.py
 index fe942b9e5b..78383655a0 100644
 --- a/tests/composite_pk/test_filter.py
 +++ b/tests/composite_pk/test_filter.py
 @@ -450,6 +474,30 @@ def test_non_outer_ref_subquery(self):
          with self.assertRaisesMessage(ValueError, msg):
              Comment.objects.filter(pk=pk)

 +    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))
 }}}

 Lastly lifting the constraint that prevented subqueries returning more
 than one column from being used as a right-hand-side required adjusting
 the existing `exact` and `in` lookup logic to disallow left-hand-side and
 right-hand-side with mismatching number of fields.
-- 
Ticket URL: <https://code.djangoproject.com/ticket/36149>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion visit 
https://groups.google.com/d/msgid/django-updates/01070194ab1a1f7b-6a74c51d-6a62-4c5c-852b-6378b88e1729-000000%40eu-central-1.amazonses.com.

Reply via email to