#25486: ORM generating incorrect query for through-model on 
<RelatedManager>.all()
-------------------------------------+-------------------------------------
     Reporter:  pembo13              |                    Owner:  nobody
         Type:  Bug                  |                   Status:  closed
    Component:  Database layer       |                  Version:  1.8
  (models, ORM)                      |
     Severity:  Normal               |               Resolution:  duplicate
     Keywords:                       |             Triage Stage:
                                     |  Unreviewed
    Has patch:  0                    |      Needs documentation:  0
  Needs tests:  0                    |  Patch needs improvement:  0
Easy pickings:  0                    |                    UI/UX:  0
-------------------------------------+-------------------------------------
Changes (by timgraham):

 * status:  new => closed
 * needs_better_patch:   => 0
 * needs_tests:   => 0
 * needs_docs:   => 0
 * resolution:   => duplicate


Old description:

> I have a through-model which itself has a through model (because it needs
> a many-to-many relationship). The problem comes when i try to get related
> mode through this many-to-many relationship. The ORM generates the WHERE
> clause on the wrong field (the pk, instead of the fk).
>
> {{{
> #!sql
> -- generated sql
> SELECT "core_role"."id", "core_role"."name"
> FROM "core_role"
> INNER JOIN "core_dealercontactrole" ON ( "core_role"."id" =
> "core_dealercontactrole"."role_id" )
> WHERE "core_dealercontactrole"."id" = 8743
> ORDER BY "core_role"."name" ASC
>
> -- corrected sql
> SELECT "core_role"."id", "core_role"."name"
> FROM "core_role"
> INNER JOIN "core_dealercontactrole" ON ( "core_role"."id" =
> "core_dealercontactrole"."role_id" )
> WHERE "core_dealercontactrole"."dealercontact_id" = 8743
> ORDER BY "core_role"."name" ASC
> }}}
>
> The code that generated the query:
>
> {{{
> #!python
> dc = DealerContact.objects.get(id=8743)
> >>> unicode(dc.roles.all().query)
> u'SELECT "core_role"."id", "core_role"."name" FROM "core_role" INNER JOIN
> "core_dealercontactrole" ON ( "core_role"."id" =
> "core_dealercontactrole"."role_id" ) WHERE "core_dealercontactrole"."id"
> = 8743 ORDER BY "core_role"."name" ASC'
> }}}
>
> Here are the models (with superfluous fields removed):
>
> {{{
> #!python
> class Contact(models.Model):
>
>         first_name = models.CharField(blank=True, max_length=50)
>         last_name = models.CharField(blank=True, max_length=50)
>
>         class Meta:
>                 ordering = ('last_name','first_name')
>
>         pass
>
> class Dealer(models.Model):
>
>         contacts = models.ManyToManyField('Contact',
> through='DealerContact', related_name='dealers')
>
>         name = models.CharField(db_index=True, max_length=250)
>
>         pass
>
> class DealerContact(models.Model):
>
>         dealer = models.ForeignKey('Dealer',
> related_name='dealercontacts+', on_delete=models.CASCADE)
>         contact = models.ForeignKey('Contact', related_name='+',
> on_delete=models.CASCADE)
>         roles = models.ManyToManyField('Role',
> through='DealerContactRole', related_name='+')
>
>         class Meta:
>                 unique_together = ('dealer','contact')
>
>         pass
>
> class DealerContactRole(models.Model):
>
>         dealercontact = models.ForeignKey('DealerContact',
> related_name='+', on_delete=models.CASCADE)
>         role = models.ForeignKey('Role', related_name='+')
>
>         class Meta:
>                 unique_together = ('dealercontact','role')
>
>         pass
>
> class Role(models.Model):
>
>         name = models.CharField(db_index=True, max_length=100)
>
>         class Meta:
>                 ordering = ('name',)
>
>         pass
> }}}

New description:

 I have a through-model which itself has a through model (because it needs
 a many-to-many relationship). The problem comes when i try to get related
 mode through this many-to-many relationship. The ORM generates the WHERE
 clause on the wrong field (the pk, instead of the fk).

 {{{
 #!sql
 -- generated sql
 SELECT "core_role"."id", "core_role"."name"
 FROM "core_role"
 INNER JOIN "core_dealercontactrole" ON ( "core_role"."id" =
 "core_dealercontactrole"."role_id" )
 WHERE "core_dealercontactrole"."id" = 8743
 ORDER BY "core_role"."name" ASC

 -- corrected sql
 SELECT "core_role"."id", "core_role"."name"
 FROM "core_role"
 INNER JOIN "core_dealercontactrole" ON ( "core_role"."id" =
 "core_dealercontactrole"."role_id" )
 WHERE "core_dealercontactrole"."dealercontact_id" = 8743
 ORDER BY "core_role"."name" ASC
 }}}

 The code that generated the query:

 {{{
 #!python
 dc = DealerContact.objects.get(id=8743)
 >>> unicode(dc.roles.all().query)
 u'SELECT "core_role"."id", "core_role"."name" FROM "core_role" INNER JOIN
 "core_dealercontactrole" ON ( "core_role"."id" =
 "core_dealercontactrole"."role_id" ) WHERE "core_dealercontactrole"."id" =
 8743 ORDER BY "core_role"."name" ASC'
 }}}

 Here are the models (with superfluous fields removed):

 {{{
 #!python
 class Contact(models.Model):
     first_name = models.CharField(blank=True, max_length=50)
     last_name = models.CharField(blank=True, max_length=50)

     class Meta:
         ordering = ('last_name', 'first_name')

 class Dealer(models.Model):
     contacts = models.ManyToManyField('Contact', through='DealerContact',
 related_name='dealers')
     name = models.CharField(db_index=True, max_length=250)

 class DealerContact(models.Model):
     dealer = models.ForeignKey('Dealer', related_name='dealercontacts+',
 on_delete=models.CASCADE)
     contact = models.ForeignKey('Contact', related_name='+',
 on_delete=models.CASCADE)
     roles = models.ManyToManyField('Role', through='DealerContactRole',
 related_name='+')

     class Meta:
         unique_together = ('dealer', 'contact')

 class DealerContactRole(models.Model):
     dealercontact = models.ForeignKey('DealerContact', related_name='+',
 on_delete=models.CASCADE)
     role = models.ForeignKey('Role', related_name='+')

     class Meta:
         unique_together = ('dealercontact', 'role')

 class Role(models.Model):
     name = models.CharField(db_index=True, max_length=100)

     class Meta:
         ordering = ('name',)
 }}}

--

Comment:

 This seems to be a regression in 1.8 and a duplicate of #24505 (bisected
 to fb48eb05816b1ac87d58696cdfe48be18c901f16 and fixed subsequently fixed
 in 4ee08958f154594b538207a53c1d457687b3f7ae). I'll backport that fix to
 1.8.

--
Ticket URL: <https://code.djangoproject.com/ticket/25486#comment:1>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-updates+unsubscr...@googlegroups.com.
To post to this group, send email to django-updates@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/065.97b717465e2bcc1c2a392fe688f3c9fc%40djangoproject.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to