Opened 7 years ago

Closed 12 months 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

Description

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):
        pass

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 14 months ago.

Download all attachments as: .zip

Change History (17)

comment:1 Changed 7 years ago by Carl Meyer

Cc: Carl Meyer added

comment:2 Changed 7 years ago by Ramiro Morales

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 Changed 7 years ago by Ilya Semenov

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 Changed 7 years ago by Russell Keith-Magee

Triage Stage: UnreviewedAccepted

comment:5 Changed 7 years ago by Ilya Semenov

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 Changed 7 years ago by Carl Meyer

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

comment:7 Changed 6 years ago by Luke Plant

Type: Bug

comment:8 Changed 6 years ago by Luke Plant

Severity: Normal

comment:9 Changed 6 years ago by anonymous

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

comment:10 Changed 5 years ago by Aymeric Augustin

UI/UX: unset

Change UI/UX from NULL to False.

comment:11 Changed 5 years ago by Aymeric Augustin

Easy pickings: unset

Change Easy pickings from NULL to False.

comment:12 Changed 4 years ago by Ramiro Morales

See also #13203.

comment:13 Changed 14 months ago by Tim Graham

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

Traceback:

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

Changed 14 months ago by Tim Graham

Attachment: 12885-test.diff added

comment:14 Changed 13 months ago by Anssi Kääriäinen

Has patch: set

I've created a PR for this (see https://github.com/django/django/pull/5487). 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 Changed 13 months ago by Tim Graham

Triage Stage: AcceptedReady for checkin

comment:16 Changed 12 months ago by Tim Graham <timograham@…>

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