Opened 10 years ago

Closed 9 years ago

#3906 closed (fixed)

Generic Relation query generates incorrect SQL

Reported by: Jamie.Norrish@… Owned by: nobody
Component: Contrib apps Version: 0.96
Severity: Keywords: generic
Cc: mir@… Triage Stage: Unreviewed
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: UI/UX:

Description

Given the following models:

class Entity (models.Model):
    entity_type = models.CharField(maxlength=30)

class PropertyAssertion (models.Model):
    entity = models.ForeignKey(Entity)
    assertion = models.GenericForeignKey()
    content_type = models.ForeignKey(ContentType, core=True)
    object_id = models.PositiveIntegerField()

class Name (models.Model):
    display_form = models.CharField(maxlength=400, blank=True)
    assertion = models.GenericRelation(PropertyAssertion)

having a method on the Entity class which performs

Name.objects.filter(assertion__entity=self, assertion__content_type=name_content_type)

(where name_content_type is whatever the content_type of the Name model is in the particular database), the generated SQL (slightly abbreviated in terms of the fields selected) is bogus:

SELECT "eats_core_name".*
FROM "eats_core_name" LEFT OUTER JOIN "eats_core_propertyassertion" AS "m2m_eats_core_name__assertion"
  ON "eats_core_name"."id" = "m2m_eats_core_name__assertion"."object_id"
 INNER JOIN "eats_core_propertyassertion" AS "eats_core_name__assertion"
  ON "m2m_eats_core_name__assertion"."object_id" = "eats_core_name__assertion"."id"
WHERE ("m2m_eats_core_name__assertion"."entity_id" = 1 AND "m2m_eats_core_name__assertion"."content_type_id" = 31)

This is joining the propertyassertion table to itself, linked by an identity between object_id and id, which have nothing to do with each other. The results of this query are predictably incorrect.

I don't know what the query was which 0.95 generated, but the code seemed to work then and does not with 0.96.

Attachments (1)

generic.py.patch (466 bytes) - added by codefi@… 9 years ago.
generic.py patch

Download all attachments as: .zip

Change History (8)

comment:1 Changed 9 years ago by fiman

Keywords: generic added

I believe I am having a problem like this as well, any idea if this can be fixed?

comment:2 Changed 9 years ago by anonymous

Component: UncategorizedContrib apps
Owner: changed from Jacob to Adrian Holovaty

Changed 9 years ago by codefi@…

Attachment: generic.py.patch added

generic.py patch

comment:3 Changed 9 years ago by coderfi@…

Has patch: set

Ok, I poked around the code, and I think I may have fixed it.
Revision: 5818 django/contrib/contenttypes/generic.py
has the following lines:

def m2m_column_name(self):

return self.object_id_field_name

def m2m_reverse_name(self):

return self.object_id_field_name

Does this seem funny to you?
So I poked around the history, and found that the m2m_reverse_name(self) method use to be:

def m2m_reverse_name(self):

return self.model._meta.pk.attname

When I changed the file to that, querying on the 'backwards' generic relationship now seems to work! Awesome!
Not sure if this fixes your problem, but it fixed my problem!

Added generic.py.patch

comment:4 Changed 9 years ago by Michael Radziej

Cc: mir@… added

comment:5 Changed 9 years ago by Malcolm Tredinnick

Keywords: qs-rf added

comment:6 Changed 9 years ago by Malcolm Tredinnick

Keywords: qs-rf removed

comment:7 Changed 9 years ago by Malcolm Tredinnick

Resolution: fixed
Status: newclosed

(In [6900]) Fixed #3906 -- Fixed the reverse_m2m_name for a generic relation. Refs #2749.

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