home / django_tickets / tickets

tickets: 8439

This data as json

id created changetime last_pulled_from_trac stage status component type severity version resolution summary description owner reporter keywords easy has_patch needs_better_patch needs_tests needs_docs ui_ux
8439 2008-08-20 05:58:53 2011-09-28 16:12:17 2022-03-06 03:42:16.536345 Accepted closed Database layer (models, ORM)     dev fixed Q objects still incorrectly choosing inner join over outer join I am basically reopening #3592 with an example that is broken in the latest SVN. I am using SVN r8445. Here are my test models: {{{ class Enemy(models.Model): pass class Troop(models.Model): pass class Soldier(models.Model): troop = models.ForeignKey(Troop) class TroopKill(models.Model): enemy = models.ForeignKey(Enemy) troop = models.ForeignKey(Troop) class SoldierKill(models.Model): enemy = models.ForeignKey(Enemy) soldier = models.ForeignKey(Soldier) grenade = models.BooleanField() }}} I want to find all enemies that were killed either by my soldier, or by the troop my soldier is in. So I execute the following query: {{{ direct_kills = Q(soldierkill__soldier__pk=1) troop_kills = Q(troopkill__troop__soldier__pk=1) all_kills = direct_kills | troop_kills print Enemy.objects.filter(all_kills).all() }}} And I get the correct SQL: {{{ SELECT "enemy"."id" FROM "enemy" LEFT OUTER JOIN "soldierkill" ON ("enemy"."id" = "soldierkill"."enemy_id") LEFT OUTER JOIN "troopkill" ON ("enemy"."id" = "troopkill"."enemy_id") LEFT OUTER JOIN "troop" ON ("troopkill"."troop_id" = "troop"."id") LEFT OUTER JOIN "soldier" T6 ON ("troop"."id" = T6."troop_id") WHERE ("soldierkill"."soldier_id" = 1 OR T6."id" = 1 ) }}} But when I try to add just one more condition (the direct kill had to have grenade=True): {{{ direct_kills = Q(soldierkill__soldier__pk=1,soldierkill__grenade=True) troop_kills = Q(troopkill__troop__soldier__pk=1) all_kills = direct_kills | troop_kills print Enemy.objects.filter(all_kills).all() }}} It switches incorrectly to inner joins. {{{ SELECT "enemy"."id" FROM "enemy" INNER JOIN "soldierkill" ON ("enemy"."id" = "soldierkill"."enemy_id") INNER JOIN "troopkill" ON ("enemy"."id" = "troopkill"."enemy_id") INNER JOIN "troop" ON ("troopkill"."troop_id" = "troop"."id") INNER JOIN "soldier" T6 ON ("troop"."id" = T6."troop_id") WHERE (("soldierkill"."grenade" = true AND "soldierkill"."soldier_id" = 1 ) OR T6."id" = 1 ) }}} Am I doing something wrong, or is this broken? Thanks, Mike mtredinnick mikemintz 1.0-blocker 0 0 0 0 0 0
Powered by Datasette · Queries took 1.038ms