8000 Another approach · django/django@a74954a · GitHub
[go: up one dir, main page]

Skip to content

Commit a74954a

Browse files
committed
Another approach
1 parent d5c2e92 commit a74954a

File tree

4 files changed

+17
-21
lines changed

4 files changed

+17
-21
lines changed

django/db/backends/base/schema.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -923,11 +923,8 @@ def alter_field(self, model, old_field, new_field, strict=False):
923923
def _field_db_check(self, field, field_db_params):
924924
# Always check constraints with the same mocked column name to avoid
925925
# recreating constrains when the column is renamed.
926-
if (constraint := field.db_check(self.connection)) is None:
927-
return None
928-
data = field.db_type_parameters(self.connection)
929-
data["column"] = "__column_name__"
930-
return constraint % data
926+
overrides = {"column": "__column_name__"}
927+
return field.db_check(self.connection, **overrides)
931928

932929
def _alter_field(
933930
self,

django/db/models/fields/__init__.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -840,13 +840,15 @@ def clean(self, value, model_instance):
840840
def db_type_parameters(self, connection):
841841
return DictWrapper(self.__dict__, connection.ops.quote_name, "qn_")
842842

843-
def db_check(self, connection):
843+
def db_check(self, connection, **overrides):
844844
"""
845845
Return the database column check constraint for this field, for the
846846
provided connection. Works the same way as db_type() for the case that
847847
get_internal_type() does not map to a preexisting model field.
848+
Any keyword arguments provided will override the ones received from
849+
db_type_parameters() and used for formatting the constraint's SQL string.
848850
"""
849-
data = self.db_type_parameters(connection)
851+
data = self.db_type_parameters(connection) | overrides
850852
try:
851853
return (
852854
connection.data_type_check_constraints[self.get_internal_type()] % data

django/db/models/fields/related.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1215,7 +1215,7 @@ def formfield(self, *, using=None, **kwargs):
12151215
}
12161216
)
12171217

1218-
def db_check(self, connection):
1218+
def db_check(self, connection, **overrides):
12191219
return None
12201220

12211221
def db_type(self, connection):
@@ -2052,7 +2052,7 @@ def formfield(self, *, using=None, **kwargs):
20522052
defaults["initial"] = [i.pk for i in initial]
20532053
return super().formfield(**defaults)
20542054

2055-
def db_check(self, connection):
2055+
def db_check(self, connection, **overrides):
20562056
return None
20572057

20582058
def db_type(self, connection):

tests/schema/tests.py

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@
6565
Upper,
6666
)
6767
from django.db.models.indexes import IndexExpression
68+
from django.db.models.lookups import In as InLookup
6869
from django.db.transaction import TransactionManagementError, atomic
6970
from django.test import TransactionTestCase, skipIfDBFeature, skipUnlessDBFeature
7071
from django.test.utils import CaptureQueriesContext, isolate_apps, register_lookup
@@ -2486,18 +2487,20 @@ class CharChoiceField(CharField):
24862487
A custom CharField that automatically creates a db constraint to guarante
24872488
that the stored value respects the field's `choices`.
24882489
"""
2490+
24892491
@property
24902492
def non_db_attrs(self):
24912493
# Remove `choices` from non_db_attrs so that migrations that only change
24922494
# choices still trigger a db operation and drop/create the constraint.
24932495
attrs = super().non_db_attrs
24942496
return tuple({*attrs} - {"choices"})
24952497

2496-
def db_check(self, connection):
2498+
def db_check(self, connection, **overrides):
24972499
if not self.choices:
24982500
return None
2501+
data = self.db_type_parameters(connection) | overrides
24992502
constraint = CheckConstraint(
2500-
condition=Q(**{f"{self.name}__in": dict(self.choices)}),
2503+
condition=InLookup(F(data["column"]), dict(self.choices)),
25012504
name="", # doesn't matter, Django will reassign one anyway
25022505
)
25032506
with connection.schema_editor() as schema_editor:
@@ -2513,23 +2516,17 @@ class Meta:
25132516
with connection.schema_editor() as editor:
25142517
editor.create_model(ModelWithCustomField)
25152518

2516-
constraints = self.get_constraints(ModelWithCustomField._meta.db_table)
2517-
self.assertEqual(
2518-
len(constraints),
2519-
1, # just the pk constraint
2520-
)
2519+
constraints = self.get_constraints_for_column(ModelWithCustomField, "f")
2520+
self.assertEqual(len(constraints), 0)
25212521

25222522
old_field = ModelWithCustomField._meta.get_field("f")
25232523
new_field = CharChoiceField(choices=[("a", "a")])
25242524
new_field.contribute_to_class(ModelWithCustomField, "f")
25252525
with connection.schema_editor() as editor:
25262526
editor.alter_field(ModelWithCustomField, old_field, new_field, strict=True)
25272527

2528-
constraints = self.get_constraints(ModelWithCustomField._meta.db_table)
2529-
self.assertEqual(
2530-
len(constraints),
2531-
2, # pk + custom constraint
2532-
)
2528+
constraints = self.get_constraints_for_column(ModelWithCustomField, "f")
2529+
self.assertEqual(len(constraints), 1)
25332530

25342531
def _test_m2m_create(self, M2MFieldClass):
25352532
"""

0 commit comments

Comments
 (0)
0