Opened 3 days ago

Last modified 20 hours ago

#36050 assigned Bug

Cannot resolve OuterRef to CompositePrimaryKey

Reported by: Jacob Walls Owned by: Csirmaz Bendegúz
Component: Database layer (models, ORM) Version: dev
Severity: Release blocker Keywords: subquery
Cc: Csirmaz Bendegúz Triage Stage: Accepted
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: yes
Easy pickings: no UI/UX: no

Description

With CompositePrimaryKey, using OuterRef("pk") in a subquery raises ValueError. Not certain if this is a release blocker or a new feature. If it's a new feature, we might want to document that it's not currently supported.

  • tests/composite_pk/test_filter.py

    diff --git a/tests/composite_pk/test_filter.py b/tests/composite_pk/test_filter.py
    index 7e361c5925..c3dfc8d44b 100644
    a b  
     1from django.db.models import OuterRef, Subquery
    12from django.test import TestCase
    23
    34from .models import Comment, Tenant, User
    class CompositePKFilterTests(TestCase):  
    5455            with self.subTest(lookup=lookup, count=count):
    5556                self.assertEqual(User.objects.filter(**lookup).count(), count)
    5657
     58    def test_outer_ref_pk(self):
     59        qs = Comment.objects.filter(
     60            id__gt=Subquery(Comment.objects.filter(pk=OuterRef("pk")).values("id")[:1])
     61        )
     62        self.assertEqual(qs.count(), 0)
     63
    5764    def test_order_comments_by_pk_asc(self):
    5865        self.assertSequenceEqual(
    5966            Comment.objects.order_by("pk"),
  File "/Users/.../django/django/db/models/fields/tuple_lookups.py", line 32, in get_prep_lookup
    self.check_rhs_is_tuple_or_list()
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^
  File "/Users/.../django/django/db/models/fields/tuple_lookups.py", line 39, in check_rhs_is_tuple_or_list
    raise ValueError(
        f"{self.lookup_name!r} lookup of {lhs_str} must be a tuple or a list"
    )
ValueError: 'exact' lookup of 'pk' must be a tuple or a list

Adjusting the guard that raises ValueError to also accept ResolvedOuterRef leads to a more interesting failure:

  File "/Users/.../django/django/db/models/expressions.py", line 1162, in as_sql
    val = output_field.get_db_prep_value(val, connection=connection)
  File "/Users/.../django/django/db/models/fields/related.py", line 1161, in get_db_prep_value
    return self.target_field.get_db_prep_value(value, connection, prepared)
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/.../django/django/db/models/fields/__init__.py", line 2819, in get_db_prep_value
    value = self.get_prep_value(value)
  File "/Users/.../django/django/db/models/fields/__init__.py", line 2129, in get_prep_value
    raise e.__class__(
        "Field '%s' expected a number but got %r." % (self.name, value),
    ) from e
TypeError: Field 'id' expected a number but got Col(composite_pk_comment, composite_pk.Comment.tenant).

Change History (5)

comment:1 by Sarah Boyce, 2 days ago

Cc: Csirmaz Bendegúz added
Severity: NormalRelease blocker
Triage Stage: UnreviewedAccepted
Type: New featureBug

Thank you Jacob
Marking as a release blocker. I think we might be able to resolve this but if not, agree we might want to document it within the not supported section.

comment:2 by Sarah Boyce, 2 days ago

Note that the "document" fix can include a better error message.

comment:3 by Csirmaz Bendegúz, 26 hours ago

Owner: set to Csirmaz Bendegúz
Status: newassigned

Thank you, I'll look into it

comment:4 by Csirmaz Bendegúz, 24 hours ago

Has patch: set

I added a patch

comment:5 by Jacob Walls, 20 hours ago

Patch needs improvement: set
Note: See TracTickets for help on using tickets.
Back to Top