Opened 3 years ago

Closed 2 years ago

Last modified 8 months ago

#15932 closed Bug (fixed)

related_name='+' ignored in ManyToManyField validation

Reported by: Fredde Owned by: nobody
Component: Documentation Version: 1.4-beta-1
Severity: Normal Keywords:
Cc: fredrik.kers@…, jann@…, sean@… Triage Stage: Accepted
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no


According to the documentation ( setting related_name='+' to any relation field should prevent django from creating a related field. This also seems to be the case in the contribute_to_related_class functions. However the validation of ManyToMany fields ignors this and gives an error message anyway.

To reproduce:

class A(models.Model):

class B(models.Model):
        # This works
        fk1 = models.ForeignKey(A, related_name = '+')
        fk2 = models.ForeignKey(A, related_name = '+')
        # This gives a "Accessor for m2m field 'm2m1' clashes with related m2m field 'A.+'" error
        m2m1 = models.ManyToManyField(A, related_name = '+')
        m2m2 = models.ManyToManyField(A, related_name = '+')

The attached patch will make the validator check f.rel.is_hidden() before doing any further validation of related field names.

Attachments (4)

m2m_validation.patch (847 bytes) - added by Fredde 3 years ago.
15932-1.4rc1-Fixed-model-validation-when-using-hidden-related_name.patch (3.2 KB) - added by clay 2 years ago.
Patch (with test) against 1.4rc1
15932-docs.diff (1.2 KB) - added by claudep 2 years ago.
Explain related_name ended with +
15932-docs-2.diff (1.3 KB) - added by claudep 2 years ago.
Fixed docs as of comment:7

Download all attachments as: .zip

Change History (16)

Changed 3 years ago by Fredde

comment:1 Changed 3 years ago by aaugustin

  • Needs documentation unset
  • Needs tests set
  • Patch needs improvement unset
  • Triage Stage changed from Unreviewed to Accepted

Confirmed with trunk.

comment:2 Changed 3 years ago by JannKleen

  • Cc jann@… added
  • Patch needs improvement set
  • UI/UX unset

I applied this patch but ran into some problems.

The m2m-insert worked as expected, but whenever executing .all(), the orm would create a sql query for the wrong table...

The problem was fixed when i gave all fields unique related_names again...

Model structure:

class A(models.Model):
    tags = models.ManyToManyField('tag', related_name='+')
    class Meta:
        abstract = True

class B(A):

class C(A):



The .all() produces a SQL query which looks roughly like that: (i.e. the orm picks the wrong m2m-table for some reason)

SELECT * FROM "foo_tag" INNER JOIN "foo_c_tags" ON ("foo_tag"."id" = "foo_c_tags"."tag_id") WHERE "foo_c_tags"."c_id" = 1;

Changed 2 years ago by clay

Patch (with test) against 1.4rc1

comment:3 Changed 2 years ago by clay

  • Cc clay added
  • Needs tests unset
  • Patch needs improvement unset
  • Version changed from 1.3 to 1.4-beta-1

This continues to be a problem in 1.4rc1. The attached patch fixes the reported model validation problem. If there is a problem in the ORM, that could be tracked in a separate ticket.

comment:4 Changed 2 years ago by sean@…

  • Cc sean@… added

I created a ticket for the ORM issue mentioned above: #18595
I think the work-around I mentioned in that ticket will work here as well.

Basically create a unique related_name value ending with '+' and it may avoid both issues.

comment:5 Changed 2 years ago by aaugustin

  • Component changed from Database layer (models, ORM) to Documentation

#18621 was a duplicate. I had forgotten about this ticket. I think it's a documentation issue. related_name must be unique and can end with '+' if you don't want the reverse relation to be created (although I don't know in which circumstances you wouldn't want to -- I you don't use it it doesn't hurt!)

Changed 2 years ago by claudep

Explain related_name ended with +

comment:6 Changed 2 years ago by claudep

Attached a patch with updated documentation about related_name. Please check the wording.

comment:7 Changed 2 years ago by anonymous

The statement that related_name has to be unique within a model is not true for the following cases:

  • The relation fields refers till different models
  • The related_name is "+" for a ForeignKey field

comment:8 Changed 2 years ago by akaariai

I don't think the patch is correct.

To me it seems the related_name must be unique in the related model, not in the originating model. And, as the '+' implies the related name is hidden in the related model, I don't see why it should be unique in this case even in the related model. It doesn't need to be unique, as it shouldn't exists at all. Maybe this is not a documentation issue after all?

Changed 2 years ago by claudep

Fixed docs as of comment:7

comment:9 Changed 2 years ago by Tim Graham <timograham@…>

  • Resolution set to fixed
  • Status changed from new to closed

In [b496be331c19f41bee3a8f6c79de0722f91d6662]:

Fixed #15932 - Documented how to supress multiple reverse relations to the same model.

Thanks Claude Paroz for the patch.

comment:10 Changed 2 years ago by Tim Graham <timograham@…>

In [1d280026c3797a23075739f28bb238972afad317]:

[1.4.X] Fixed #15932 - Documented how to supress multiple reverse relations to the same model.

Thanks Claude Paroz for the patch.

Backport of b496be331c from master

comment:11 Changed 2 years ago by clay

  • Cc clay removed

comment:12 Changed 8 months ago by Loic Bistuer <loic.bistuer@…>

In 82a58ce5b67e0b79fa0efbad72e21d9d1be25ceb:

Fixed #21491 -- Removed documented workaround for a known issue.

The issue was that two M2M hidden reverse managers
(related_name ending with a '+') could clash with each other.

Refs #21375 and #15932. Thanks Baptiste.

Add Comment

Modify Ticket

Change Properties
<Author field>
as closed
as The resolution will be set. Next status will be 'closed'
The resolution will be deleted. Next status will be 'new'

E-mail address and user name can be saved in the Preferences.

Note: See TracTickets for help on using tickets.