Opened 14 years ago

Closed 9 years ago

#12885 closed Bug (fixed)

GenericRelation fails to join the related table from a inherited model

Reported by: Ilya Semenov Owned by: nobody
Component: contrib.contenttypes Version: 1.1
Severity: Normal Keywords:
Cc: Carl Meyer Triage Stage: Ready for checkin
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no


A minimalistic crashing example is worth thousands words:

class Car(models.Model):
        content_type = models.ForeignKey(ContentType)
        object_id = models.PositiveIntegerField()
        object = generic.GenericForeignKey()

class CarDriver(models.Model):
        cars = generic.GenericRelation(Car)

class Truck(Car):

class TruckDriver(models.Model):
        trucks = generic.GenericRelation(Truck)

# Selecting cars for a car drivers works fine

>>> john = CarDriver.objects.create()
>>> Car.objects.filter(cardriver=john)

# Selecting trucks for a truck driver crashes

>>> pete = TruckDriver.objects.create()
>>> Truck.objects.filter(truckdriver=pete)
# OperationalError: (1054, "Unknown column 'T2.object_id' in 'where clause'")

Attachments (1)

12885-test.diff (729 bytes ) - added by Tim Graham 9 years ago.

Download all attachments as: .zip

Change History (17)

comment:1 by Carl Meyer, 14 years ago

Cc: Carl Meyer added

comment:2 by Ramiro Morales, 14 years ago

Component: ORM aggregationDatabase layer (models, ORM)
Owner: set to nobody

Can you exercise the same test case you've created against SVN trunk and report back the results please?

comment:3 by Ilya Semenov, 14 years ago

The SQL query is a bit different in SVN trunk, but still results in the same error ("Unknown column 'T2.object_id' in 'where clause'").

SQL query in Django 1.1.1:

SELECT `tracker_car`.`id`, `tracker_car`.`content_type_id`, `tracker_car`.`object_id`, `tracker_truck`.`car_ptr_id`
FROM `tracker_truck`
INNER JOIN `tracker_truck` T2 ON (`tracker_truck`.`car_ptr_id` = T2.`id`)
INNER JOIN `tracker_car` ON (`tracker_truck`.`car_ptr_id` = `tracker_car`.`id`)
WHERE T2.`object_id` = 1 LIMIT 21

SQL query in Django-SVN r12453:

SELECT `tracker_car`.`id`, `tracker_car`.`content_type_id`, `tracker_car`.`object_id`, `tracker_truck`.`car_ptr_id`
FROM `tracker_truck`
INNER JOIN `tracker_truck` T2 ON (`tracker_truck`.`car_ptr_id` = T2.`car_ptr_id`)
INNER JOIN `tracker_car` ON (`tracker_truck`.`car_ptr_id` = `tracker_car`.`id`)
WHERE T2.`object_id` = 1 LIMIT 21

(By the way, I am also confused by the magic number 21, but that's irrelevant to the topic.)

comment:4 by Russell Keith-Magee, 14 years ago

Triage Stage: UnreviewedAccepted

comment:5 by Ilya Semenov, 14 years ago

Just in case, the expected query is:

SELECT `tracker_car`.`id`, `tracker_car`.`content_type_id`, `tracker_car`.`object_id`, `tracker_truck`.`car_ptr_id`
FROM `tracker_truck`
INNER JOIN `tracker_car` ON (`tracker_truck`.`car_ptr_id` = `tracker_car`.`id`)
WHERE `tracker_car`.`object_id` = 1
  • the redundant JOIN to itself removed along with its alias, and there's no "LIMIT 21".

I will probably look into the related ORM code on the weekend.

comment:6 by Carl Meyer, 14 years ago

The magic "LIMIT 21" is added because the QuerySet is evaluated via repr. This is a safety feature to prevent careless use of " shell" from bringing your database to its knees.

comment:7 by Luke Plant, 13 years ago

Type: Bug

comment:8 by Luke Plant, 13 years ago

Severity: Normal

comment:9 by anonymous, 13 years ago

Component: Database layer (models, ORM)contrib.contenttypes

comment:10 by Aymeric Augustin, 12 years ago

UI/UX: unset

Change UI/UX from NULL to False.

comment:11 by Aymeric Augustin, 12 years ago

Easy pickings: unset

Change Easy pickings from NULL to False.

comment:12 by Ramiro Morales, 11 years ago

See also #13203.

comment:13 by Tim Graham, 9 years ago

This remains an issue as of 58c7ff39fb265754fb17ab8d7f8a1401b355777b (Django 1.10 dev).

Here's the query for the attached failing test:

SELECT "generic_relations_mineral"."id", "generic_relations_mineral"."name", "generic_relations_mineral"."hardness", "generic_relations_valuablerock"."mineral_ptr_id"
FROM "generic_relations_valuablerock"
INNER JOIN "generic_relations_valuabletaggeditem" ON ("generic_relations_valuablerock"."mineral_ptr_id" = "generic_relations_valuabletaggeditem"."object_id" AND ("generic_relations_valuabletaggeditem"."content_type_id" = 13)) 
INNER JOIN "generic_relations_taggeditem" ON ("generic_relations_valuabletaggeditem"."taggeditem_ptr_id" = "generic_relations_taggeditem"."id")
INNER JOIN "generic_relations_mineral" ON ("generic_relations_valuablerock"."mineral_ptr_id" = "generic_relations_mineral"."id")
WHERE "generic_relations_taggeditem"."tag" = countertop


File "/home/tim/code/django/django/db/backends/sqlite3/", line 323, in execute
    return Database.Cursor.execute(self, query, params)
django.db.utils.OperationalError: no such column: generic_relations_valuabletaggeditem.object_id

by Tim Graham, 9 years ago

Attachment: 12885-test.diff added

comment:14 by Anssi Kääriäinen, 9 years ago

Has patch: set

I've created a PR for this (see Luckily the changes needed here were only to contrib.contenttypes. This is always a good sign, we likely don't have a more fundamental problem. Lets see what CI things of my PR...

comment:15 by Tim Graham, 9 years ago

Triage Stage: AcceptedReady for checkin

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

Resolution: fixed
Status: newclosed

In cd0ba805:

Fixed #12885 -- Fixed queries with GenericRelations to multi-table inheritance child models.

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