Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

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
  • Loading branch information...
commit f748fa27629b8824d30866e4687bb91c264dfb65 1 parent c0727ad
@freakboy3742 freakboy3742 authored
View
4 django/core/management/validation.py
@@ -68,7 +68,7 @@ def get_validation_errors(outfile, app=None):
# fields, m2m fields, m2m related objects or related objects
if f.rel:
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
# so skip the next section
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
# objects
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
# so skip the next section
if isinstance(f.rel.to, (str, unicode)):
View
6 django/db/models/fields/related.py
@@ -646,6 +646,7 @@ def __init__(self, to, to_field=None, rel_class=ManyToOneRel, **kwargs):
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)
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
kwargs['verbose_name'] = kwargs.get('verbose_name', None)
@@ -756,6 +757,11 @@ def contribute_to_related_class(self, cls, related):
class ManyToManyField(RelatedField, Field):
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['rel'] = ManyToManyRel(to,
num_in_admin=kwargs.pop('num_in_admin', 0),
View
17 tests/modeltests/invalid_models/models.py
@@ -5,7 +5,7 @@
"""
from django.db import models
-model_errors = ""
+
class FieldErrors(models.Model):
charfield = models.CharField()
decimalfield = models.DecimalField()
@@ -168,6 +168,15 @@ class RelationshipDoubleFK(models.Model):
third = models.ForeignKey(Group, related_name="rel_to_set")
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.
invalid_models.fielderrors: "decimalfield": DecimalFields require a "decimal_places" attribute.
invalid_models.fielderrors: "decimalfield": DecimalFields require a "max_digits" attribute.
@@ -250,8 +259,8 @@ class RelationshipDoubleFK(models.Model):
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_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 relation with model Rel1, 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: '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: '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
@@ -260,4 +269,6 @@ class RelationshipDoubleFK(models.Model):
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.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.
"""
Please sign in to comment.
Something went wrong with that request. Please try again.