diff --git a/.github/workflows/test-python.yml b/.github/workflows/test-python.yml index 1d38102f2..95b78ecfa 100644 --- a/.github/workflows/test-python.yml +++ b/.github/workflows/test-python.yml @@ -97,6 +97,7 @@ jobs: m2m_through_regress m2o_recursive model_fields + model_forms one_to_one ordering or_lookups diff --git a/django_mongodb/features.py b/django_mongodb/features.py index 822f190a3..7fd858707 100644 --- a/django_mongodb/features.py +++ b/django_mongodb/features.py @@ -113,6 +113,7 @@ def django_test_expected_failures(self): "QuerySet.prefetch_related() is not supported on MongoDB.": { "m2m_through_regress.test_multitable.MultiTableTests.test_m2m_prefetch_proxied", "m2m_through_regress.test_multitable.MultiTableTests.test_m2m_prefetch_reverse_proxied", + "model_forms.tests.OtherModelFormTests.test_prefetch_related_queryset", }, "QuerySet.update() with expression not supported.": { "annotations.tests.AliasTests.test_update_with_alias", @@ -235,6 +236,11 @@ def django_test_expected_failures(self): "lookup.tests.LookupTests.test_exact_exists", "lookup.tests.LookupTests.test_nested_outerref_lhs", "lookup.tests.LookupQueryingTests.test_filter_exists_lhs", + "model_forms.tests.LimitChoicesToTests.test_fields_for_model_applies_limit_choices_to", + "model_forms.tests.LimitChoicesToTests.test_limit_choices_to_callable_for_fk_rel", + "model_forms.tests.LimitChoicesToTests.test_limit_choices_to_callable_for_m2m_rel", + "model_forms.tests.LimitChoicesToTests.test_limit_choices_to_m2m_through", + "model_forms.tests.LimitChoicesToTests.test_limit_choices_to_no_duplicates", "queries.tests.ExcludeTest17600.test_exclude_plain", "queries.tests.ExcludeTest17600.test_exclude_with_q_is_equal_to_plain_exclude_variation", "queries.tests.ExcludeTest17600.test_exclude_with_q_object_no_distinct", diff --git a/django_mongodb/fields/auto.py b/django_mongodb/fields/auto.py index 1a7975177..f27d60517 100644 --- a/django_mongodb/fields/auto.py +++ b/django_mongodb/fields/auto.py @@ -1,6 +1,7 @@ from bson import ObjectId, errors from django.core import exceptions from django.db.models.fields import AutoField, Field +from django.utils.functional import cached_property from django.utils.translation import gettext_lazy as _ @@ -15,14 +16,26 @@ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) def get_prep_value(self, value): - # Override AutoField casting to integer. - return Field.get_prep_value(self, value) + if value is None: + return None + # Accept int for compatibility with Django's test suite which has many + # instances of manually assigned integer IDs, as well as for things + # like settings.SITE_ID which has a system check requiring an integer. + if isinstance(value, (ObjectId | int)): + return value + try: + return ObjectId(value) + except errors.InvalidId as e: + # A manually assigned integer ID? + if isinstance(value, str) and value.isdigit(): + return int(value) + raise ValueError(f"Field '{self.name}' expected an ObjectId but got {value!r}.") from e def rel_db_type(self, connection): return Field().db_type(connection=connection) def to_python(self, value): - if value is None: + if value is None or isinstance(value, int): return value try: return ObjectId(value) @@ -32,3 +45,8 @@ def to_python(self, value): code="invalid", params={"value": value}, ) from None + + @cached_property + def validators(self): + # Avoid IntegerField validators inherited from AutoField. + return [*self.default_validators, *self._validators]