Opened 8 years ago

Closed 7 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@… 8 years ago.
generic.py patch

Download all attachments as: .zip

Change History (8)

comment:1 Changed 8 years ago by fiman

  • Keywords generic added
  • Needs documentation unset
  • Needs tests unset
  • Patch needs improvement unset

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

comment:2 Changed 8 years ago by anonymous

  • Component changed from Uncategorized to Contrib apps
  • Owner changed from jacob to adrian

Changed 8 years ago by codefi@…

generic.py patch

comment:3 Changed 8 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 8 years ago by mir

  • Cc mir@… added

comment:5 Changed 7 years ago by mtredinnick

  • Keywords qs-rf added

comment:6 Changed 7 years ago by mtredinnick

  • Keywords qs-rf removed

comment:7 Changed 7 years ago by mtredinnick

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

(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