Skip to content

allow order_by() to reference annotations #67

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions django_mongodb/compiler.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from django.core.exceptions import EmptyResultSet, FullResultSet
from django.core.exceptions import EmptyResultSet, FieldDoesNotExist, FullResultSet
from django.db import DatabaseError, IntegrityError, NotSupportedError
from django.db.models import NOT_PROVIDED, Count, Expression
from django.db.models.aggregates import Aggregate
Expand Down Expand Up @@ -212,7 +212,7 @@ def _get_ordering(self):
if not ordering:
return self.query.standard_ordering

field_ordering = []
column_ordering = []
for order in ordering:
if LOOKUP_SEP in order:
raise NotSupportedError("Ordering can't span tables on MongoDB (%s)." % order)
Expand All @@ -227,8 +227,13 @@ def _get_ordering(self):
if name == "pk":
name = opts.pk.name

field_ordering.append((opts.get_field(name), ascending))
return field_ordering
try:
column = opts.get_field(name).column
except FieldDoesNotExist:
# `name` is an annotation in $project.
column = name
column_ordering.append((column, ascending))
return column_ordering

@cached_property
def collection_name(self):
Expand Down
20 changes: 9 additions & 11 deletions django_mongodb/features.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ class DatabaseFeatures(BaseDatabaseFeatures):
"ordering.tests.OrderingTests.test_default_ordering",
"ordering.tests.OrderingTests.test_default_ordering_by_f_expression",
"ordering.tests.OrderingTests.test_default_ordering_does_not_affect_group_by",
"ordering.tests.OrderingTests.test_order_by_constant_value",
"ordering.tests.OrderingTests.test_order_by_expr_query_reuse",
"ordering.tests.OrderingTests.test_order_by_expression_ref",
"ordering.tests.OrderingTests.test_order_by_f_expression",
Expand Down Expand Up @@ -87,7 +88,9 @@ class DatabaseFeatures(BaseDatabaseFeatures):
# Wrong results in queries with multiple tables.
"annotations.tests.NonAggregateAnnotationTestCase.test_annotation_aggregate_with_m2o",
"annotations.tests.NonAggregateAnnotationTestCase.test_annotation_reverse_m2m",
"annotations.tests.NonAggregateAnnotationTestCase.test_annotation_with_m2m",
"annotations.tests.NonAggregateAnnotationTestCase.test_chaining_annotation_filter_with_m2m",
"annotations.tests.NonAggregateAnnotationTestCase.test_mti_annotations",
"lookup.tests.LookupTests.test_lookup_collision",
"expressions.test_queryset_values.ValuesExpressionsTests.test_values_list_expression",
"expressions.test_queryset_values.ValuesExpressionsTests.test_values_list_expression_flat",
Expand All @@ -102,6 +105,10 @@ class DatabaseFeatures(BaseDatabaseFeatures):
# pymongo.errors.OperationFailure: $multiply only supports numeric
# types, not date. (should be wrapped in DatabaseError).
"expressions.tests.FTimeDeltaTests.test_invalid_operator",
# alias().order_by() doesn't work.
"annotations.tests.AliasTests.test_order_by_alias",
# annotate() + values_list() + order_by() loses annotated value.
"expressions_case.tests.CaseExpressionTests.test_annotate_values_not_in_order_by",
}
# $bitAnd, #bitOr, and $bitXor are new in MongoDB 6.3.
_django_test_expected_failures_bitwise = {
Expand Down Expand Up @@ -280,27 +287,18 @@ def django_test_expected_failures(self):
"annotations.tests.NonAggregateAnnotationTestCase.test_combined_f_expression_annotation_with_aggregation",
"annotations.tests.NonAggregateAnnotationTestCase.test_full_expression_annotation_with_aggregation",
"annotations.tests.NonAggregateAnnotationTestCase.test_grouping_by_q_expression_annotation",
"annotations.tests.NonAggregateAnnotationTestCase.test_order_by_aggregate",
"annotations.tests.NonAggregateAnnotationTestCase.test_q_expression_annotation_with_aggregation",
"defer_regress.tests.DeferRegressionTest.test_basic",
"defer_regress.tests.DeferRegressionTest.test_defer_annotate_select_related",
"defer_regress.tests.DeferRegressionTest.test_ticket_16409",
"expressions.tests.BasicExpressionsTests.test_aggregate_subquery_annotation",
"expressions.tests.FieldTransformTests.test_month_aggregation",
"expressions_case.tests.CaseDocumentationExamples.test_conditional_aggregation_example",
"model_fields.test_jsonfield.TestQuerying.test_ordering_grouping_by_count",
# Func not implemented.
"annotations.tests.NonAggregateAnnotationTestCase.test_custom_functions",
"annotations.tests.NonAggregateAnnotationTestCase.test_custom_functions_can_ref_other_functions",
# FieldDoesNotExist with ordering.
"annotations.tests.AliasTests.test_order_by_alias",
"annotations.tests.NonAggregateAnnotationTestCase.test_annotation_with_m2m",
"annotations.tests.NonAggregateAnnotationTestCase.test_mti_annotations",
"annotations.tests.NonAggregateAnnotationTestCase.test_order_by_aggregate",
"annotations.tests.NonAggregateAnnotationTestCase.test_order_by_annotation",
"expressions.tests.NegatedExpressionTests.test_filter",
"expressions_case.tests.CaseExpressionTests.test_annotate_values_not_in_order_by",
"expressions_case.tests.CaseExpressionTests.test_order_by_conditional_implicit",
"model_fields.test_jsonfield.TestQuerying.test_ordering_grouping_by_count",
"ordering.tests.OrderingTests.test_order_by_constant_value",
},
"Exists is not supported on MongoDB.": {
"annotations.tests.NonAggregateAnnotationTestCase.test_annotation_exists_none_query",
Expand Down
6 changes: 3 additions & 3 deletions django_mongodb/query.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ def order_by(self, ordering):
Reorder query results or execution order. Called by compiler during
query building.

`ordering` is a list with (field, ascending) tuples or a boolean --
`ordering` is a list with (column, ascending) tuples or a boolean --
use natural ordering, if any, when the argument is True and its reverse
otherwise.
"""
Expand All @@ -81,9 +81,9 @@ def order_by(self, ordering):
if not ordering:
self.ordering.append(("$natural", DESCENDING))
else:
for field, ascending in ordering:
for column, ascending in ordering:
direction = ASCENDING if ascending else DESCENDING
self.ordering.append((field.column, direction))
self.ordering.append((column, direction))

@wrap_database_errors
def delete(self):
Expand Down