mirror of
https://github.com/django/django.git
synced 2025-04-26 02:04:38 +00:00
Fixed #26718 -- Added system check for existence of the fields specified by ForeignKey.to_field.
This commit is contained in:
parent
f6681393d3
commit
21130ce1a9
@ -463,9 +463,32 @@ class ForeignObject(RelatedField):
|
|||||||
|
|
||||||
def check(self, **kwargs):
|
def check(self, **kwargs):
|
||||||
errors = super(ForeignObject, self).check(**kwargs)
|
errors = super(ForeignObject, self).check(**kwargs)
|
||||||
|
errors.extend(self._check_to_fields_exist())
|
||||||
errors.extend(self._check_unique_target())
|
errors.extend(self._check_unique_target())
|
||||||
return errors
|
return errors
|
||||||
|
|
||||||
|
def _check_to_fields_exist(self):
|
||||||
|
# Skip nonexistent models.
|
||||||
|
if isinstance(self.remote_field.model, six.string_types):
|
||||||
|
return []
|
||||||
|
|
||||||
|
errors = []
|
||||||
|
for to_field in self.to_fields:
|
||||||
|
if to_field:
|
||||||
|
try:
|
||||||
|
self.remote_field.model._meta.get_field(to_field)
|
||||||
|
except exceptions.FieldDoesNotExist:
|
||||||
|
errors.append(
|
||||||
|
checks.Error(
|
||||||
|
"The to_field '%s' doesn't exist on the related "
|
||||||
|
"model '%s'."
|
||||||
|
% (to_field, self.remote_field.model._meta.label),
|
||||||
|
obj=self,
|
||||||
|
id='fields.E312',
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return errors
|
||||||
|
|
||||||
def _check_unique_target(self):
|
def _check_unique_target(self):
|
||||||
rel_is_string = isinstance(self.remote_field.model, six.string_types)
|
rel_is_string = isinstance(self.remote_field.model, six.string_types)
|
||||||
if rel_is_string or not self.requires_unique_target:
|
if rel_is_string or not self.requires_unique_target:
|
||||||
|
@ -211,6 +211,8 @@ Related Fields
|
|||||||
add at least a subset of them to a unique_together constraint.
|
add at least a subset of them to a unique_together constraint.
|
||||||
* **fields.E311**: ``<model>`` must set ``unique=True`` because it is
|
* **fields.E311**: ``<model>`` must set ``unique=True`` because it is
|
||||||
referenced by a ``ForeignKey``.
|
referenced by a ``ForeignKey``.
|
||||||
|
* **fields.E312**: The ``to_field`` ``<field name>`` doesn't exist on the
|
||||||
|
related model ``<app label>.<model>``.
|
||||||
* **fields.E320**: Field specifies ``on_delete=SET_NULL``, but cannot be null.
|
* **fields.E320**: Field specifies ``on_delete=SET_NULL``, but cannot be null.
|
||||||
* **fields.E321**: The field specifies ``on_delete=SET_DEFAULT``, but has no
|
* **fields.E321**: The field specifies ``on_delete=SET_DEFAULT``, but has no
|
||||||
default value.
|
default value.
|
||||||
|
@ -763,6 +763,56 @@ class RelativeFieldTests(SimpleTestCase):
|
|||||||
errors = Child.check()
|
errors = Child.check()
|
||||||
self.assertFalse(errors)
|
self.assertFalse(errors)
|
||||||
|
|
||||||
|
def test_to_fields_exist(self):
|
||||||
|
class Parent(models.Model):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class Child(models.Model):
|
||||||
|
a = models.PositiveIntegerField()
|
||||||
|
b = models.PositiveIntegerField()
|
||||||
|
parent = ForeignObject(
|
||||||
|
Parent,
|
||||||
|
on_delete=models.SET_NULL,
|
||||||
|
from_fields=('a', 'b'),
|
||||||
|
to_fields=('a', 'b'),
|
||||||
|
)
|
||||||
|
|
||||||
|
field = Child._meta.get_field('parent')
|
||||||
|
expected = [
|
||||||
|
Error(
|
||||||
|
"The to_field 'a' doesn't exist on the related model 'invalid_models_tests.Parent'.",
|
||||||
|
obj=field,
|
||||||
|
id='fields.E312',
|
||||||
|
),
|
||||||
|
Error(
|
||||||
|
"The to_field 'b' doesn't exist on the related model 'invalid_models_tests.Parent'.",
|
||||||
|
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):
|
||||||
|
a = models.PositiveIntegerField()
|
||||||
|
b = models.PositiveIntegerField()
|
||||||
|
parent = ForeignObject(
|
||||||
|
'invalid_models_tests.Parent',
|
||||||
|
on_delete=models.SET_NULL,
|
||||||
|
from_fields=('a', 'b'),
|
||||||
|
to_fields=('a', 'b'),
|
||||||
|
)
|
||||||
|
|
||||||
|
field = Child._meta.get_field('parent')
|
||||||
|
self.assertEqual(field.check(), [
|
||||||
|
Error(
|
||||||
|
"Field defines a relation with model 'invalid_models_tests.Parent', "
|
||||||
|
"which is either not installed, or is abstract.",
|
||||||
|
id='fields.E300',
|
||||||
|
obj=field,
|
||||||
|
),
|
||||||
|
])
|
||||||
|
|
||||||
|
|
||||||
@isolate_apps('invalid_models_tests')
|
@isolate_apps('invalid_models_tests')
|
||||||
class AccessorClashTests(SimpleTestCase):
|
class AccessorClashTests(SimpleTestCase):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user