diff --git a/README.md b/README.md index 7fe76a1e7..fe2785b9b 100644 --- a/README.md +++ b/README.md @@ -116,6 +116,9 @@ Migrations for 'admin': - `extra()` - `select_related()` +- `Subquery`, `Exists`, and using a `QuerySet` in `QuerySet.annotate()` aren't + supported. + - Queries with joins aren't supported. - `DateTimeField` doesn't support microsecond precision, and correspondingly, diff --git a/django_mongodb/expressions.py b/django_mongodb/expressions.py index f08e6c666..d00c3e295 100644 --- a/django_mongodb/expressions.py +++ b/django_mongodb/expressions.py @@ -3,15 +3,18 @@ from bson import Decimal128 from django.core.exceptions import EmptyResultSet, FullResultSet +from django.db import NotSupportedError from django.db.models.expressions import ( Case, Col, CombinedExpression, ExpressionWrapper, NegatedExpression, + Subquery, Value, When, ) +from django.db.models.sql import Query def case(self, compiler, connection): @@ -59,6 +62,14 @@ def negated_expression(self, compiler, connection): return {"$not": expression_wrapper(self, compiler, connection)} +def query(self, compiler, connection): # noqa: ARG001 + raise NotSupportedError("Using a QuerySet in annotate() is not supported on MongoDB.") + + +def subquery(self, compiler, connection): # noqa: ARG001 + raise NotSupportedError(f"{self.__class__.__name__} is not supported on MongoDB.") + + def when(self, compiler, connection): return self.condition.as_mql(compiler, connection) @@ -82,5 +93,7 @@ def register_expressions(): CombinedExpression.as_mql = combined_expression ExpressionWrapper.as_mql = expression_wrapper NegatedExpression.as_mql = negated_expression + Query.as_mql = query + Subquery.as_mql = subquery When.as_mql = when Value.as_mql = value diff --git a/django_mongodb/features.py b/django_mongodb/features.py index 7779d886d..1eaf9130e 100644 --- a/django_mongodb/features.py +++ b/django_mongodb/features.py @@ -59,10 +59,6 @@ class DatabaseFeatures(BaseDatabaseFeatures): # the result back to UTC. "db_functions.datetime.test_extract_trunc.DateFunctionWithTimeZoneTests.test_trunc_func_with_timezone", "db_functions.datetime.test_extract_trunc.DateFunctionWithTimeZoneTests.test_trunc_timezone_applied_before_truncation", - # pk__in=queryset doesn't work because subqueries aren't a thing in - # MongoDB. - "annotations.tests.NonAggregateAnnotationTestCase.test_annotation_and_alias_filter_in_subquery", - "model_fields.test_jsonfield.TestQuerying.test_usage_in_subquery", # Length of null considered zero rather than null. "db_functions.text.test_length.LengthTests.test_basic", # Key transforms are incorrectly treated as joins: @@ -220,25 +216,11 @@ def django_test_expected_failures(self): "timezones.tests.NewDatabaseTests.test_query_aggregation", }, "QuerySet.annotate() has some limitations.": { - # Exists not supported. - "annotations.tests.NonAggregateAnnotationTestCase.test_annotation_exists_none_query", - "lookup.tests.LookupTests.test_exact_exists", - "lookup.tests.LookupTests.test_nested_outerref_lhs", - "lookup.tests.LookupQueryingTests.test_filter_exists_lhs", # annotate() with combined expressions doesn't work: # 'WhereNode' object has no attribute 'field' "lookup.tests.LookupQueryingTests.test_combined_annotated_lookups_in_filter", "lookup.tests.LookupQueryingTests.test_combined_annotated_lookups_in_filter_false", "lookup.tests.LookupQueryingTests.test_combined_lookups", - # Subquery not supported. - "annotations.tests.NonAggregateAnnotationTestCase.test_empty_queryset_annotation", - "db_functions.comparison.test_coalesce.CoalesceTests.test_empty_queryset", - "db_functions.datetime.test_extract_trunc.DateFunctionTests.test_extract_outerref", - "db_functions.datetime.test_extract_trunc.DateFunctionTests.test_trunc_subquery_with_parameters", - "expressions_case.tests.CaseExpressionTests.test_in_subquery", - "lookup.tests.LookupQueryingTests.test_filter_subquery_lhs", - "model_fields.test_jsonfield.TestQuerying.test_nested_key_transform_on_subquery", - "model_fields.test_jsonfield.TestQuerying.test_obj_subquery_lookup", # Invalid $project :: caused by :: Unknown expression $count, "annotations.tests.NonAggregateAnnotationTestCase.test_combined_expression_annotation_with_aggregation", "annotations.tests.NonAggregateAnnotationTestCase.test_combined_f_expression_annotation_with_aggregation", @@ -263,6 +245,28 @@ def django_test_expected_failures(self): # annotate().filter().count() gives incorrect results. "db_functions.datetime.test_extract_trunc.DateFunctionTests.test_extract_year_exact_lookup", }, + "Exists is not supported on MongoDB.": { + "annotations.tests.NonAggregateAnnotationTestCase.test_annotation_exists_none_query", + "lookup.tests.LookupTests.test_exact_exists", + "lookup.tests.LookupTests.test_nested_outerref_lhs", + "lookup.tests.LookupQueryingTests.test_filter_exists_lhs", + }, + "Subquery is not supported on MongoDB.": { + "annotations.tests.NonAggregateAnnotationTestCase.test_empty_queryset_annotation", + "db_functions.datetime.test_extract_trunc.DateFunctionTests.test_extract_outerref", + "db_functions.datetime.test_extract_trunc.DateFunctionTests.test_trunc_subquery_with_parameters", + "lookup.tests.LookupQueryingTests.test_filter_subquery_lhs", + "model_fields.test_jsonfield.TestQuerying.test_nested_key_transform_on_subquery", + "model_fields.test_jsonfield.TestQuerying.test_obj_subquery_lookup", + }, + "Using a QuerySet in annotate() is not supported on MongoDB.": { + "annotations.tests.NonAggregateAnnotationTestCase.test_annotation_and_alias_filter_in_subquery", + "annotations.tests.NonAggregateAnnotationTestCase.test_empty_expression_annotation", + "db_functions.comparison.test_coalesce.CoalesceTests.test_empty_queryset", + "expressions_case.tests.CaseExpressionTests.test_in_subquery", + "lookup.tests.LookupTests.test_in_different_database", + "model_fields.test_jsonfield.TestQuerying.test_usage_in_subquery", + }, "Count doesn't work in QuerySet.annotate()": { "annotations.tests.AliasTests.test_alias_annotate_with_aggregation", "annotations.tests.AliasTests.test_order_by_alias_aggregate",