Fixed #7908: Added validation checks on attempts to create ForeignKey and M2M relations with abstract classes. Thanks to Rock Howard for the report.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@8442 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
c0727ad43d
commit
f748fa2762
|
@ -68,7 +68,7 @@ def get_validation_errors(outfile, app=None):
|
||||||
# fields, m2m fields, m2m related objects or related objects
|
# fields, m2m fields, m2m related objects or related objects
|
||||||
if f.rel:
|
if f.rel:
|
||||||
if f.rel.to not in models.get_models():
|
if f.rel.to not in models.get_models():
|
||||||
e.add(opts, "'%s' has relation with model %s, which has not been installed" % (f.name, f.rel.to))
|
e.add(opts, "'%s' has a relation with model %s, which has either not been installed or is abstract." % (f.name, f.rel.to))
|
||||||
# it is a string and we could not find the model it refers to
|
# it is a string and we could not find the model it refers to
|
||||||
# so skip the next section
|
# so skip the next section
|
||||||
if isinstance(f.rel.to, (str, unicode)):
|
if isinstance(f.rel.to, (str, unicode)):
|
||||||
|
@ -105,7 +105,7 @@ def get_validation_errors(outfile, app=None):
|
||||||
# existing fields, m2m fields, m2m related objects or related
|
# existing fields, m2m fields, m2m related objects or related
|
||||||
# objects
|
# objects
|
||||||
if f.rel.to not in models.get_models():
|
if f.rel.to not in models.get_models():
|
||||||
e.add(opts, "'%s' has m2m relation with model %s, which has not been installed" % (f.name, f.rel.to))
|
e.add(opts, "'%s' has an m2m relation with model %s, which has either not been installed or is abstract." % (f.name, f.rel.to))
|
||||||
# it is a string and we could not find the model it refers to
|
# it is a string and we could not find the model it refers to
|
||||||
# so skip the next section
|
# so skip the next section
|
||||||
if isinstance(f.rel.to, (str, unicode)):
|
if isinstance(f.rel.to, (str, unicode)):
|
||||||
|
|
|
@ -646,6 +646,7 @@ class ForeignKey(RelatedField, Field):
|
||||||
except AttributeError: # to._meta doesn't exist, so it must be RECURSIVE_RELATIONSHIP_CONSTANT
|
except AttributeError: # to._meta doesn't exist, so it must be RECURSIVE_RELATIONSHIP_CONSTANT
|
||||||
assert isinstance(to, basestring), "%s(%r) is invalid. First parameter to ForeignKey must be either a model, a model name, or the string %r" % (self.__class__.__name__, to, RECURSIVE_RELATIONSHIP_CONSTANT)
|
assert isinstance(to, basestring), "%s(%r) is invalid. First parameter to ForeignKey must be either a model, a model name, or the string %r" % (self.__class__.__name__, to, RECURSIVE_RELATIONSHIP_CONSTANT)
|
||||||
else:
|
else:
|
||||||
|
assert not to._meta.abstract, "%s cannot define a relation with abstract class %s" % (self.__class__.__name__, to._meta.object_name)
|
||||||
to_field = to_field or to._meta.pk.name
|
to_field = to_field or to._meta.pk.name
|
||||||
kwargs['verbose_name'] = kwargs.get('verbose_name', None)
|
kwargs['verbose_name'] = kwargs.get('verbose_name', None)
|
||||||
|
|
||||||
|
@ -756,6 +757,11 @@ class OneToOneField(ForeignKey):
|
||||||
|
|
||||||
class ManyToManyField(RelatedField, Field):
|
class ManyToManyField(RelatedField, Field):
|
||||||
def __init__(self, to, **kwargs):
|
def __init__(self, to, **kwargs):
|
||||||
|
try:
|
||||||
|
assert not to._meta.abstract, "%s cannot define a relation with abstract class %s" % (self.__class__.__name__, to._meta.object_name)
|
||||||
|
except AttributeError: # to._meta doesn't exist, so it must be RECURSIVE_RELATIONSHIP_CONSTANT
|
||||||
|
assert isinstance(to, basestring), "%s(%r) is invalid. First parameter to ManyToManyField must be either a model, a model name, or the string %r" % (self.__class__.__name__, to, RECURSIVE_RELATIONSHIP_CONSTANT)
|
||||||
|
|
||||||
kwargs['verbose_name'] = kwargs.get('verbose_name', None)
|
kwargs['verbose_name'] = kwargs.get('verbose_name', None)
|
||||||
kwargs['rel'] = ManyToManyRel(to,
|
kwargs['rel'] = ManyToManyRel(to,
|
||||||
num_in_admin=kwargs.pop('num_in_admin', 0),
|
num_in_admin=kwargs.pop('num_in_admin', 0),
|
||||||
|
|
|
@ -5,7 +5,7 @@ This example exists purely to point out errors in models.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
model_errors = ""
|
|
||||||
class FieldErrors(models.Model):
|
class FieldErrors(models.Model):
|
||||||
charfield = models.CharField()
|
charfield = models.CharField()
|
||||||
decimalfield = models.DecimalField()
|
decimalfield = models.DecimalField()
|
||||||
|
@ -168,6 +168,15 @@ class RelationshipDoubleFK(models.Model):
|
||||||
third = models.ForeignKey(Group, related_name="rel_to_set")
|
third = models.ForeignKey(Group, related_name="rel_to_set")
|
||||||
date_added = models.DateTimeField()
|
date_added = models.DateTimeField()
|
||||||
|
|
||||||
|
class AbstractModel(models.Model):
|
||||||
|
name = models.CharField(max_length=10)
|
||||||
|
class Meta:
|
||||||
|
abstract = True
|
||||||
|
|
||||||
|
class AbstractRelationModel(models.Model):
|
||||||
|
fk1 = models.ForeignKey('AbstractModel')
|
||||||
|
fk2 = models.ManyToManyField('AbstractModel')
|
||||||
|
|
||||||
model_errors = """invalid_models.fielderrors: "charfield": CharFields require a "max_length" attribute.
|
model_errors = """invalid_models.fielderrors: "charfield": CharFields require a "max_length" attribute.
|
||||||
invalid_models.fielderrors: "decimalfield": DecimalFields require a "decimal_places" attribute.
|
invalid_models.fielderrors: "decimalfield": DecimalFields require a "decimal_places" attribute.
|
||||||
invalid_models.fielderrors: "decimalfield": DecimalFields require a "max_digits" attribute.
|
invalid_models.fielderrors: "decimalfield": DecimalFields require a "max_digits" attribute.
|
||||||
|
@ -250,8 +259,8 @@ invalid_models.selfclashm2m: Accessor for m2m field 'm2m_4' clashes with related
|
||||||
invalid_models.selfclashm2m: Accessor for m2m field 'm2m_4' clashes with related m2m field 'SelfClashM2M.selfclashm2m_set'. Add a related_name argument to the definition for 'm2m_4'.
|
invalid_models.selfclashm2m: Accessor for m2m field 'm2m_4' clashes with related m2m field 'SelfClashM2M.selfclashm2m_set'. Add a related_name argument to the definition for 'm2m_4'.
|
||||||
invalid_models.selfclashm2m: Reverse query name for m2m field 'm2m_3' clashes with field 'SelfClashM2M.selfclashm2m'. Add a related_name argument to the definition for 'm2m_3'.
|
invalid_models.selfclashm2m: Reverse query name for m2m field 'm2m_3' clashes with field 'SelfClashM2M.selfclashm2m'. Add a related_name argument to the definition for 'm2m_3'.
|
||||||
invalid_models.selfclashm2m: Reverse query name for m2m field 'm2m_4' clashes with field 'SelfClashM2M.selfclashm2m'. Add a related_name argument to the definition for 'm2m_4'.
|
invalid_models.selfclashm2m: Reverse query name for m2m field 'm2m_4' clashes with field 'SelfClashM2M.selfclashm2m'. Add a related_name argument to the definition for 'm2m_4'.
|
||||||
invalid_models.missingrelations: 'rel2' has m2m relation with model Rel2, which has not been installed
|
invalid_models.missingrelations: 'rel1' has a relation with model Rel1, which has either not been installed or is abstract.
|
||||||
invalid_models.missingrelations: 'rel1' has relation with model Rel1, which has not been installed
|
invalid_models.missingrelations: 'rel2' has an m2m relation with model Rel2, which has either not been installed or is abstract.
|
||||||
invalid_models.grouptwo: 'primary' has a manually-defined m2m relation through model Membership, which does not have foreign keys to Person and GroupTwo
|
invalid_models.grouptwo: 'primary' has a manually-defined m2m relation through model Membership, which does not have foreign keys to Person and GroupTwo
|
||||||
invalid_models.grouptwo: 'secondary' has a manually-defined m2m relation through model MembershipMissingFK, which does not have foreign keys to Group and GroupTwo
|
invalid_models.grouptwo: 'secondary' has a manually-defined m2m relation through model MembershipMissingFK, which does not have foreign keys to Group and GroupTwo
|
||||||
invalid_models.missingmanualm2mmodel: 'missing_m2m' specifies an m2m relation through model MissingM2MModel, which has not been installed
|
invalid_models.missingmanualm2mmodel: 'missing_m2m' specifies an m2m relation through model MissingM2MModel, which has not been installed
|
||||||
|
@ -260,4 +269,6 @@ invalid_models.group: Intermediary model RelationshipDoubleFK has more than one
|
||||||
invalid_models.personselfrefm2m: Many-to-many fields with intermediate tables cannot be symmetrical.
|
invalid_models.personselfrefm2m: Many-to-many fields with intermediate tables cannot be symmetrical.
|
||||||
invalid_models.personselfrefm2m: Intermediary model RelationshipTripleFK has more than two foreign keys to PersonSelfRefM2M, which is ambiguous and is not permitted.
|
invalid_models.personselfrefm2m: Intermediary model RelationshipTripleFK has more than two foreign keys to PersonSelfRefM2M, which is ambiguous and is not permitted.
|
||||||
invalid_models.personselfrefm2mexplicit: Many-to-many fields with intermediate tables cannot be symmetrical.
|
invalid_models.personselfrefm2mexplicit: Many-to-many fields with intermediate tables cannot be symmetrical.
|
||||||
|
invalid_models.abstractrelationmodel: 'fk1' has a relation with model AbstractModel, which has either not been installed or is abstract.
|
||||||
|
invalid_models.abstractrelationmodel: 'fk2' has an m2m relation with model AbstractModel, which has either not been installed or is abstract.
|
||||||
"""
|
"""
|
||||||
|
|
Loading…
Reference in New Issue