Skip to content
Draft
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
4 changes: 2 additions & 2 deletions .evergreen/run-tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@
set -eux

# Install django-mongodb-backend
/opt/python/3.10/bin/python3 -m venv venv
/opt/python/3.12/bin/python3 -m venv venv
. venv/bin/activate
python -m pip install -U pip
pip install -e .

# Install django and test dependencies
git clone --branch mongodb-5.2.x https://github.com/mongodb-forks/django django_repo
git clone --branch mongodb-6.0.x https://github.com/mongodb-forks/django django_repo
pushd django_repo/tests/
pip install -e ..
pip install -r requirements/py3.txt
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/linters.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
persist-credentials: false
- uses: actions/setup-python@v6
with:
python-version: '3.10'
python-version: '3.12'
cache: 'pip'
cache-dependency-path: 'pyproject.toml'
- name: Install Python dependencies
Expand All @@ -39,7 +39,7 @@ jobs:
with:
cache: 'pip'
cache-dependency-path: 'pyproject.toml'
python-version: '3.10'
python-version: '3.12'
- name: Install dependencies
run: |
pip install -U pip
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test-python-atlas.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ jobs:
uses: actions/checkout@v5
with:
repository: 'mongodb-forks/django'
ref: 'mongodb-5.2.x'
ref: 'mongodb-6.0.x'
path: 'django_repo'
persist-credentials: false
- name: Install system packages for Django's Python test dependencies
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test-python-geo.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ jobs:
uses: actions/checkout@v5
with:
repository: 'mongodb-forks/django'
ref: 'mongodb-5.2.x'
ref: 'mongodb-6.0.x'
path: 'django_repo'
persist-credentials: false
- name: Install system packages for Django's Python test dependencies
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test-python.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ jobs:
uses: actions/checkout@v5
with:
repository: 'mongodb-forks/django'
ref: 'mongodb-5.2.x'
ref: 'mongodb-6.0.x'
path: 'django_repo'
persist-credentials: false
- name: Install system packages for Django's Python test dependencies
Expand Down
4 changes: 2 additions & 2 deletions .readthedocs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,6 @@ python:
- docs

build:
os: ubuntu-22.04
os: ubuntu-24.04
tools:
python: "3.11"
python: "3.12"
6 changes: 2 additions & 4 deletions django_mongodb_backend/__init__.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
__version__ = "5.2.2.dev0"
__version__ = "6.0.0b0.dev0"

# Check Django compatibility before other imports which may fail if the
# wrong version of Django is installed.
from .utils import check_django_compatability, parse_uri
from .utils import check_django_compatability

check_django_compatability()

Expand All @@ -15,8 +15,6 @@
from .lookups import register_lookups # noqa: E402
from .query import register_nodes # noqa: E402

__all__ = ["parse_uri"]

register_aggregates()
register_checks()
register_expressions()
Expand Down
28 changes: 25 additions & 3 deletions django_mongodb_backend/aggregates.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
from django.db.models.aggregates import Aggregate, Count, StdDev, Variance
from django.db.models.expressions import Case, Value, When
from django.db import NotSupportedError
from django.db.models.aggregates import (
Aggregate,
AggregateFilter,
Count,
StdDev,
StringAgg,
Variance,
)
from django.db.models.expressions import Case, Col, Value, When
from django.db.models.lookups import IsNull

from .query_utils import process_lhs
Expand All @@ -16,7 +24,11 @@ def aggregate(
resolve_inner_expression=False,
**extra_context, # noqa: ARG001
):
if self.filter:
# TODO: isinstance(self.filter, Col) works around failure of
# aggregation.tests.AggregateTestCase.test_distinct_on_aggregate. Is this
# correct?
if self.filter is not None and not isinstance(self.filter, Col):
# Generate a CASE statement for this aggregate.
node = self.copy()
node.filter = None
source_expressions = node.get_source_expressions()
Expand All @@ -31,6 +43,10 @@ def aggregate(
return {f"${operator}": lhs_mql}


def aggregate_filter(self, compiler, connection, **extra_context):
return self.condition.as_mql(compiler, connection, **extra_context)


def count(self, compiler, connection, resolve_inner_expression=False, **extra_context): # noqa: ARG001
"""
When resolve_inner_expression=True, return the MQL that resolves as a
Expand Down Expand Up @@ -72,8 +88,14 @@ def stddev_variance(self, compiler, connection, **extra_context):
return aggregate(self, compiler, connection, operator=operator, **extra_context)


def string_agg(self, compiler, connection, **extra_context): # noqa: ARG001
raise NotSupportedError("StringAgg is not supported.")


def register_aggregates():
Aggregate.as_mql = aggregate
AggregateFilter.as_mql = aggregate_filter
Count.as_mql = count
StdDev.as_mql = stddev_variance
StringAgg.as_mql = string_agg
Variance.as_mql = stddev_variance
18 changes: 18 additions & 0 deletions django_mongodb_backend/features.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,18 @@ class DatabaseFeatures(GISFeatures, BaseDatabaseFeatures):
"model_fields.test_jsonfield.TestSaveLoad.test_bulk_update_custom_get_prep_value",
# To debug: https://github.com/mongodb/django-mongodb-backend/issues/362
"constraints.tests.UniqueConstraintTests.test_validate_case_when",
# StringAgg is not supported.
"aggregation.tests.AggregateTestCase.test_distinct_on_stringagg",
"aggregation.tests.AggregateTestCase.test_string_agg_escapes_delimiter",
"aggregation.tests.AggregateTestCase.test_string_agg_filter",
"aggregation.tests.AggregateTestCase.test_string_agg_filter_in_subquery",
"aggregation.tests.AggregateTestCase.test_stringagg_default_value",
# bulk_create() population of _order not implemented.
# https://github.com/django/django/commit/953095d1e603fe0f8f01175b1409ca23818dcff9
"contenttypes_tests.test_order_with_respect_to.OrderWithRespectToGFKTests.test_bulk_create_allows_duplicate_order_values",
"contenttypes_tests.test_order_with_respect_to.OrderWithRespectToGFKTests.test_bulk_create_mixed_scenario",
"contenttypes_tests.test_order_with_respect_to.OrderWithRespectToGFKTests.test_bulk_create_respects_mixed_manual_order",
"contenttypes_tests.test_order_with_respect_to.OrderWithRespectToGFKTests.test_bulk_create_with_existing_children",
}
# $bitAnd, #bitOr, and $bitXor are new in MongoDB 6.3.
_django_test_expected_failures_bitwise = {
Expand Down Expand Up @@ -142,6 +154,7 @@ def django_test_expected_failures(self):
"validation.test_unique.PerformUniqueChecksTest.test_unique_db_default",
},
"Insert expressions aren't supported.": {
"basic.tests.ModelTest.test_save_expressions",
"bulk_create.tests.BulkCreateTests.test_bulk_insert_now",
"bulk_create.tests.BulkCreateTests.test_bulk_insert_expressions",
"expressions.tests.BasicExpressionsTests.test_new_object_create",
Expand Down Expand Up @@ -204,6 +217,7 @@ def django_test_expected_failures(self):
"prefetch_related.tests.LookupOrderingTest.test_order",
"prefetch_related.tests.MultiDbTests.test_using_is_honored_m2m",
"prefetch_related.tests.MultiTableInheritanceTest",
"prefetch_related.tests.PrefetchRelatedMTICacheTests",
"prefetch_related.tests.PrefetchRelatedTests",
"prefetch_related.tests.ReadPrefetchedObjectsCacheTests",
"prefetch_related.tests.Ticket21410Tests",
Expand Down Expand Up @@ -566,6 +580,7 @@ def django_test_expected_failures(self):
"Custom lookups are not supported.": {
"custom_lookups.tests.BilateralTransformTests",
"custom_lookups.tests.LookupTests.test_basic_lookup",
"custom_lookups.tests.LookupTests.test_custom_lookup_with_subquery",
"custom_lookups.tests.LookupTests.test_custom_name_lookup",
"custom_lookups.tests.LookupTests.test_div3_extract",
"custom_lookups.tests.SubqueryTransformTests.test_subquery_usage",
Expand All @@ -583,6 +598,9 @@ def django_test_expected_failures(self):
"test_utils.tests.DisallowedDatabaseQueriesTests.test_disallowed_database_queries",
"test_utils.tests.DisallowedDatabaseQueriesTests.test_disallowed_thread_database_connection",
},
"search lookup not supported on non-Atlas.": {
"expressions.tests.BasicExpressionsTests.test_lookups_subquery",
},
}

@cached_property
Expand Down
7 changes: 6 additions & 1 deletion django_mongodb_backend/fields/json.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,12 @@ def build_json_mql_path(lhs, key_transforms):
get_field = {"$getField": {"input": result, "field": key}}
# Handle array indexing if the key is a digit. If key is something
# like '001', it's not an array index despite isdigit() returning True.
if key.isdigit() and str(int(key)) == key:
try:
int(key)
is_digit = str(int(key)) == key
except ValueError:
is_digit = False
if is_digit:
result = {
"$cond": {
"if": {"$isArray": result},
Expand Down
2 changes: 2 additions & 0 deletions django_mongodb_backend/gis/operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ def gis_operators(self):
"FromWKT",
"GeoHash",
"GeometryDistance",
"GeometryType",
"Intersection",
"IsEmpty",
"IsValid",
Expand All @@ -52,6 +53,7 @@ def gis_operators(self):
"Perimeter",
"PointOnSurface",
"Reverse",
"Rotate",
"Scale",
"SnapToGrid",
"SymDifference",
Expand Down
47 changes: 0 additions & 47 deletions django_mongodb_backend/utils.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
import copy
import time
import warnings

import django
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured, ValidationError
from django.db.backends.utils import logger
from django.utils.deprecation import RemovedInDjango60Warning
from django.utils.functional import SimpleLazyObject
from django.utils.text import format_lazy
from django.utils.version import get_version_tuple
from pymongo.uri_parser import parse_uri as pymongo_parse_uri


def check_django_compatability():
Expand All @@ -30,50 +27,6 @@ def check_django_compatability():
)


def parse_uri(uri, *, db_name=None, options=None, test=None):
"""
Convert the given uri into a dictionary suitable for Django's DATABASES
setting.
"""
warnings.warn(
'parse_uri() is deprecated. Put the connection string in DATABASES["HOST"] instead.',
RemovedInDjango60Warning,
stacklevel=2,
)
uri = pymongo_parse_uri(uri)
host = None
port = None
if uri["fqdn"]:
# This is a SRV URI and the host is the fqdn.
host = f"mongodb+srv://{uri['fqdn']}"
else:
nodelist = uri.get("nodelist")
if len(nodelist) == 1:
host, port = nodelist[0]
elif len(nodelist) > 1:
host = ",".join([f"{host}:{port}" for host, port in nodelist])
db_name = db_name or uri["database"]
if not db_name:
raise ImproperlyConfigured("You must provide the db_name parameter.")
opts = uri.get("options")
if options:
opts.update(options)
settings_dict = {
"ENGINE": "django_mongodb_backend",
"NAME": db_name,
"HOST": host,
"PORT": port,
"USER": uri.get("username"),
"PASSWORD": uri.get("password"),
"OPTIONS": opts,
}
if "authSource" not in settings_dict["OPTIONS"] and uri["database"]:
settings_dict["OPTIONS"]["authSource"] = uri["database"]
if test:
settings_dict["TEST"] = test
return settings_dict


def prefix_validation_error(error, prefix, code, params):
"""
Prefix a validation error message while maintaining the existing
Expand Down
4 changes: 1 addition & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ dynamic = ["version", "dependencies"]
description = "Django MongoDB Backend"
readme = "README.md"
license = {file="LICENSE"}
requires-python = ">=3.10"
requires-python = ">=3.12"
authors = [
{ name = "The MongoDB Python Team" },
]
Expand All @@ -27,8 +27,6 @@ classifiers = [
"Operating System :: OS Independent",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
]
Expand Down
Empty file removed tests/backend_/utils/__init__.py
Empty file.
Loading