diff --git a/django/core/management/validation.py b/django/core/management/validation.py index 1dc76205c8d..0b3542c66d0 100644 --- a/django/core/management/validation.py +++ b/django/core/management/validation.py @@ -99,7 +99,7 @@ def get_validation_errors(outfile, app=None): if r.get_accessor_name() == rel_query_name: e.add(opts, "Reverse query name for field '%s' clashes with related field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name)) - seen_intermediary_signatures = [] + seen_intermediary_signatures = [] for i, f in enumerate(opts.local_many_to_many): # Check to see if the related m2m field will clash with any # existing fields, m2m fields, m2m related objects or related @@ -110,6 +110,11 @@ def get_validation_errors(outfile, app=None): # so skip the next section if isinstance(f.rel.to, (str, unicode)): continue + + # Check that the field is not set to unique. ManyToManyFields do not support unique. + if f.unique: + e.add(opts, "ManyToManyFields cannot be unique. Remove the unique argument on '%s'." % f.name) + if getattr(f.rel, 'through', None) is not None: if hasattr(f.rel, 'through_model'): from_model, to_model = cls, f.rel.to @@ -152,7 +157,7 @@ def get_validation_errors(outfile, app=None): e.add(opts, "'%s' has a manually-defined m2m relation through model %s, which does not have foreign keys to %s and %s" % (f.name, f.rel.through, f.rel.to._meta.object_name, cls._meta.object_name)) else: e.add(opts, "'%s' specifies an m2m relation through model %s, which has not been installed" % (f.name, f.rel.through)) - + rel_opts = f.rel.to._meta rel_name = RelatedObject(f.rel.to, cls, f).get_accessor_name() rel_query_name = f.related_query_name() diff --git a/tests/modeltests/invalid_models/models.py b/tests/modeltests/invalid_models/models.py index c450193d975..abd72b12938 100644 --- a/tests/modeltests/invalid_models/models.py +++ b/tests/modeltests/invalid_models/models.py @@ -110,11 +110,11 @@ class Car(models.Model): class MissingRelations(models.Model): rel1 = models.ForeignKey("Rel1") rel2 = models.ManyToManyField("Rel2") - + class MissingManualM2MModel(models.Model): name = models.CharField(max_length=5) missing_m2m = models.ManyToManyField(Model, through="MissingM2MModel") - + class Person(models.Model): name = models.CharField(max_length=5) @@ -176,7 +176,11 @@ class AbstractModel(models.Model): class AbstractRelationModel(models.Model): fk1 = models.ForeignKey('AbstractModel') fk2 = models.ManyToManyField('AbstractModel') - + +class UniqueM2M(models.Model): + """ Model to test for unique ManyToManyFields, which are invalid. """ + unique_people = models.ManyToManyField( Person, unique=True ) + 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. @@ -271,4 +275,5 @@ invalid_models.personselfrefm2m: Intermediary model RelationshipTripleFK has mor 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. +invalid_models.uniquem2m: ManyToManyFields cannot be unique. Remove the unique argument on 'unique_people'. """