Opened 13 years ago

Closed 12 years ago

Last modified 10 years 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

Description

According to the documentation (http://docs.djangoproject.com/en/dev/ref/models/fields/#django.db.models.ForeignKey.related_name) 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):
        pass

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 13 years ago.
15932-1.4rc1-Fixed-model-validation-when-using-hidden-related_name.patch (3.2 KB ) - added by Clay McClure 12 years ago.
Patch (with test) against 1.4rc1
15932-docs.diff (1.2 KB ) - added by Claude Paroz 12 years ago.
Explain related_name ended with +
15932-docs-2.diff (1.3 KB ) - added by Claude Paroz 12 years ago.
Fixed docs as of comment:7

Download all attachments as: .zip

Change History (16)

by Fredde, 13 years ago

Attachment: m2m_validation.patch added

comment:1 by Aymeric Augustin, 13 years ago

Needs tests: set
Triage Stage: UnreviewedAccepted

Confirmed with trunk.

comment:2 by Jann Kleen, 12 years ago

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):
    pass

class C(A):
    pass

Queries:

>>>b.tags.add(tag)
>>>b.tags.all()
[]

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;

by Clay McClure, 12 years ago

Patch (with test) against 1.4rc1

comment:3 by Clay McClure, 12 years ago

Cc: Clay McClure added
Needs tests: unset
Patch needs improvement: unset
Version: 1.31.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 by sean@…, 12 years ago

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 by Aymeric Augustin, 12 years ago

Component: Database layer (models, ORM)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!)

by Claude Paroz, 12 years ago

Attachment: 15932-docs.diff added

Explain related_name ended with +

comment:6 by Claude Paroz, 12 years ago

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

comment:7 by anonymous, 12 years ago

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 by Anssi Kääriäinen, 12 years ago

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?

by Claude Paroz, 12 years ago

Attachment: 15932-docs-2.diff added

Fixed docs as of comment:7

comment:9 by Tim Graham <timograham@…>, 12 years ago

Resolution: fixed
Status: newclosed

In [b496be331c19f41bee3a8f6c79de0722f91d6662]:

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

Thanks Claude Paroz for the patch.

comment:10 by Tim Graham <timograham@…>, 12 years ago

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 by Clay McClure, 12 years ago

Cc: Clay McClure removed

comment:12 by Loic Bistuer <loic.bistuer@…>, 10 years ago

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.

Note: See TracTickets for help on using tickets.
Back to Top