Skip to content

Commit

Permalink
Fixed #31410 -- Added check for fields of UniqueConstraints.
Browse files Browse the repository at this point in the history
  • Loading branch information
hramezani committed May 20, 2020
1 parent 20a8a44 commit 8566d6b
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 0 deletions.
3 changes: 3 additions & 0 deletions django/db/models/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -1926,6 +1926,9 @@ def _check_constraints(cls, databases):
id='models.W038',
)
)
for constraint in cls._meta.constraints:
if isinstance(constraint, UniqueConstraint):
errors.extend(cls._check_local_fields(constraint.fields, "unique_constraint"))
return errors


Expand Down
62 changes: 62 additions & 0 deletions tests/invalid_models_tests/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -1414,6 +1414,68 @@ class Meta:
constraints = [models.CheckConstraint(check=models.Q(age__gte=18), name='is_adult')]
self.assertEqual(Model.check(databases=self.databases), [])

def test_unique_constraint_pointing_to_missing_field(self):
class Model(models.Model):
class Meta:
constraints = [models.UniqueConstraint(fields=['missing_field'], name='name')]

self.assertEqual(Model.check(databases=self.databases), [
Error(
"'unique_constraint' refers to the nonexistent field 'missing_field'.",
obj=Model,
id='models.E012',
),
])

def test_unique_constraint_pointing_to_m2m_field(self):
class Model(models.Model):
m2m = models.ManyToManyField('self')

class Meta:
constraints = [models.UniqueConstraint(fields=['m2m'], name='name1')]

self.assertEqual(Model.check(databases=self.databases), [
Error(
"'unique_constraint' refers to a ManyToManyField 'm2m', but "
"ManyToManyFields are not permitted in 'unique_constraint'.",
obj=Model,
id='models.E013',
),
])

def test_unique_constraint_pointing_to_non_local_field(self):
class Foo(models.Model):
field1 = models.IntegerField()

class Bar(Foo):
field2 = models.IntegerField()

class Meta:
constraints = [models.UniqueConstraint(fields=['field2', 'field1'], name='name1')]

self.assertEqual(Bar.check(databases=self.databases), [
Error(
"'unique_constraint' refers to field 'field1' which is not local to "
"model 'Bar'.",
hint='This issue may be caused by multi-table inheritance.',
obj=Bar,
id='models.E016',
),
])

def test_unique_constraint_pointing_to_fk(self):
class Foo(models.Model):
pass

class Bar(models.Model):
foo_1 = models.ForeignKey(Foo, on_delete=models.CASCADE, related_name='bar_1')
foo_2 = models.ForeignKey(Foo, on_delete=models.CASCADE, related_name='bar_2')

class Meta:
constraints = [models.UniqueConstraint(fields=['foo_1_id', 'foo_2'], name='name1')]

self.assertEqual(Bar.check(databases=self.databases), [])

def test_unique_constraint_with_condition(self):
class Model(models.Model):
age = models.IntegerField()
Expand Down

0 comments on commit 8566d6b

Please sign in to comment.