Made assertions in invalid_models_tests consistent.
This commit is contained in:
parent
169c3b3e07
commit
f816ceedf1
|
@ -25,6 +25,4 @@ class BackendSpecificChecksTests(SimpleTestCase):
|
|||
|
||||
field = Model._meta.get_field('field')
|
||||
with mock.patch.object(connections['default'].validation, 'check_field', return_value=[error]):
|
||||
errors = field.check()
|
||||
|
||||
self.assertEqual(errors, [error])
|
||||
self.assertEqual(field.check(), [error])
|
||||
|
|
|
@ -17,5 +17,4 @@ class CustomFieldTest(SimpleTestCase):
|
|||
other_field = models.IntegerField()
|
||||
|
||||
field = Model._meta.get_field('field')
|
||||
errors = field.check()
|
||||
self.assertEqual(errors, [])
|
||||
self.assertEqual(field.check(), [])
|
||||
|
|
|
@ -38,45 +38,39 @@ class IndexTogetherTests(SimpleTestCase):
|
|||
class Meta:
|
||||
index_together = 42
|
||||
|
||||
errors = Model.check()
|
||||
expected = [
|
||||
self.assertEqual(Model.check(), [
|
||||
Error(
|
||||
"'index_together' must be a list or tuple.",
|
||||
obj=Model,
|
||||
id='models.E008',
|
||||
),
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
def test_non_list(self):
|
||||
class Model(models.Model):
|
||||
class Meta:
|
||||
index_together = 'not-a-list'
|
||||
|
||||
errors = Model.check()
|
||||
expected = [
|
||||
self.assertEqual(Model.check(), [
|
||||
Error(
|
||||
"'index_together' must be a list or tuple.",
|
||||
obj=Model,
|
||||
id='models.E008',
|
||||
),
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
def test_list_containing_non_iterable(self):
|
||||
class Model(models.Model):
|
||||
class Meta:
|
||||
index_together = [('a', 'b'), 42]
|
||||
|
||||
errors = Model.check()
|
||||
expected = [
|
||||
self.assertEqual(Model.check(), [
|
||||
Error(
|
||||
"All 'index_together' elements must be lists or tuples.",
|
||||
obj=Model,
|
||||
id='models.E009',
|
||||
),
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
def test_pointing_to_missing_field(self):
|
||||
class Model(models.Model):
|
||||
|
@ -85,15 +79,13 @@ class IndexTogetherTests(SimpleTestCase):
|
|||
["missing_field"],
|
||||
]
|
||||
|
||||
errors = Model.check()
|
||||
expected = [
|
||||
self.assertEqual(Model.check(), [
|
||||
Error(
|
||||
"'index_together' refers to the nonexistent field 'missing_field'.",
|
||||
obj=Model,
|
||||
id='models.E012',
|
||||
),
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
def test_pointing_to_non_local_field(self):
|
||||
class Foo(models.Model):
|
||||
|
@ -107,8 +99,7 @@ class IndexTogetherTests(SimpleTestCase):
|
|||
["field2", "field1"],
|
||||
]
|
||||
|
||||
errors = Bar.check()
|
||||
expected = [
|
||||
self.assertEqual(Bar.check(), [
|
||||
Error(
|
||||
"'index_together' refers to field 'field1' which is not "
|
||||
"local to model 'Bar'.",
|
||||
|
@ -116,8 +107,7 @@ class IndexTogetherTests(SimpleTestCase):
|
|||
obj=Bar,
|
||||
id='models.E016',
|
||||
),
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
def test_pointing_to_m2m_field(self):
|
||||
class Model(models.Model):
|
||||
|
@ -128,16 +118,14 @@ class IndexTogetherTests(SimpleTestCase):
|
|||
["m2m"],
|
||||
]
|
||||
|
||||
errors = Model.check()
|
||||
expected = [
|
||||
self.assertEqual(Model.check(), [
|
||||
Error(
|
||||
"'index_together' refers to a ManyToManyField 'm2m', but "
|
||||
"ManyToManyFields are not permitted in 'index_together'.",
|
||||
obj=Model,
|
||||
id='models.E013',
|
||||
),
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
|
||||
# unique_together tests are very similar to index_together tests.
|
||||
|
@ -149,15 +137,13 @@ class UniqueTogetherTests(SimpleTestCase):
|
|||
class Meta:
|
||||
unique_together = 42
|
||||
|
||||
errors = Model.check()
|
||||
expected = [
|
||||
self.assertEqual(Model.check(), [
|
||||
Error(
|
||||
"'unique_together' must be a list or tuple.",
|
||||
obj=Model,
|
||||
id='models.E010',
|
||||
),
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
def test_list_containing_non_iterable(self):
|
||||
class Model(models.Model):
|
||||
|
@ -167,30 +153,26 @@ class UniqueTogetherTests(SimpleTestCase):
|
|||
class Meta:
|
||||
unique_together = [('a', 'b'), 42]
|
||||
|
||||
errors = Model.check()
|
||||
expected = [
|
||||
self.assertEqual(Model.check(), [
|
||||
Error(
|
||||
"All 'unique_together' elements must be lists or tuples.",
|
||||
obj=Model,
|
||||
id='models.E011',
|
||||
),
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
def test_non_list(self):
|
||||
class Model(models.Model):
|
||||
class Meta:
|
||||
unique_together = 'not-a-list'
|
||||
|
||||
errors = Model.check()
|
||||
expected = [
|
||||
self.assertEqual(Model.check(), [
|
||||
Error(
|
||||
"'unique_together' must be a list or tuple.",
|
||||
obj=Model,
|
||||
id='models.E010',
|
||||
),
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
def test_valid_model(self):
|
||||
class Model(models.Model):
|
||||
|
@ -201,8 +183,7 @@ class UniqueTogetherTests(SimpleTestCase):
|
|||
# unique_together can be a simple tuple
|
||||
unique_together = ('one', 'two')
|
||||
|
||||
errors = Model.check()
|
||||
self.assertEqual(errors, [])
|
||||
self.assertEqual(Model.check(), [])
|
||||
|
||||
def test_pointing_to_missing_field(self):
|
||||
class Model(models.Model):
|
||||
|
@ -211,15 +192,13 @@ class UniqueTogetherTests(SimpleTestCase):
|
|||
["missing_field"],
|
||||
]
|
||||
|
||||
errors = Model.check()
|
||||
expected = [
|
||||
self.assertEqual(Model.check(), [
|
||||
Error(
|
||||
"'unique_together' refers to the nonexistent field 'missing_field'.",
|
||||
obj=Model,
|
||||
id='models.E012',
|
||||
),
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
def test_pointing_to_m2m(self):
|
||||
class Model(models.Model):
|
||||
|
@ -230,16 +209,14 @@ class UniqueTogetherTests(SimpleTestCase):
|
|||
["m2m"],
|
||||
]
|
||||
|
||||
errors = Model.check()
|
||||
expected = [
|
||||
self.assertEqual(Model.check(), [
|
||||
Error(
|
||||
"'unique_together' refers to a ManyToManyField 'm2m', but "
|
||||
"ManyToManyFields are not permitted in 'unique_together'.",
|
||||
obj=Model,
|
||||
id='models.E013',
|
||||
),
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
|
||||
@isolate_apps('invalid_models_tests')
|
||||
|
@ -250,8 +227,7 @@ class FieldNamesTests(SimpleTestCase):
|
|||
field_ = models.CharField(max_length=10)
|
||||
m2m_ = models.ManyToManyField('self')
|
||||
|
||||
errors = Model.check()
|
||||
expected = [
|
||||
self.assertEqual(Model.check(), [
|
||||
Error(
|
||||
'Field names must not end with an underscore.',
|
||||
obj=Model._meta.get_field('field_'),
|
||||
|
@ -262,8 +238,7 @@ class FieldNamesTests(SimpleTestCase):
|
|||
obj=Model._meta.get_field('m2m_'),
|
||||
id='fields.E001',
|
||||
),
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
max_column_name_length, column_limit_db_alias = get_max_column_name_length()
|
||||
|
||||
|
@ -373,12 +348,7 @@ class FieldNamesTests(SimpleTestCase):
|
|||
long_field_name2 = 'b' * (self.max_column_name_length + 1)
|
||||
models.CharField(max_length=11).contribute_to_class(ModelWithLongField, long_field_name)
|
||||
models.CharField(max_length=11, db_column='vlmn').contribute_to_class(ModelWithLongField, long_field_name2)
|
||||
|
||||
errors = ModelWithLongField.check()
|
||||
|
||||
# Error because of the field with long name added to the model
|
||||
# without specifying db_column
|
||||
expected = [
|
||||
self.assertEqual(ModelWithLongField.check(), [
|
||||
Error(
|
||||
'Autogenerated column name too long for field "%s". '
|
||||
'Maximum length is "%s" for database "%s".'
|
||||
|
@ -387,37 +357,31 @@ class FieldNamesTests(SimpleTestCase):
|
|||
obj=ModelWithLongField,
|
||||
id='models.E018',
|
||||
)
|
||||
]
|
||||
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
def test_including_separator(self):
|
||||
class Model(models.Model):
|
||||
some__field = models.IntegerField()
|
||||
|
||||
errors = Model.check()
|
||||
expected = [
|
||||
self.assertEqual(Model.check(), [
|
||||
Error(
|
||||
'Field names must not contain "__".',
|
||||
obj=Model._meta.get_field('some__field'),
|
||||
id='fields.E002',
|
||||
)
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
def test_pk(self):
|
||||
class Model(models.Model):
|
||||
pk = models.IntegerField()
|
||||
|
||||
errors = Model.check()
|
||||
expected = [
|
||||
self.assertEqual(Model.check(), [
|
||||
Error(
|
||||
"'pk' is a reserved word that cannot be used as a field name.",
|
||||
obj=Model._meta.get_field('pk'),
|
||||
id='fields.E003',
|
||||
)
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
|
||||
@isolate_apps('invalid_models_tests')
|
||||
|
@ -430,16 +394,14 @@ class ShadowingFieldsTests(SimpleTestCase):
|
|||
class Child(Parent):
|
||||
child = models.CharField(max_length=100)
|
||||
|
||||
errors = Child.check()
|
||||
expected = [
|
||||
self.assertEqual(Child.check(), [
|
||||
Error(
|
||||
"The field 'child' clashes with the field "
|
||||
"'child' from model 'invalid_models_tests.parent'.",
|
||||
obj=Child._meta.get_field('child'),
|
||||
id='models.E006',
|
||||
)
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
def test_multiinheritance_clash(self):
|
||||
class Mother(models.Model):
|
||||
|
@ -453,8 +415,7 @@ class ShadowingFieldsTests(SimpleTestCase):
|
|||
# both parents define these fields.
|
||||
pass
|
||||
|
||||
errors = Child.check()
|
||||
expected = [
|
||||
self.assertEqual(Child.check(), [
|
||||
Error(
|
||||
"The field 'id' from parent model "
|
||||
"'invalid_models_tests.mother' clashes with the field 'id' "
|
||||
|
@ -469,8 +430,7 @@ class ShadowingFieldsTests(SimpleTestCase):
|
|||
obj=Child,
|
||||
id='models.E005',
|
||||
)
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
def test_inheritance_clash(self):
|
||||
class Parent(models.Model):
|
||||
|
@ -484,16 +444,14 @@ class ShadowingFieldsTests(SimpleTestCase):
|
|||
# This field clashes with parent "f_id" field.
|
||||
f = models.ForeignKey(Target, models.CASCADE)
|
||||
|
||||
errors = Child.check()
|
||||
expected = [
|
||||
self.assertEqual(Child.check(), [
|
||||
Error(
|
||||
"The field 'f' clashes with the field 'f_id' "
|
||||
"from model 'invalid_models_tests.parent'.",
|
||||
obj=Child._meta.get_field('f'),
|
||||
id='models.E006',
|
||||
)
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
def test_multigeneration_inheritance(self):
|
||||
class GrandParent(models.Model):
|
||||
|
@ -508,16 +466,14 @@ class ShadowingFieldsTests(SimpleTestCase):
|
|||
class GrandChild(Child):
|
||||
clash = models.IntegerField()
|
||||
|
||||
errors = GrandChild.check()
|
||||
expected = [
|
||||
self.assertEqual(GrandChild.check(), [
|
||||
Error(
|
||||
"The field 'clash' clashes with the field 'clash' "
|
||||
"from model 'invalid_models_tests.grandparent'.",
|
||||
obj=GrandChild._meta.get_field('clash'),
|
||||
id='models.E006',
|
||||
)
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
def test_id_clash(self):
|
||||
class Target(models.Model):
|
||||
|
@ -527,16 +483,14 @@ class ShadowingFieldsTests(SimpleTestCase):
|
|||
fk = models.ForeignKey(Target, models.CASCADE)
|
||||
fk_id = models.IntegerField()
|
||||
|
||||
errors = Model.check()
|
||||
expected = [
|
||||
self.assertEqual(Model.check(), [
|
||||
Error(
|
||||
"The field 'fk_id' clashes with the field 'fk' from model "
|
||||
"'invalid_models_tests.model'.",
|
||||
obj=Model._meta.get_field('fk_id'),
|
||||
id='models.E006',
|
||||
)
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
|
||||
@isolate_apps('invalid_models_tests')
|
||||
|
@ -548,32 +502,28 @@ class OtherModelTests(SimpleTestCase):
|
|||
class Model(models.Model):
|
||||
id = invalid_id
|
||||
|
||||
errors = Model.check()
|
||||
expected = [
|
||||
self.assertEqual(Model.check(), [
|
||||
Error(
|
||||
"'id' can only be used as a field name if the field also sets "
|
||||
"'primary_key=True'.",
|
||||
obj=Model,
|
||||
id='models.E004',
|
||||
),
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
def test_ordering_non_iterable(self):
|
||||
class Model(models.Model):
|
||||
class Meta:
|
||||
ordering = "missing_field"
|
||||
|
||||
errors = Model.check()
|
||||
expected = [
|
||||
self.assertEqual(Model.check(), [
|
||||
Error(
|
||||
"'ordering' must be a tuple or list "
|
||||
"(even if you want to order by only one field).",
|
||||
obj=Model,
|
||||
id='models.E014',
|
||||
),
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
def test_just_ordering_no_errors(self):
|
||||
class Model(models.Model):
|
||||
|
@ -608,15 +558,13 @@ class OtherModelTests(SimpleTestCase):
|
|||
order_with_respect_to = 'question'
|
||||
ordering = ['order']
|
||||
|
||||
errors = Answer.check()
|
||||
expected = [
|
||||
self.assertEqual(Answer.check(), [
|
||||
Error(
|
||||
"'ordering' and 'order_with_respect_to' cannot be used together.",
|
||||
obj=Answer,
|
||||
id='models.E021',
|
||||
),
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
def test_non_valid(self):
|
||||
class RelationModel(models.Model):
|
||||
|
@ -628,30 +576,26 @@ class OtherModelTests(SimpleTestCase):
|
|||
class Meta:
|
||||
ordering = ['relation']
|
||||
|
||||
errors = Model.check()
|
||||
expected = [
|
||||
self.assertEqual(Model.check(), [
|
||||
Error(
|
||||
"'ordering' refers to the nonexistent field 'relation'.",
|
||||
obj=Model,
|
||||
id='models.E015',
|
||||
),
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
def test_ordering_pointing_to_missing_field(self):
|
||||
class Model(models.Model):
|
||||
class Meta:
|
||||
ordering = ("missing_field",)
|
||||
|
||||
errors = Model.check()
|
||||
expected = [
|
||||
self.assertEqual(Model.check(), [
|
||||
Error(
|
||||
"'ordering' refers to the nonexistent field 'missing_field'.",
|
||||
obj=Model,
|
||||
id='models.E015',
|
||||
)
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
def test_ordering_pointing_to_missing_foreignkey_field(self):
|
||||
# refs #22711
|
||||
|
@ -662,15 +606,13 @@ class OtherModelTests(SimpleTestCase):
|
|||
class Meta:
|
||||
ordering = ("missing_fk_field_id",)
|
||||
|
||||
errors = Model.check()
|
||||
expected = [
|
||||
self.assertEqual(Model.check(), [
|
||||
Error(
|
||||
"'ordering' refers to the nonexistent field 'missing_fk_field_id'.",
|
||||
obj=Model,
|
||||
id='models.E015',
|
||||
)
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
def test_ordering_pointing_to_existing_foreignkey_field(self):
|
||||
# refs #22711
|
||||
|
@ -731,14 +673,12 @@ class OtherModelTests(SimpleTestCase):
|
|||
class Meta:
|
||||
swappable = 'TEST_SWAPPED_MODEL_BAD_VALUE'
|
||||
|
||||
errors = Model.check()
|
||||
expected = [
|
||||
self.assertEqual(Model.check(), [
|
||||
Error(
|
||||
"'TEST_SWAPPED_MODEL_BAD_VALUE' is not of the form 'app_label.app_name'.",
|
||||
id='models.E001',
|
||||
),
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
@override_settings(TEST_SWAPPED_MODEL_BAD_MODEL='not_an_app.Target')
|
||||
def test_swappable_missing_app(self):
|
||||
|
@ -746,15 +686,13 @@ class OtherModelTests(SimpleTestCase):
|
|||
class Meta:
|
||||
swappable = 'TEST_SWAPPED_MODEL_BAD_MODEL'
|
||||
|
||||
errors = Model.check()
|
||||
expected = [
|
||||
self.assertEqual(Model.check(), [
|
||||
Error(
|
||||
"'TEST_SWAPPED_MODEL_BAD_MODEL' references 'not_an_app.Target', "
|
||||
'which has not been installed, or is abstract.',
|
||||
id='models.E002',
|
||||
),
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
def test_two_m2m_through_same_relationship(self):
|
||||
class Person(models.Model):
|
||||
|
@ -768,16 +706,14 @@ class OtherModelTests(SimpleTestCase):
|
|||
person = models.ForeignKey(Person, models.CASCADE)
|
||||
group = models.ForeignKey(Group, models.CASCADE)
|
||||
|
||||
errors = Group.check()
|
||||
expected = [
|
||||
self.assertEqual(Group.check(), [
|
||||
Error(
|
||||
"The model has two many-to-many relations through "
|
||||
"the intermediate model 'invalid_models_tests.Membership'.",
|
||||
obj=Group,
|
||||
id='models.E003',
|
||||
)
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
def test_missing_parent_link(self):
|
||||
msg = 'Add parent_link=True to invalid_models_tests.ParkingLot.parent.'
|
||||
|
@ -927,7 +863,7 @@ class OtherModelTests(SimpleTestCase):
|
|||
post_init.connect(DummyClass(), sender='missing-app.Model', apps=apps)
|
||||
post_init.connect(DummyClass().dummy_method, sender='missing-app.Model', apps=apps)
|
||||
|
||||
expected = [
|
||||
self.assertEqual(_check_lazy_references(apps), [
|
||||
Error(
|
||||
"%r contains a lazy reference to auth.imaginarymodel, "
|
||||
"but app 'auth' doesn't provide model 'imaginarymodel'." % dummy_function,
|
||||
|
@ -972,5 +908,4 @@ class OtherModelTests(SimpleTestCase):
|
|||
obj='invalid_models_tests.test_models',
|
||||
id='signals.E001',
|
||||
),
|
||||
]
|
||||
self.assertEqual(_check_lazy_references(apps), expected)
|
||||
])
|
||||
|
|
|
@ -15,9 +15,7 @@ class AutoFieldTests(SimpleTestCase):
|
|||
id = models.AutoField(primary_key=True)
|
||||
|
||||
field = Model._meta.get_field('id')
|
||||
errors = field.check()
|
||||
expected = []
|
||||
self.assertEqual(errors, expected)
|
||||
self.assertEqual(field.check(), [])
|
||||
|
||||
def test_primary_key(self):
|
||||
# primary_key must be True. Refs #12467.
|
||||
|
@ -30,15 +28,13 @@ class AutoFieldTests(SimpleTestCase):
|
|||
another = models.IntegerField(primary_key=True)
|
||||
|
||||
field = Model._meta.get_field('field')
|
||||
errors = field.check()
|
||||
expected = [
|
||||
self.assertEqual(field.check(), [
|
||||
Error(
|
||||
'AutoFields must set primary_key=True.',
|
||||
obj=field,
|
||||
id='fields.E100',
|
||||
),
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
|
||||
@isolate_apps('invalid_models_tests')
|
||||
|
@ -49,16 +45,14 @@ class BooleanFieldTests(SimpleTestCase):
|
|||
field = models.BooleanField(null=True)
|
||||
|
||||
field = Model._meta.get_field('field')
|
||||
errors = field.check()
|
||||
expected = [
|
||||
self.assertEqual(field.check(), [
|
||||
Error(
|
||||
'BooleanFields do not accept null values.',
|
||||
hint='Use a NullBooleanField instead.',
|
||||
obj=field,
|
||||
id='fields.E110',
|
||||
),
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
|
||||
@isolate_apps('invalid_models_tests')
|
||||
|
@ -75,99 +69,85 @@ class CharFieldTests(TestCase):
|
|||
db_index=True)
|
||||
|
||||
field = Model._meta.get_field('field')
|
||||
errors = field.check()
|
||||
expected = []
|
||||
self.assertEqual(errors, expected)
|
||||
self.assertEqual(field.check(), [])
|
||||
|
||||
def test_missing_max_length(self):
|
||||
class Model(models.Model):
|
||||
field = models.CharField()
|
||||
|
||||
field = Model._meta.get_field('field')
|
||||
errors = field.check()
|
||||
expected = [
|
||||
self.assertEqual(field.check(), [
|
||||
Error(
|
||||
"CharFields must define a 'max_length' attribute.",
|
||||
obj=field,
|
||||
id='fields.E120',
|
||||
),
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
def test_negative_max_length(self):
|
||||
class Model(models.Model):
|
||||
field = models.CharField(max_length=-1)
|
||||
|
||||
field = Model._meta.get_field('field')
|
||||
errors = field.check()
|
||||
expected = [
|
||||
self.assertEqual(field.check(), [
|
||||
Error(
|
||||
"'max_length' must be a positive integer.",
|
||||
obj=field,
|
||||
id='fields.E121',
|
||||
),
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
def test_bad_max_length_value(self):
|
||||
class Model(models.Model):
|
||||
field = models.CharField(max_length="bad")
|
||||
|
||||
field = Model._meta.get_field('field')
|
||||
errors = field.check()
|
||||
expected = [
|
||||
self.assertEqual(field.check(), [
|
||||
Error(
|
||||
"'max_length' must be a positive integer.",
|
||||
obj=field,
|
||||
id='fields.E121',
|
||||
),
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
def test_str_max_length_value(self):
|
||||
class Model(models.Model):
|
||||
field = models.CharField(max_length='20')
|
||||
|
||||
field = Model._meta.get_field('field')
|
||||
errors = field.check()
|
||||
expected = [
|
||||
self.assertEqual(field.check(), [
|
||||
Error(
|
||||
"'max_length' must be a positive integer.",
|
||||
obj=field,
|
||||
id='fields.E121',
|
||||
),
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
def test_str_max_length_type(self):
|
||||
class Model(models.Model):
|
||||
field = models.CharField(max_length=True)
|
||||
|
||||
field = Model._meta.get_field('field')
|
||||
errors = field.check()
|
||||
expected = [
|
||||
self.assertEqual(field.check(), [
|
||||
Error(
|
||||
"'max_length' must be a positive integer.",
|
||||
obj=field,
|
||||
id='fields.E121'
|
||||
),
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
def test_non_iterable_choices(self):
|
||||
class Model(models.Model):
|
||||
field = models.CharField(max_length=10, choices='bad')
|
||||
|
||||
field = Model._meta.get_field('field')
|
||||
errors = field.check()
|
||||
expected = [
|
||||
self.assertEqual(field.check(), [
|
||||
Error(
|
||||
"'choices' must be an iterable (e.g., a list or tuple).",
|
||||
obj=field,
|
||||
id='fields.E004',
|
||||
),
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
def test_iterable_of_iterable_choices(self):
|
||||
class ThingItem:
|
||||
|
@ -195,30 +175,26 @@ class CharFieldTests(TestCase):
|
|||
field = models.CharField(max_length=10, choices=[(1, 2, 3), (1, 2, 3)])
|
||||
|
||||
field = Model._meta.get_field('field')
|
||||
errors = field.check()
|
||||
expected = [
|
||||
self.assertEqual(field.check(), [
|
||||
Error(
|
||||
"'choices' must be an iterable containing (actual value, human readable name) tuples.",
|
||||
obj=field,
|
||||
id='fields.E005',
|
||||
),
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
def test_bad_db_index_value(self):
|
||||
class Model(models.Model):
|
||||
field = models.CharField(max_length=10, db_index='bad')
|
||||
|
||||
field = Model._meta.get_field('field')
|
||||
errors = field.check()
|
||||
expected = [
|
||||
self.assertEqual(field.check(), [
|
||||
Error(
|
||||
"'db_index' must be None, True or False.",
|
||||
obj=field,
|
||||
id='fields.E006',
|
||||
),
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
def test_bad_validators(self):
|
||||
class Model(models.Model):
|
||||
|
@ -247,19 +223,18 @@ class CharFieldTests(TestCase):
|
|||
|
||||
field = Model._meta.get_field('field')
|
||||
validator = DatabaseValidation(connection=connection)
|
||||
errors = validator.check_field(field)
|
||||
expected = [
|
||||
self.assertEqual(validator.check_field(field), [
|
||||
Error(
|
||||
'MySQL does not allow unique CharFields to have a max_length > 255.',
|
||||
obj=field,
|
||||
id='mysql.E001',
|
||||
)
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
|
||||
@isolate_apps('invalid_models_tests')
|
||||
class DateFieldTests(TestCase):
|
||||
maxDiff = None
|
||||
|
||||
def test_auto_now_and_auto_now_add_raise_error(self):
|
||||
class Model(models.Model):
|
||||
|
@ -294,7 +269,7 @@ class DateFieldTests(TestCase):
|
|||
errors = field_dt.check()
|
||||
errors.extend(field_d.check())
|
||||
errors.extend(field_now.check()) # doesn't raise a warning
|
||||
expected = [
|
||||
self.assertEqual(errors, [
|
||||
DjangoWarning(
|
||||
'Fixed default value provided.',
|
||||
hint='It seems you set a fixed date / time / datetime '
|
||||
|
@ -313,11 +288,7 @@ class DateFieldTests(TestCase):
|
|||
obj=field_d,
|
||||
id='fields.W161',
|
||||
)
|
||||
]
|
||||
maxDiff = self.maxDiff
|
||||
self.maxDiff = None
|
||||
self.assertEqual(errors, expected)
|
||||
self.maxDiff = maxDiff
|
||||
])
|
||||
|
||||
@override_settings(USE_TZ=True)
|
||||
def test_fix_default_value_tz(self):
|
||||
|
@ -326,6 +297,7 @@ class DateFieldTests(TestCase):
|
|||
|
||||
@isolate_apps('invalid_models_tests')
|
||||
class DateTimeFieldTests(TestCase):
|
||||
maxDiff = None
|
||||
|
||||
def test_fix_default_value(self):
|
||||
class Model(models.Model):
|
||||
|
@ -339,7 +311,7 @@ class DateTimeFieldTests(TestCase):
|
|||
errors = field_dt.check()
|
||||
errors.extend(field_d.check())
|
||||
errors.extend(field_now.check()) # doesn't raise a warning
|
||||
expected = [
|
||||
self.assertEqual(errors, [
|
||||
DjangoWarning(
|
||||
'Fixed default value provided.',
|
||||
hint='It seems you set a fixed date / time / datetime '
|
||||
|
@ -358,11 +330,7 @@ class DateTimeFieldTests(TestCase):
|
|||
obj=field_d,
|
||||
id='fields.W161',
|
||||
)
|
||||
]
|
||||
maxDiff = self.maxDiff
|
||||
self.maxDiff = None
|
||||
self.assertEqual(errors, expected)
|
||||
self.maxDiff = maxDiff
|
||||
])
|
||||
|
||||
@override_settings(USE_TZ=True)
|
||||
def test_fix_default_value_tz(self):
|
||||
|
@ -377,8 +345,7 @@ class DecimalFieldTests(SimpleTestCase):
|
|||
field = models.DecimalField()
|
||||
|
||||
field = Model._meta.get_field('field')
|
||||
errors = field.check()
|
||||
expected = [
|
||||
self.assertEqual(field.check(), [
|
||||
Error(
|
||||
"DecimalFields must define a 'decimal_places' attribute.",
|
||||
obj=field,
|
||||
|
@ -389,16 +356,14 @@ class DecimalFieldTests(SimpleTestCase):
|
|||
obj=field,
|
||||
id='fields.E132',
|
||||
),
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
def test_negative_max_digits_and_decimal_places(self):
|
||||
class Model(models.Model):
|
||||
field = models.DecimalField(max_digits=-1, decimal_places=-1)
|
||||
|
||||
field = Model._meta.get_field('field')
|
||||
errors = field.check()
|
||||
expected = [
|
||||
self.assertEqual(field.check(), [
|
||||
Error(
|
||||
"'decimal_places' must be a non-negative integer.",
|
||||
obj=field,
|
||||
|
@ -409,16 +374,14 @@ class DecimalFieldTests(SimpleTestCase):
|
|||
obj=field,
|
||||
id='fields.E133',
|
||||
),
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
def test_bad_values_of_max_digits_and_decimal_places(self):
|
||||
class Model(models.Model):
|
||||
field = models.DecimalField(max_digits="bad", decimal_places="bad")
|
||||
|
||||
field = Model._meta.get_field('field')
|
||||
errors = field.check()
|
||||
expected = [
|
||||
self.assertEqual(field.check(), [
|
||||
Error(
|
||||
"'decimal_places' must be a non-negative integer.",
|
||||
obj=field,
|
||||
|
@ -429,32 +392,27 @@ class DecimalFieldTests(SimpleTestCase):
|
|||
obj=field,
|
||||
id='fields.E133',
|
||||
),
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
def test_decimal_places_greater_than_max_digits(self):
|
||||
class Model(models.Model):
|
||||
field = models.DecimalField(max_digits=9, decimal_places=10)
|
||||
|
||||
field = Model._meta.get_field('field')
|
||||
errors = field.check()
|
||||
expected = [
|
||||
self.assertEqual(field.check(), [
|
||||
Error(
|
||||
"'max_digits' must be greater or equal to 'decimal_places'.",
|
||||
obj=field,
|
||||
id='fields.E134',
|
||||
),
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
def test_valid_field(self):
|
||||
class Model(models.Model):
|
||||
field = models.DecimalField(max_digits=10, decimal_places=10)
|
||||
|
||||
field = Model._meta.get_field('field')
|
||||
errors = field.check()
|
||||
expected = []
|
||||
self.assertEqual(errors, expected)
|
||||
self.assertEqual(field.check(), [])
|
||||
|
||||
|
||||
@isolate_apps('invalid_models_tests')
|
||||
|
@ -471,24 +429,20 @@ class FileFieldTests(SimpleTestCase):
|
|||
field = models.FileField(upload_to='somewhere')
|
||||
|
||||
field = Model._meta.get_field('field')
|
||||
errors = field.check()
|
||||
expected = []
|
||||
self.assertEqual(errors, expected)
|
||||
self.assertEqual(field.check(), [])
|
||||
|
||||
def test_primary_key(self):
|
||||
class Model(models.Model):
|
||||
field = models.FileField(primary_key=False, upload_to='somewhere')
|
||||
|
||||
field = Model._meta.get_field('field')
|
||||
errors = field.check()
|
||||
expected = [
|
||||
self.assertEqual(field.check(), [
|
||||
Error(
|
||||
"'primary_key' is not a valid argument for a FileField.",
|
||||
obj=field,
|
||||
id='fields.E201',
|
||||
)
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
def test_upload_to_starts_with_slash(self):
|
||||
class Model(models.Model):
|
||||
|
@ -524,15 +478,13 @@ class FilePathFieldTests(SimpleTestCase):
|
|||
field = models.FilePathField(allow_files=False, allow_folders=False)
|
||||
|
||||
field = Model._meta.get_field('field')
|
||||
errors = field.check()
|
||||
expected = [
|
||||
self.assertEqual(field.check(), [
|
||||
Error(
|
||||
"FilePathFields must have either 'allow_files' or 'allow_folders' set to True.",
|
||||
obj=field,
|
||||
id='fields.E140',
|
||||
),
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
|
||||
@isolate_apps('invalid_models_tests')
|
||||
|
@ -543,16 +495,14 @@ class GenericIPAddressFieldTests(SimpleTestCase):
|
|||
field = models.GenericIPAddressField(null=False, blank=True)
|
||||
|
||||
field = Model._meta.get_field('field')
|
||||
errors = field.check()
|
||||
expected = [
|
||||
self.assertEqual(field.check(), [
|
||||
Error(
|
||||
('GenericIPAddressFields cannot have blank=True if null=False, '
|
||||
'as blank values are stored as nulls.'),
|
||||
obj=field,
|
||||
id='fields.E150',
|
||||
),
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
|
||||
@isolate_apps('invalid_models_tests')
|
||||
|
@ -590,21 +540,20 @@ class IntegerFieldTests(SimpleTestCase):
|
|||
class Model(models.Model):
|
||||
value = models.IntegerField(max_length=2)
|
||||
|
||||
value = Model._meta.get_field('value')
|
||||
errors = Model.check()
|
||||
expected = [
|
||||
field = Model._meta.get_field('value')
|
||||
self.assertEqual(field.check(), [
|
||||
DjangoWarning(
|
||||
"'max_length' is ignored when used with IntegerField",
|
||||
hint="Remove 'max_length' from field",
|
||||
obj=value,
|
||||
obj=field,
|
||||
id='fields.W122',
|
||||
)
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
|
||||
@isolate_apps('invalid_models_tests')
|
||||
class TimeFieldTests(TestCase):
|
||||
maxDiff = None
|
||||
|
||||
def test_fix_default_value(self):
|
||||
class Model(models.Model):
|
||||
|
@ -618,7 +567,7 @@ class TimeFieldTests(TestCase):
|
|||
errors = field_dt.check()
|
||||
errors.extend(field_t.check())
|
||||
errors.extend(field_now.check()) # doesn't raise a warning
|
||||
expected = [
|
||||
self.assertEqual(errors, [
|
||||
DjangoWarning(
|
||||
'Fixed default value provided.',
|
||||
hint='It seems you set a fixed date / time / datetime '
|
||||
|
@ -637,11 +586,7 @@ class TimeFieldTests(TestCase):
|
|||
obj=field_t,
|
||||
id='fields.W161',
|
||||
)
|
||||
]
|
||||
maxDiff = self.maxDiff
|
||||
self.maxDiff = None
|
||||
self.assertEqual(errors, expected)
|
||||
self.maxDiff = maxDiff
|
||||
])
|
||||
|
||||
@override_settings(USE_TZ=True)
|
||||
def test_fix_default_value_tz(self):
|
||||
|
|
|
@ -17,8 +17,7 @@ class RelativeFieldTests(SimpleTestCase):
|
|||
field = models.ForeignKey(Target, models.CASCADE, related_name='+')
|
||||
|
||||
field = Model._meta.get_field('field')
|
||||
errors = field.check()
|
||||
self.assertEqual(errors, [])
|
||||
self.assertEqual(field.check(), [])
|
||||
|
||||
def test_foreign_key_to_missing_model(self):
|
||||
# Model names are resolved when a model is being created, so we cannot
|
||||
|
@ -28,16 +27,14 @@ class RelativeFieldTests(SimpleTestCase):
|
|||
foreign_key = models.ForeignKey('Rel1', models.CASCADE)
|
||||
|
||||
field = Model._meta.get_field('foreign_key')
|
||||
errors = field.check()
|
||||
expected = [
|
||||
self.assertEqual(field.check(), [
|
||||
Error(
|
||||
"Field defines a relation with model 'Rel1', "
|
||||
"which is either not installed, or is abstract.",
|
||||
obj=field,
|
||||
id='fields.E300',
|
||||
),
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
@isolate_apps('invalid_models_tests')
|
||||
def test_foreign_key_to_isolate_apps_model(self):
|
||||
|
@ -59,16 +56,14 @@ class RelativeFieldTests(SimpleTestCase):
|
|||
m2m = models.ManyToManyField("Rel2")
|
||||
|
||||
field = Model._meta.get_field('m2m')
|
||||
errors = field.check(from_model=Model)
|
||||
expected = [
|
||||
self.assertEqual(field.check(from_model=Model), [
|
||||
Error(
|
||||
"Field defines a relation with model 'Rel2', "
|
||||
"which is either not installed, or is abstract.",
|
||||
obj=field,
|
||||
id='fields.E300',
|
||||
),
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
@isolate_apps('invalid_models_tests')
|
||||
def test_many_to_many_to_isolate_apps_model(self):
|
||||
|
@ -112,10 +107,8 @@ class RelativeFieldTests(SimpleTestCase):
|
|||
model = models.ForeignKey('Model', models.CASCADE)
|
||||
modelm2m = models.ForeignKey('ModelM2M', models.CASCADE)
|
||||
|
||||
errors = ModelM2M.check()
|
||||
field = ModelM2M._meta.get_field('m2m')
|
||||
|
||||
expected = [
|
||||
self.assertEqual(ModelM2M.check(), [
|
||||
DjangoWarning(
|
||||
'null has no effect on ManyToManyField.',
|
||||
obj=field,
|
||||
|
@ -132,9 +125,7 @@ class RelativeFieldTests(SimpleTestCase):
|
|||
obj=field,
|
||||
id='fields.W343',
|
||||
),
|
||||
]
|
||||
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
def test_ambiguous_relationship_model(self):
|
||||
|
||||
|
@ -151,8 +142,7 @@ class RelativeFieldTests(SimpleTestCase):
|
|||
second_model = models.ForeignKey(Group, models.CASCADE)
|
||||
|
||||
field = Group._meta.get_field('field')
|
||||
errors = field.check(from_model=Group)
|
||||
expected = [
|
||||
self.assertEqual(field.check(from_model=Group), [
|
||||
Error(
|
||||
"The model is used as an intermediate model by "
|
||||
"'invalid_models_tests.Group.field', but it has more than one "
|
||||
|
@ -166,8 +156,7 @@ class RelativeFieldTests(SimpleTestCase):
|
|||
obj=field,
|
||||
id='fields.E335',
|
||||
),
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
def test_relationship_model_with_foreign_key_to_wrong_model(self):
|
||||
class WrongModel(models.Model):
|
||||
|
@ -185,8 +174,7 @@ class RelativeFieldTests(SimpleTestCase):
|
|||
# The last foreign key should point to Group model.
|
||||
|
||||
field = Group._meta.get_field('members')
|
||||
errors = field.check(from_model=Group)
|
||||
expected = [
|
||||
self.assertEqual(field.check(from_model=Group), [
|
||||
Error(
|
||||
"The model is used as an intermediate model by "
|
||||
"'invalid_models_tests.Group.members', but it does not "
|
||||
|
@ -194,8 +182,7 @@ class RelativeFieldTests(SimpleTestCase):
|
|||
obj=InvalidRelationship,
|
||||
id='fields.E336',
|
||||
),
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
def test_relationship_model_missing_foreign_key(self):
|
||||
class Person(models.Model):
|
||||
|
@ -209,8 +196,7 @@ class RelativeFieldTests(SimpleTestCase):
|
|||
# No foreign key to Person
|
||||
|
||||
field = Group._meta.get_field('members')
|
||||
errors = field.check(from_model=Group)
|
||||
expected = [
|
||||
self.assertEqual(field.check(from_model=Group), [
|
||||
Error(
|
||||
"The model is used as an intermediate model by "
|
||||
"'invalid_models_tests.Group.members', but it does not have "
|
||||
|
@ -218,8 +204,7 @@ class RelativeFieldTests(SimpleTestCase):
|
|||
obj=InvalidRelationship,
|
||||
id='fields.E336',
|
||||
),
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
def test_missing_relationship_model(self):
|
||||
class Person(models.Model):
|
||||
|
@ -229,16 +214,14 @@ class RelativeFieldTests(SimpleTestCase):
|
|||
members = models.ManyToManyField('Person', through="MissingM2MModel")
|
||||
|
||||
field = Group._meta.get_field('members')
|
||||
errors = field.check(from_model=Group)
|
||||
expected = [
|
||||
self.assertEqual(field.check(from_model=Group), [
|
||||
Error(
|
||||
"Field specifies a many-to-many relation through model "
|
||||
"'MissingM2MModel', which has not been installed.",
|
||||
obj=field,
|
||||
id='fields.E331',
|
||||
),
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
def test_missing_relationship_model_on_model_check(self):
|
||||
class Person(models.Model):
|
||||
|
@ -285,15 +268,13 @@ class RelativeFieldTests(SimpleTestCase):
|
|||
second = models.ForeignKey(Person, models.CASCADE, related_name="rel_to_set")
|
||||
|
||||
field = Person._meta.get_field('friends')
|
||||
errors = field.check(from_model=Person)
|
||||
expected = [
|
||||
self.assertEqual(field.check(from_model=Person), [
|
||||
Error(
|
||||
'Many-to-many fields with intermediate tables must not be symmetrical.',
|
||||
obj=field,
|
||||
id='fields.E332',
|
||||
),
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
def test_too_many_foreign_keys_in_self_referential_model(self):
|
||||
class Person(models.Model):
|
||||
|
@ -305,8 +286,7 @@ class RelativeFieldTests(SimpleTestCase):
|
|||
third = models.ForeignKey(Person, models.CASCADE, related_name="too_many_by_far")
|
||||
|
||||
field = Person._meta.get_field('friends')
|
||||
errors = field.check(from_model=Person)
|
||||
expected = [
|
||||
self.assertEqual(field.check(from_model=Person), [
|
||||
Error(
|
||||
"The model is used as an intermediate model by "
|
||||
"'invalid_models_tests.Person.friends', but it has more than two "
|
||||
|
@ -317,8 +297,7 @@ class RelativeFieldTests(SimpleTestCase):
|
|||
obj=InvalidRelationship,
|
||||
id='fields.E333',
|
||||
),
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
def test_symmetric_self_reference_with_intermediate_table(self):
|
||||
class Person(models.Model):
|
||||
|
@ -330,15 +309,13 @@ class RelativeFieldTests(SimpleTestCase):
|
|||
second = models.ForeignKey(Person, models.CASCADE, related_name="rel_to_set")
|
||||
|
||||
field = Person._meta.get_field('friends')
|
||||
errors = field.check(from_model=Person)
|
||||
expected = [
|
||||
self.assertEqual(field.check(from_model=Person), [
|
||||
Error(
|
||||
'Many-to-many fields with intermediate tables must not be symmetrical.',
|
||||
obj=field,
|
||||
id='fields.E332',
|
||||
),
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
def test_symmetric_self_reference_with_intermediate_table_and_through_fields(self):
|
||||
"""
|
||||
|
@ -360,15 +337,13 @@ class RelativeFieldTests(SimpleTestCase):
|
|||
referee = models.ForeignKey(Person, models.CASCADE, related_name="referred")
|
||||
|
||||
field = Person._meta.get_field('friends')
|
||||
errors = field.check(from_model=Person)
|
||||
expected = [
|
||||
self.assertEqual(field.check(from_model=Person), [
|
||||
Error(
|
||||
'Many-to-many fields with intermediate tables must not be symmetrical.',
|
||||
obj=field,
|
||||
id='fields.E332',
|
||||
),
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
def test_foreign_key_to_abstract_model(self):
|
||||
class AbstractModel(models.Model):
|
||||
|
@ -390,8 +365,7 @@ class RelativeFieldTests(SimpleTestCase):
|
|||
)
|
||||
for field in fields:
|
||||
expected_error.obj = field
|
||||
errors = field.check()
|
||||
self.assertEqual(errors, [expected_error])
|
||||
self.assertEqual(field.check(), [expected_error])
|
||||
|
||||
def test_m2m_to_abstract_model(self):
|
||||
class AbstractModel(models.Model):
|
||||
|
@ -413,8 +387,7 @@ class RelativeFieldTests(SimpleTestCase):
|
|||
)
|
||||
for field in fields:
|
||||
expected_error.obj = field
|
||||
errors = field.check(from_model=Model)
|
||||
self.assertEqual(errors, [expected_error])
|
||||
self.assertEqual(field.check(from_model=Model), [expected_error])
|
||||
|
||||
def test_unique_m2m(self):
|
||||
class Person(models.Model):
|
||||
|
@ -424,15 +397,13 @@ class RelativeFieldTests(SimpleTestCase):
|
|||
members = models.ManyToManyField('Person', unique=True)
|
||||
|
||||
field = Group._meta.get_field('members')
|
||||
errors = field.check(from_model=Group)
|
||||
expected = [
|
||||
self.assertEqual(field.check(from_model=Group), [
|
||||
Error(
|
||||
'ManyToManyFields cannot be unique.',
|
||||
obj=field,
|
||||
id='fields.E330',
|
||||
),
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
def test_foreign_key_to_non_unique_field(self):
|
||||
class Target(models.Model):
|
||||
|
@ -442,15 +413,13 @@ class RelativeFieldTests(SimpleTestCase):
|
|||
foreign_key = models.ForeignKey('Target', models.CASCADE, to_field='bad')
|
||||
|
||||
field = Model._meta.get_field('foreign_key')
|
||||
errors = field.check()
|
||||
expected = [
|
||||
self.assertEqual(field.check(), [
|
||||
Error(
|
||||
"'Target.bad' must set unique=True because it is referenced by a foreign key.",
|
||||
obj=field,
|
||||
id='fields.E311',
|
||||
),
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
def test_foreign_key_to_non_unique_field_under_explicit_model(self):
|
||||
class Target(models.Model):
|
||||
|
@ -460,15 +429,13 @@ class RelativeFieldTests(SimpleTestCase):
|
|||
field = models.ForeignKey(Target, models.CASCADE, to_field='bad')
|
||||
|
||||
field = Model._meta.get_field('field')
|
||||
errors = field.check()
|
||||
expected = [
|
||||
self.assertEqual(field.check(), [
|
||||
Error(
|
||||
"'Target.bad' must set unique=True because it is referenced by a foreign key.",
|
||||
obj=field,
|
||||
id='fields.E311',
|
||||
),
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
def test_foreign_object_to_non_unique_fields(self):
|
||||
class Person(models.Model):
|
||||
|
@ -488,8 +455,7 @@ class RelativeFieldTests(SimpleTestCase):
|
|||
)
|
||||
|
||||
field = MMembership._meta.get_field('person')
|
||||
errors = field.check()
|
||||
expected = [
|
||||
self.assertEqual(field.check(), [
|
||||
Error(
|
||||
"No subset of the fields 'country_id', 'city_id' on model 'Person' is unique.",
|
||||
hint=(
|
||||
|
@ -499,8 +465,7 @@ class RelativeFieldTests(SimpleTestCase):
|
|||
obj=field,
|
||||
id='fields.E310',
|
||||
)
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
def test_on_delete_set_null_on_non_nullable_field(self):
|
||||
class Person(models.Model):
|
||||
|
@ -510,16 +475,14 @@ class RelativeFieldTests(SimpleTestCase):
|
|||
foreign_key = models.ForeignKey('Person', models.SET_NULL)
|
||||
|
||||
field = Model._meta.get_field('foreign_key')
|
||||
errors = field.check()
|
||||
expected = [
|
||||
self.assertEqual(field.check(), [
|
||||
Error(
|
||||
'Field specifies on_delete=SET_NULL, but cannot be null.',
|
||||
hint='Set null=True argument on the field, or change the on_delete rule.',
|
||||
obj=field,
|
||||
id='fields.E320',
|
||||
),
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
def test_on_delete_set_default_without_default_value(self):
|
||||
class Person(models.Model):
|
||||
|
@ -529,16 +492,14 @@ class RelativeFieldTests(SimpleTestCase):
|
|||
foreign_key = models.ForeignKey('Person', models.SET_DEFAULT)
|
||||
|
||||
field = Model._meta.get_field('foreign_key')
|
||||
errors = field.check()
|
||||
expected = [
|
||||
self.assertEqual(field.check(), [
|
||||
Error(
|
||||
'Field specifies on_delete=SET_DEFAULT, but has no default value.',
|
||||
hint='Set a default value, or change the on_delete rule.',
|
||||
obj=field,
|
||||
id='fields.E321',
|
||||
),
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
@skipIfDBFeature('interprets_empty_strings_as_nulls')
|
||||
def test_nullable_primary_key(self):
|
||||
|
@ -546,16 +507,14 @@ class RelativeFieldTests(SimpleTestCase):
|
|||
field = models.IntegerField(primary_key=True, null=True)
|
||||
|
||||
field = Model._meta.get_field('field')
|
||||
errors = field.check()
|
||||
expected = [
|
||||
self.assertEqual(field.check(), [
|
||||
Error(
|
||||
'Primary keys must not have null=True.',
|
||||
hint='Set null=False on the field, or remove primary_key=True argument.',
|
||||
obj=field,
|
||||
id='fields.E007',
|
||||
),
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
def test_not_swapped_model(self):
|
||||
class SwappableModel(models.Model):
|
||||
|
@ -635,8 +594,7 @@ class RelativeFieldTests(SimpleTestCase):
|
|||
|
||||
for field in fields:
|
||||
expected_error.obj = field
|
||||
errors = field.check(from_model=Model)
|
||||
self.assertEqual(errors, [expected_error])
|
||||
self.assertEqual(field.check(from_model=Model), [expected_error])
|
||||
|
||||
def test_related_field_has_invalid_related_name(self):
|
||||
digit = 0
|
||||
|
@ -667,8 +625,7 @@ class RelativeFieldTests(SimpleTestCase):
|
|||
})
|
||||
|
||||
field = Child._meta.get_field('parent')
|
||||
errors = Child.check()
|
||||
expected = [
|
||||
self.assertEqual(Child.check(), [
|
||||
Error(
|
||||
"The name '%s' is invalid related_name for field Child%s.parent"
|
||||
% (invalid_related_name, invalid_related_name),
|
||||
|
@ -676,8 +633,7 @@ class RelativeFieldTests(SimpleTestCase):
|
|||
obj=field,
|
||||
id='fields.E306',
|
||||
),
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
def test_related_field_has_valid_related_name(self):
|
||||
lowercase = 'a'
|
||||
|
@ -704,9 +660,7 @@ class RelativeFieldTests(SimpleTestCase):
|
|||
'parent': models.ForeignKey('Parent', models.CASCADE, related_name=related_name),
|
||||
'__module__': Parent.__module__,
|
||||
})
|
||||
|
||||
errors = Child.check()
|
||||
self.assertFalse(errors)
|
||||
self.assertEqual(Child.check(), [])
|
||||
|
||||
def test_to_fields_exist(self):
|
||||
class Parent(models.Model):
|
||||
|
@ -723,7 +677,7 @@ class RelativeFieldTests(SimpleTestCase):
|
|||
)
|
||||
|
||||
field = Child._meta.get_field('parent')
|
||||
expected = [
|
||||
self.assertEqual(field.check(), [
|
||||
Error(
|
||||
"The to_field 'a' doesn't exist on the related model 'invalid_models_tests.Parent'.",
|
||||
obj=field,
|
||||
|
@ -734,8 +688,7 @@ class RelativeFieldTests(SimpleTestCase):
|
|||
obj=field,
|
||||
id='fields.E312',
|
||||
),
|
||||
]
|
||||
self.assertEqual(field.check(), expected)
|
||||
])
|
||||
|
||||
def test_to_fields_not_checked_if_related_model_doesnt_exist(self):
|
||||
class Child(models.Model):
|
||||
|
@ -828,8 +781,7 @@ class AccessorClashTests(SimpleTestCase):
|
|||
class Model(models.Model):
|
||||
rel = relative
|
||||
|
||||
errors = Model.check()
|
||||
expected = [
|
||||
self.assertEqual(Model.check(), [
|
||||
Error(
|
||||
"Reverse accessor for 'Model.rel' clashes with field name 'Target.model_set'.",
|
||||
hint=("Rename field 'Target.model_set', or add/change "
|
||||
|
@ -838,8 +790,7 @@ class AccessorClashTests(SimpleTestCase):
|
|||
obj=Model._meta.get_field('rel'),
|
||||
id='fields.E302',
|
||||
),
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
def test_clash_between_accessors(self):
|
||||
class Target(models.Model):
|
||||
|
@ -849,8 +800,7 @@ class AccessorClashTests(SimpleTestCase):
|
|||
foreign = models.ForeignKey(Target, models.CASCADE)
|
||||
m2m = models.ManyToManyField(Target)
|
||||
|
||||
errors = Model.check()
|
||||
expected = [
|
||||
self.assertEqual(Model.check(), [
|
||||
Error(
|
||||
"Reverse accessor for 'Model.foreign' clashes with reverse accessor for 'Model.m2m'.",
|
||||
hint=(
|
||||
|
@ -869,8 +819,7 @@ class AccessorClashTests(SimpleTestCase):
|
|||
obj=Model._meta.get_field('m2m'),
|
||||
id='fields.E304',
|
||||
),
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
def test_m2m_to_m2m_with_inheritance(self):
|
||||
""" Ref #22047. """
|
||||
|
@ -887,8 +836,7 @@ class AccessorClashTests(SimpleTestCase):
|
|||
class Child(Parent):
|
||||
pass
|
||||
|
||||
errors = Model.check()
|
||||
expected = [
|
||||
self.assertEqual(Model.check(), [
|
||||
Error(
|
||||
"Reverse accessor for 'Model.children' clashes with field name 'Child.m2m_clash'.",
|
||||
hint=(
|
||||
|
@ -898,8 +846,7 @@ class AccessorClashTests(SimpleTestCase):
|
|||
obj=Model._meta.get_field('children'),
|
||||
id='fields.E302',
|
||||
)
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
def test_no_clash_for_hidden_related_name(self):
|
||||
class Stub(models.Model):
|
||||
|
@ -960,8 +907,7 @@ class ReverseQueryNameClashTests(SimpleTestCase):
|
|||
class Model(models.Model):
|
||||
rel = relative
|
||||
|
||||
errors = Model.check()
|
||||
expected = [
|
||||
self.assertEqual(Model.check(), [
|
||||
Error(
|
||||
"Reverse query name for 'Model.rel' clashes with field name 'Target.model'.",
|
||||
hint=(
|
||||
|
@ -971,8 +917,7 @@ class ReverseQueryNameClashTests(SimpleTestCase):
|
|||
obj=Model._meta.get_field('rel'),
|
||||
id='fields.E303',
|
||||
),
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
|
||||
@isolate_apps('invalid_models_tests')
|
||||
|
@ -1018,8 +963,7 @@ class ExplicitRelatedNameClashTests(SimpleTestCase):
|
|||
class Model(models.Model):
|
||||
rel = relative
|
||||
|
||||
errors = Model.check()
|
||||
expected = [
|
||||
self.assertEqual(Model.check(), [
|
||||
Error(
|
||||
"Reverse accessor for 'Model.rel' clashes with field name 'Target.clash'.",
|
||||
hint=(
|
||||
|
@ -1038,8 +982,7 @@ class ExplicitRelatedNameClashTests(SimpleTestCase):
|
|||
obj=Model._meta.get_field('rel'),
|
||||
id='fields.E303',
|
||||
),
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
|
||||
@isolate_apps('invalid_models_tests')
|
||||
|
@ -1126,8 +1069,7 @@ class ExplicitRelatedQueryNameClashTests(SimpleTestCase):
|
|||
class Model(models.Model):
|
||||
rel = relative
|
||||
|
||||
errors = Model.check()
|
||||
expected = [
|
||||
self.assertEqual(Model.check(), [
|
||||
Error(
|
||||
"Reverse query name for 'Model.rel' clashes with field name 'Target.clash'.",
|
||||
hint=(
|
||||
|
@ -1137,8 +1079,7 @@ class ExplicitRelatedQueryNameClashTests(SimpleTestCase):
|
|||
obj=Model._meta.get_field('rel'),
|
||||
id='fields.E303',
|
||||
),
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
|
||||
@isolate_apps('invalid_models_tests')
|
||||
|
@ -1149,8 +1090,7 @@ class SelfReferentialM2MClashTests(SimpleTestCase):
|
|||
first_m2m = models.ManyToManyField('self', symmetrical=False)
|
||||
second_m2m = models.ManyToManyField('self', symmetrical=False)
|
||||
|
||||
errors = Model.check()
|
||||
expected = [
|
||||
self.assertEqual(Model.check(), [
|
||||
Error(
|
||||
"Reverse accessor for 'Model.first_m2m' clashes with reverse accessor for 'Model.second_m2m'.",
|
||||
hint=(
|
||||
|
@ -1169,15 +1109,13 @@ class SelfReferentialM2MClashTests(SimpleTestCase):
|
|||
obj=Model._meta.get_field('second_m2m'),
|
||||
id='fields.E304',
|
||||
),
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
def test_accessor_clash(self):
|
||||
class Model(models.Model):
|
||||
model_set = models.ManyToManyField("self", symmetrical=False)
|
||||
|
||||
errors = Model.check()
|
||||
expected = [
|
||||
self.assertEqual(Model.check(), [
|
||||
Error(
|
||||
"Reverse accessor for 'Model.model_set' clashes with field name 'Model.model_set'.",
|
||||
hint=(
|
||||
|
@ -1187,15 +1125,13 @@ class SelfReferentialM2MClashTests(SimpleTestCase):
|
|||
obj=Model._meta.get_field('model_set'),
|
||||
id='fields.E302',
|
||||
),
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
def test_reverse_query_name_clash(self):
|
||||
class Model(models.Model):
|
||||
model = models.ManyToManyField("self", symmetrical=False)
|
||||
|
||||
errors = Model.check()
|
||||
expected = [
|
||||
self.assertEqual(Model.check(), [
|
||||
Error(
|
||||
"Reverse query name for 'Model.model' clashes with field name 'Model.model'.",
|
||||
hint=(
|
||||
|
@ -1205,16 +1141,14 @@ class SelfReferentialM2MClashTests(SimpleTestCase):
|
|||
obj=Model._meta.get_field('model'),
|
||||
id='fields.E303',
|
||||
),
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
def test_clash_under_explicit_related_name(self):
|
||||
class Model(models.Model):
|
||||
clash = models.IntegerField()
|
||||
m2m = models.ManyToManyField("self", symmetrical=False, related_name='clash')
|
||||
|
||||
errors = Model.check()
|
||||
expected = [
|
||||
self.assertEqual(Model.check(), [
|
||||
Error(
|
||||
"Reverse accessor for 'Model.m2m' clashes with field name 'Model.clash'.",
|
||||
hint=(
|
||||
|
@ -1233,16 +1167,14 @@ class SelfReferentialM2MClashTests(SimpleTestCase):
|
|||
obj=Model._meta.get_field('m2m'),
|
||||
id='fields.E303',
|
||||
),
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
def test_valid_model(self):
|
||||
class Model(models.Model):
|
||||
first = models.ManyToManyField("self", symmetrical=False, related_name='first_accessor')
|
||||
second = models.ManyToManyField("self", symmetrical=False, related_name='second_accessor')
|
||||
|
||||
errors = Model.check()
|
||||
self.assertEqual(errors, [])
|
||||
self.assertEqual(Model.check(), [])
|
||||
|
||||
|
||||
@isolate_apps('invalid_models_tests')
|
||||
|
@ -1252,8 +1184,7 @@ class SelfReferentialFKClashTests(SimpleTestCase):
|
|||
class Model(models.Model):
|
||||
model_set = models.ForeignKey("Model", models.CASCADE)
|
||||
|
||||
errors = Model.check()
|
||||
expected = [
|
||||
self.assertEqual(Model.check(), [
|
||||
Error(
|
||||
"Reverse accessor for 'Model.model_set' clashes with field name 'Model.model_set'.",
|
||||
hint=(
|
||||
|
@ -1264,15 +1195,13 @@ class SelfReferentialFKClashTests(SimpleTestCase):
|
|||
obj=Model._meta.get_field('model_set'),
|
||||
id='fields.E302',
|
||||
),
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
def test_reverse_query_name_clash(self):
|
||||
class Model(models.Model):
|
||||
model = models.ForeignKey("Model", models.CASCADE)
|
||||
|
||||
errors = Model.check()
|
||||
expected = [
|
||||
self.assertEqual(Model.check(), [
|
||||
Error(
|
||||
"Reverse query name for 'Model.model' clashes with field name 'Model.model'.",
|
||||
hint=(
|
||||
|
@ -1282,16 +1211,14 @@ class SelfReferentialFKClashTests(SimpleTestCase):
|
|||
obj=Model._meta.get_field('model'),
|
||||
id='fields.E303',
|
||||
),
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
def test_clash_under_explicit_related_name(self):
|
||||
class Model(models.Model):
|
||||
clash = models.CharField(max_length=10)
|
||||
foreign = models.ForeignKey("Model", models.CASCADE, related_name='clash')
|
||||
|
||||
errors = Model.check()
|
||||
expected = [
|
||||
self.assertEqual(Model.check(), [
|
||||
Error(
|
||||
"Reverse accessor for 'Model.foreign' clashes with field name 'Model.clash'.",
|
||||
hint=(
|
||||
|
@ -1310,8 +1237,7 @@ class SelfReferentialFKClashTests(SimpleTestCase):
|
|||
obj=Model._meta.get_field('foreign'),
|
||||
id='fields.E303',
|
||||
),
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
|
||||
@isolate_apps('invalid_models_tests')
|
||||
|
@ -1336,8 +1262,7 @@ class ComplexClashTests(SimpleTestCase):
|
|||
m2m_1 = models.ManyToManyField(Target, related_name='id')
|
||||
m2m_2 = models.ManyToManyField(Target, related_name='src_safe')
|
||||
|
||||
errors = Model.check()
|
||||
expected = [
|
||||
self.assertEqual(Model.check(), [
|
||||
Error(
|
||||
"Reverse accessor for 'Model.foreign_1' clashes with field name 'Target.id'.",
|
||||
hint=("Rename field 'Target.id', or add/change a related_name "
|
||||
|
@ -1425,8 +1350,7 @@ class ComplexClashTests(SimpleTestCase):
|
|||
obj=Model._meta.get_field('m2m_2'),
|
||||
id='fields.E305',
|
||||
),
|
||||
]
|
||||
self.assertEqual(errors, expected)
|
||||
])
|
||||
|
||||
|
||||
@isolate_apps('invalid_models_tests')
|
||||
|
@ -1459,8 +1383,7 @@ class M2mThroughFieldsTests(SimpleTestCase):
|
|||
inviter = models.ForeignKey(Fan, models.CASCADE, related_name='+')
|
||||
|
||||
field = Event._meta.get_field('invitees')
|
||||
errors = field.check(from_model=Event)
|
||||
expected = [
|
||||
self.assertEqual(field.check(from_model=Event), [
|
||||
Error(
|
||||
"'Invitation.invitee' is not a foreign key to 'Event'.",
|
||||
hint="Did you mean one of the following foreign keys to 'Event': event?",
|
||||
|
@ -1473,8 +1396,7 @@ class M2mThroughFieldsTests(SimpleTestCase):
|
|||
obj=field,
|
||||
id='fields.E339',
|
||||
),
|
||||
]
|
||||
self.assertEqual(expected, errors)
|
||||
])
|
||||
|
||||
def test_invalid_field(self):
|
||||
"""
|
||||
|
@ -1497,8 +1419,7 @@ class M2mThroughFieldsTests(SimpleTestCase):
|
|||
inviter = models.ForeignKey(Fan, models.CASCADE, related_name='+')
|
||||
|
||||
field = Event._meta.get_field('invitees')
|
||||
errors = field.check(from_model=Event)
|
||||
expected = [
|
||||
self.assertEqual(field.check(from_model=Event), [
|
||||
Error(
|
||||
"The intermediary model 'invalid_models_tests.Invitation' has no field 'invalid_field_1'.",
|
||||
hint="Did you mean one of the following foreign keys to 'Event': event?",
|
||||
|
@ -1511,8 +1432,7 @@ class M2mThroughFieldsTests(SimpleTestCase):
|
|||
obj=field,
|
||||
id='fields.E338',
|
||||
),
|
||||
]
|
||||
self.assertEqual(expected, errors)
|
||||
])
|
||||
|
||||
def test_explicit_field_names(self):
|
||||
"""
|
||||
|
@ -1531,16 +1451,16 @@ class M2mThroughFieldsTests(SimpleTestCase):
|
|||
inviter = models.ForeignKey(Fan, models.CASCADE, related_name='+')
|
||||
|
||||
field = Event._meta.get_field('invitees')
|
||||
errors = field.check(from_model=Event)
|
||||
expected = [
|
||||
self.assertEqual(field.check(from_model=Event), [
|
||||
Error(
|
||||
"Field specifies 'through_fields' but does not provide the names "
|
||||
"of the two link fields that should be used for the relation "
|
||||
"through model 'invalid_models_tests.Invitation'.",
|
||||
hint="Make sure you specify 'through_fields' as through_fields=('field1', 'field2')",
|
||||
obj=field,
|
||||
id='fields.E337')]
|
||||
self.assertEqual(expected, errors)
|
||||
id='fields.E337',
|
||||
),
|
||||
])
|
||||
|
||||
def test_superset_foreign_object(self):
|
||||
class Parent(models.Model):
|
||||
|
@ -1564,8 +1484,7 @@ class M2mThroughFieldsTests(SimpleTestCase):
|
|||
)
|
||||
|
||||
field = Child._meta.get_field('parent')
|
||||
errors = field.check(from_model=Child)
|
||||
expected = [
|
||||
self.assertEqual(field.check(from_model=Child), [
|
||||
Error(
|
||||
"No subset of the fields 'a', 'b' on model 'Parent' is unique.",
|
||||
hint=(
|
||||
|
@ -1575,8 +1494,7 @@ class M2mThroughFieldsTests(SimpleTestCase):
|
|||
obj=field,
|
||||
id='fields.E310',
|
||||
),
|
||||
]
|
||||
self.assertEqual(expected, errors)
|
||||
])
|
||||
|
||||
def test_intersection_foreign_object(self):
|
||||
class Parent(models.Model):
|
||||
|
@ -1602,8 +1520,7 @@ class M2mThroughFieldsTests(SimpleTestCase):
|
|||
)
|
||||
|
||||
field = Child._meta.get_field('parent')
|
||||
errors = field.check(from_model=Child)
|
||||
expected = [
|
||||
self.assertEqual(field.check(from_model=Child), [
|
||||
Error(
|
||||
"No subset of the fields 'a', 'b', 'd' on model 'Parent' is unique.",
|
||||
hint=(
|
||||
|
@ -1613,5 +1530,4 @@ class M2mThroughFieldsTests(SimpleTestCase):
|
|||
obj=field,
|
||||
id='fields.E310',
|
||||
),
|
||||
]
|
||||
self.assertEqual(expected, errors)
|
||||
])
|
||||
|
|
Loading…
Reference in New Issue