diff --git a/django/core/management/validation.py b/django/core/management/validation.py index bc2856c127..d999c8b9b1 100644 --- a/django/core/management/validation.py +++ b/django/core/management/validation.py @@ -160,7 +160,7 @@ def get_validation_errors(outfile, app=None): elif field.rel.to == cls: seen_this_fk = True if not seen_related_fk or not seen_this_fk: - 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)) + e.add(opts, "'%s' is 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)) diff --git a/django/db/models/fields/related.py b/django/db/models/fields/related.py index 122ddd4ce5..008f5b6ac0 100644 --- a/django/db/models/fields/related.py +++ b/django/db/models/fields/related.py @@ -843,7 +843,7 @@ class ManyToManyField(RelatedField, Field): self._m2m_column_name_cache = f.column break # If this is an m2m relation to self, avoid the inevitable name clash - elif related.model == related.parent_model: + elif related.model._meta.object_name.lower() == related.parent_model._meta.object_name.lower(): self._m2m_column_name_cache = 'from_' + related.model._meta.object_name.lower() + '_id' else: self._m2m_column_name_cache = related.model._meta.object_name.lower() + '_id' diff --git a/tests/modeltests/invalid_models/models.py b/tests/modeltests/invalid_models/models.py index c033d31237..dc41616c42 100644 --- a/tests/modeltests/invalid_models/models.py +++ b/tests/modeltests/invalid_models/models.py @@ -267,8 +267,8 @@ invalid_models.selfclashm2m: Reverse query name for m2m field 'm2m_3' clashes wi 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: '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.grouptwo: 'primary' is a manually-defined m2m relation through model Membership, which does not have foreign keys to Person and GroupTwo +invalid_models.grouptwo: 'secondary' is 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.group: The model Group has two manually-defined m2m relations through the model Membership, which is not permitted. Please consider using an extra field on your intermediary model instead. invalid_models.group: Intermediary model RelationshipDoubleFK has more than one foreign key to Person, which is ambiguous and is not permitted. diff --git a/tests/regressiontests/m2m_regress/models.py b/tests/regressiontests/m2m_regress/models.py index 913e719902..7f6da3341b 100644 --- a/tests/regressiontests/m2m_regress/models.py +++ b/tests/regressiontests/m2m_regress/models.py @@ -1,4 +1,5 @@ from django.db import models +from django.contrib.auth import models as auth # No related name is needed here, since symmetrical relations are not # explicitly reversible. @@ -41,6 +42,14 @@ class Worksheet(models.Model): id = models.CharField(primary_key=True, max_length=100) lines = models.ManyToManyField(Line, blank=True, null=True) +# Regression for #11226 -- A model with the same name that another one to +# which it has a m2m relation. This shouldn't cause a name clash between +# the automatically created m2m intermediary table FK field names when +# running syncdb +class User(models.Model): + name = models.CharField(max_length=30) + friends = models.ManyToManyField(auth.User) + __test__ = {"regressions": """ # Multiple m2m references to the same model or a different model must be # distinguished when accessing the relations through an instance attribute.