Skip to content

add system check to prohibit AutoField #185

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 2 commits into from
Nov 11, 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
2 changes: 2 additions & 0 deletions django_mongodb/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from .query_utils import regex_match
from .schema import DatabaseSchemaEditor
from .utils import OperationDebugWrapper
from .validation import DatabaseValidation


class Cursor:
Expand Down Expand Up @@ -128,6 +129,7 @@ def _isnull_operator(a, b):
features_class = DatabaseFeatures
introspection_class = DatabaseIntrospection
ops_class = DatabaseOperations
validation_class = DatabaseValidation

def get_collection(self, name, **kwargs):
collection = Collection(self.database, name, **kwargs)
Expand Down
3 changes: 3 additions & 0 deletions django_mongodb/fields/auto.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ def get_prep_value(self, value):
return int(value)
raise ValueError(f"Field '{self.name}' expected an ObjectId but got {value!r}.") from e

def get_internal_type(self):
return "ObjectIdAutoField"

def db_type(self, connection):
return "objectId"

Expand Down
11 changes: 11 additions & 0 deletions django_mongodb/operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,17 @@ def explain_query_prefix(self, format=None, **options):
super().explain_query_prefix(format, **options)
return validated_options

def integer_field_range(self, internal_type):
# MongODB doesn't enforce any integer constraints, but it supports
# integers up to 64 bits.
if internal_type in {
"PositiveBigIntegerField",
"PositiveIntegerField",
"PositiveSmallIntegerField",
}:
return (0, 9223372036854775807)
return (-9223372036854775808, 9223372036854775807)

def prepare_join_on_clause(self, lhs_table, lhs_field, rhs_table, rhs_field):
lhs_expr, rhs_expr = super().prepare_join_on_clause(
lhs_table, lhs_field, rhs_table, rhs_field
Expand Down
20 changes: 20 additions & 0 deletions django_mongodb/validation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from django.core import checks
from django.db.backends.base.validation import BaseDatabaseValidation


class DatabaseValidation(BaseDatabaseValidation):
prohibited_fields = {"AutoField", "BigAutoField", "SmallAutoField"}

def check_field_type(self, field, field_type):
"""Prohibit AutoField on MongoDB."""
errors = []
if field.get_internal_type() in self.prohibited_fields:
errors.append(
checks.Error(
f"{self.connection.display_name} does not support {field.__class__.__name__}.",
obj=field,
hint="Use django_mongodb.fields.ObjectIdAutoField instead.",
id="mongodb.E001",
)
)
return errors
Empty file.
63 changes: 63 additions & 0 deletions tests/invalid_models_tests_/test_autofield.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
from django.core.checks import Error
from django.db import connection, models
from django.test import SimpleTestCase
from django.test.utils import isolate_apps

from django_mongodb.validation import DatabaseValidation


@isolate_apps("invalid_models_tests")
class ProhibitedFieldTests(SimpleTestCase):
def test_autofield(self):
class Model(models.Model):
id = models.AutoField(primary_key=True)

field = Model._meta.get_field("id")
validator = DatabaseValidation(connection=connection)
self.assertEqual(
validator.check_field(field),
[
Error(
"MongoDB does not support AutoField.",
hint="Use django_mongodb.fields.ObjectIdAutoField instead.",
obj=field,
id="mongodb.E001",
)
],
)

def test_bigautofield(self):
class Model(models.Model):
id = models.BigAutoField(primary_key=True)

field = Model._meta.get_field("id")
validator = DatabaseValidation(connection=connection)
self.assertEqual(
validator.check_field(field),
[
Error(
"MongoDB does not support BigAutoField.",
hint="Use django_mongodb.fields.ObjectIdAutoField instead.",
obj=field,
id="mongodb.E001",
)
],
)

def test_smallautofield(self):
class Model(models.Model):
id = models.SmallAutoField(primary_key=True)

field = Model._meta.get_field("id")
validator = DatabaseValidation(connection=connection)
self.assertEqual(
validator.check_field(field),
[
Error(
"MongoDB does not support SmallAutoField.",
hint="Use django_mongodb.fields.ObjectIdAutoField instead.",
obj=field,
id="mongodb.E001",
)
],
)
4 changes: 4 additions & 0 deletions tests/model_fields_/test_autofield.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ def test_deconstruct(self):
self.assertEqual(args, [])
self.assertEqual(kwargs, {"primary_key": True})

def test_get_internal_type(self):
f = ObjectIdAutoField()
self.assertEqual(f.get_internal_type(), "ObjectIdAutoField")

def test_to_python(self):
f = ObjectIdAutoField()
self.assertEqual(f.to_python("1"), 1)