diff --git a/django_mongodb/compiler.py b/django_mongodb/compiler.py index e1159a743..bf2dbc973 100644 --- a/django_mongodb/compiler.py +++ b/django_mongodb/compiler.py @@ -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 @@ -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) @@ -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): diff --git a/django_mongodb/features.py b/django_mongodb/features.py index 32b20e306..7989438ee 100644 --- a/django_mongodb/features.py +++ b/django_mongodb/features.py @@ -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", @@ -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", @@ -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 = { @@ -280,6 +287,7 @@ 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", @@ -287,20 +295,10 @@ def django_test_expected_failures(self): "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", diff --git a/django_mongodb/query.py b/django_mongodb/query.py index e56016868..9879e878a 100644 --- a/django_mongodb/query.py +++ b/django_mongodb/query.py @@ -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. """ @@ -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):