Opened 4 years ago

Closed 4 years ago

#25545 closed Bug (duplicate)

The ORM generates incorrect queries for m2m with disabled backward relations

Reported by: Morgan Aubert Owned by: nobody
Component: Database layer (models, ORM) Version: 1.8
Severity: Normal Keywords: m2m, related_name
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

This bug appears on the latest Django 1.8.5 release if you set two ManyToMany fields with the same name on two distinct models. The ManyToMany relations must be pointing toward the same model.

from django.db import models


class TestLabel(models.Model):
    label = models.CharField(max_length=100)


class TestModelA(models.Model):
    labels = models.ManyToManyField(TestLabel, related_name='a_labels+')


class TestModelB(models.Model):
    labels = models.ManyToManyField(TestLabel, related_name='b_labels+')

Whan you add a TestLabel instance to one of the labels relations, it is correctly added but you cannot fetch it using the all() method of the ManyRelatedManager: an empty list is returned.

>>> t1 = TestLabel.objects.create(label='Test 1')
>>> t2 = TestLabel.objects.create(label='Test 2')
>>> 
>>> a = TestModelA.objects.create()
>>> b = TestModelB.objects.create()
>>> 
>>> a.labels.add(t1)
>>> a.labels.all()
[]

Moreover, the generated SQL query is incorrect :

>>> print(a.labels.all().query)
SELECT "example_project_testlabel"."id", "example_project_testlabel"."label" FROM "example_project_testlabel" INNER JOIN "example_project_testmodelb_labels" ON ( "example_project_testlabel"."id" = "example_project_testmodelb_labels"."testlabel_id" ) WHERE "example_project_testmodelb_labels"."testmodelb_id" = 4

The bug seems to be caused by the related_name which is generated when the backward relation is disabled (0e2d3b93043676975aa921a70b5faafef02cac5c). The related_name should be generated from the name of the relation and the name of the class (this add been fixed in Django 1.9 - see f7b297815819153b53dc1125d3f42869fb1b7ebc).

This bug can cause ValueError exceptions to be raised if prefetch_related is applied to a queryset :

>>> TestModelA.objects.all().prefetch_related('labels')
[...]
ValueError: Cannot query "TestModelA object": Must be "TestModelB" instance.

Change History (3)

comment:1 Changed 4 years ago by Tim Graham

This is a regression in Django 1.8.5 then?

comment:2 in reply to:  1 Changed 4 years ago by Morgan Aubert

Replying to timgraham:

This is a regression in Django 1.8.5 then?

It seems so. I cannot reproduce the bug by using Django 1.8.4.

comment:3 Changed 4 years ago by Tim Graham

Resolution: duplicate
Status: newclosed

Marking as duplicate of #24156 and backported that fix to stable/1.8.x in eb85e6672aeb00c67a3666785965edeceed976af. Thanks for the report.

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