#36065: order_by("pk") not equivalent to order_by(F("pk")) for 
CompositePrimaryKey
-------------------------------------+-------------------------------------
     Reporter:  Jacob Walls          |                    Owner:  (none)
         Type:  Bug                  |                   Status:  new
    Component:  Database layer       |                  Version:  dev
  (models, ORM)                      |
     Severity:  Release blocker      |               Resolution:
     Keywords:                       |             Triage Stage:  Accepted
    Has patch:  0                    |      Needs documentation:  0
  Needs tests:  0                    |  Patch needs improvement:  0
Easy pickings:  0                    |                    UI/UX:  0
-------------------------------------+-------------------------------------
Comment (by Simon Charette):

 The changes made to `SQLCompiler.find_ordering_name`
 
[https://github.com/django/django/commit/978aae4334fa71ba78a3e94408f0f3aebde8d07c
 #diff-
 f58de2deaccecd2d53199c5ca29e3e1050ec2adb80fb057cdfc0b4e6accdf14fR1119 to
 accommodate for] `order_by(*: str)` references to a composite primary key
 failed to account for the fact that resolvable and direct `OrderBy`
 instance can be passed to `QuerySet.order_by`.

 The solution likely lies in adjusting `find_ordering_name` to create a
 `ColPairs` when there are multiple targets (instead of calling
 `composite.unnest`) and adjusting `OrderBy.as_sql` to properly deal with
 `ColPairs`. I guess we should test for `F("pk").asc(nulls_first=True)` and
 `F("pk").asc(nulls_last=True)` (even if primary keys cannot contain nulls)
 while we're at it to ensure the proper `NULLS LAST` emulation is working
 correction.

 {{{#!diff
 diff --git a/django/db/models/expressions.py
 b/django/db/models/expressions.py
 index 667e9f93c6..2e1828ff9b 100644
 --- a/django/db/models/expressions.py
 +++ b/django/db/models/expressions.py
 @@ -1850,6 +1850,16 @@ def get_source_expressions(self):
          return [self.expression]

      def as_sql(self, compiler, connection, template=None,
 **extra_context):
 +        if isinstance(self.expression, ColPairs):
 +            sql_parts = []
 +            params = []
 +            for col in self.expression.get_cols():
 +                copy = self.copy()
 +                copy.set_source_expressions([col])
 +                sql, col_params = compiler.compile(copy)
 +                sql_parts.append(sql)
 +                params.extend(col_params)
 +            return ", ".join(sql_parts), params
          template = template or self.template
          if connection.features.supports_order_by_nulls_modifier:
              if self.nulls_last:
 diff --git a/django/db/models/sql/compiler.py
 b/django/db/models/sql/compiler.py
 index 5bb491d823..251cc08e51 100644
 --- a/django/db/models/sql/compiler.py
 +++ b/django/db/models/sql/compiler.py
 @@ -1117,10 +1117,9 @@ def find_ordering_name(
                  )
              return results
          targets, alias, _ = self.query.trim_joins(targets, joins, path)
 -        target_fields = composite.unnest(targets)
          return [
              (OrderBy(transform_function(t, alias),
 descending=descending), False)
 -            for t in target_fields
 +            for t in targets
          ]

      def _setup_joins(self, pieces, opts, alias):
 diff --git a/tests/composite_pk/test_filter.py
 b/tests/composite_pk/test_filter.py
 index 7e361c5925..be0e80a518 100644
 --- a/tests/composite_pk/test_filter.py
 +++ b/tests/composite_pk/test_filter.py
 @@ -1,3 +1,4 @@
 +from django.db.models import F
  from django.test import TestCase

  from .models import Comment, Tenant, User
 @@ -78,6 +79,12 @@ def test_order_comments_by_pk_desc(self):
              ),
          )

 +    def test_order_comments_by_pk_asc_f(self):
 +        self.assertQuerySetEqual(
 +            Comment.objects.order_by("pk"),
 +            Comment.objects.order_by(F("pk")),
 +        )
 +
      def test_filter_comments_by_pk_gt(self):
          c11, c12, c13, c24, c15 = (
              self.comment_1
 }}}

 Note that we'll need to mark `OrderBy.allows_composite_expressions = True`
 per the work on #36042 depending on the order in which the changes are
 merged.
-- 
Ticket URL: <https://code.djangoproject.com/ticket/36065#comment:2>
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/010701943c5a1a5a-0172d42d-0acb-4247-9fdd-2d7fdd6b4f54-000000%40eu-central-1.amazonses.com.

Reply via email to