Fixed #14028 - Added validation for clashing db_columns.
Thanks akaariai for the suggestion.
This commit is contained in:
parent
a53caf28bf
commit
41167645b1
|
@ -63,6 +63,9 @@ def get_validation_errors(outfile, app=None):
|
||||||
if not opts.get_field(cls.USERNAME_FIELD).unique:
|
if not opts.get_field(cls.USERNAME_FIELD).unique:
|
||||||
e.add(opts, 'The USERNAME_FIELD must be unique. Add unique=True to the field parameters.')
|
e.add(opts, 'The USERNAME_FIELD must be unique. Add unique=True to the field parameters.')
|
||||||
|
|
||||||
|
# Store a list of column names which have already been used by other fields.
|
||||||
|
used_column_names = []
|
||||||
|
|
||||||
# Model isn't swapped; do field-specific validation.
|
# Model isn't swapped; do field-specific validation.
|
||||||
for f in opts.local_fields:
|
for f in opts.local_fields:
|
||||||
if f.name == 'id' and not f.primary_key and opts.pk.name == 'id':
|
if f.name == 'id' and not f.primary_key and opts.pk.name == 'id':
|
||||||
|
@ -75,6 +78,17 @@ def get_validation_errors(outfile, app=None):
|
||||||
# consider NULL and '' to be equal (and thus set up
|
# consider NULL and '' to be equal (and thus set up
|
||||||
# character-based fields a little differently).
|
# character-based fields a little differently).
|
||||||
e.add(opts, '"%s": Primary key fields cannot have null=True.' % f.name)
|
e.add(opts, '"%s": Primary key fields cannot have null=True.' % f.name)
|
||||||
|
|
||||||
|
# Column name validation.
|
||||||
|
# Determine which column name this field wants to use.
|
||||||
|
_, column_name = f.get_attname_column()
|
||||||
|
|
||||||
|
# Ensure the column name is not already in use.
|
||||||
|
if column_name and column_name in used_column_names:
|
||||||
|
e.add(opts, "Field '%s' has column name '%s' that is already used." % (f.name, column_name))
|
||||||
|
else:
|
||||||
|
used_column_names.append(column_name)
|
||||||
|
|
||||||
if isinstance(f, models.CharField):
|
if isinstance(f, models.CharField):
|
||||||
try:
|
try:
|
||||||
max_length = int(f.max_length)
|
max_length = int(f.max_length)
|
||||||
|
|
|
@ -364,6 +364,56 @@ class BadIndexTogether1(models.Model):
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class DuplicateColumnNameModel1(models.Model):
|
||||||
|
"""
|
||||||
|
A field (bar) attempts to use a column name which is already auto-assigned
|
||||||
|
earlier in the class. This should raise a validation error.
|
||||||
|
"""
|
||||||
|
foo = models.IntegerField()
|
||||||
|
bar = models.IntegerField(db_column='foo')
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
db_table = 'foobar'
|
||||||
|
|
||||||
|
|
||||||
|
class DuplicateColumnNameModel2(models.Model):
|
||||||
|
"""
|
||||||
|
A field (foo) attempts to use a column name which is already auto-assigned
|
||||||
|
later in the class. This should raise a validation error.
|
||||||
|
"""
|
||||||
|
foo = models.IntegerField(db_column='bar')
|
||||||
|
bar = models.IntegerField()
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
db_table = 'foobar'
|
||||||
|
|
||||||
|
|
||||||
|
class DuplicateColumnNameModel3(models.Model):
|
||||||
|
"""Two fields attempt to use each others' names.
|
||||||
|
|
||||||
|
This is not a desirable scenario but valid nonetheless.
|
||||||
|
|
||||||
|
It should not raise a validation error.
|
||||||
|
"""
|
||||||
|
foo = models.IntegerField(db_column='bar')
|
||||||
|
bar = models.IntegerField(db_column='foo')
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
db_table = 'foobar3'
|
||||||
|
|
||||||
|
|
||||||
|
class DuplicateColumnNameModel4(models.Model):
|
||||||
|
"""Two fields attempt to use the same db_column value.
|
||||||
|
|
||||||
|
This should raise a validation error.
|
||||||
|
"""
|
||||||
|
foo = models.IntegerField(db_column='baz')
|
||||||
|
bar = models.IntegerField(db_column='baz')
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
db_table = 'foobar'
|
||||||
|
|
||||||
|
|
||||||
model_errors = """invalid_models.fielderrors: "charfield": CharFields require a "max_length" attribute that is a positive integer.
|
model_errors = """invalid_models.fielderrors: "charfield": CharFields require a "max_length" attribute that is a positive integer.
|
||||||
invalid_models.fielderrors: "charfield2": CharFields require a "max_length" attribute that is a positive integer.
|
invalid_models.fielderrors: "charfield2": CharFields require a "max_length" attribute that is a positive integer.
|
||||||
invalid_models.fielderrors: "charfield3": CharFields require a "max_length" attribute that is a positive integer.
|
invalid_models.fielderrors: "charfield3": CharFields require a "max_length" attribute that is a positive integer.
|
||||||
|
@ -477,6 +527,9 @@ invalid_models.hardreferencemodel: 'm2m_4' defines a relation with the model 'in
|
||||||
invalid_models.badswappablevalue: TEST_SWAPPED_MODEL_BAD_VALUE is not of the form 'app_label.app_name'.
|
invalid_models.badswappablevalue: TEST_SWAPPED_MODEL_BAD_VALUE is not of the form 'app_label.app_name'.
|
||||||
invalid_models.badswappablemodel: Model has been swapped out for 'not_an_app.Target' which has not been installed or is abstract.
|
invalid_models.badswappablemodel: Model has been swapped out for 'not_an_app.Target' which has not been installed or is abstract.
|
||||||
invalid_models.badindextogether1: "index_together" refers to field_that_does_not_exist, a field that doesn't exist.
|
invalid_models.badindextogether1: "index_together" refers to field_that_does_not_exist, a field that doesn't exist.
|
||||||
|
invalid_models.duplicatecolumnnamemodel1: Field 'bar' has column name 'foo' that is already used.
|
||||||
|
invalid_models.duplicatecolumnnamemodel2: Field 'bar' has column name 'bar' that is already used.
|
||||||
|
invalid_models.duplicatecolumnnamemodel4: Field 'bar' has column name 'baz' that is already used.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if not connection.features.interprets_empty_strings_as_nulls:
|
if not connection.features.interprets_empty_strings_as_nulls:
|
||||||
|
|
Loading…
Reference in New Issue