There seems to be some inconsistent behavior when combining querysets
that use isnull on a ForeignKey. I'm not sure how to explain it well
in plain english, so here's a boiled-down example:

# Models

class Item (models.Model):
    title = models.CharField( max_length=100 )

class PropertyValue (models.Model):
    label = models.CharField( max_length=100 )

class Property (models.Model):
    item = models.ForeignKey( Item, related_name='props' )
    key = models.CharField( max_length=100 )
    value = models.ForeignKey( PropertyValue, null=True )

# Example

item = Item.objects.create(title='Some Item')
pv = PropertyValue.objects.create(label='Some Value')
item.props.create(key='a', value=pv)
item.props.create(key='b')
q1 = Q(props__key='a', props__value=pv)
q2 = Q(props__key='b', props__value__isnull=True)
qs1 = Item.objects.filter(q1) & Item.objects.filter(q2)
qs2 = Item.objects.filter(q2) & Item.objects.filter(q1)

I would have expected qs1 and qs2 to yield the same result, but they
do not. They should both return the single item, but qs1 returns
nothing. The SQL for qs1 looks like:

SELECT "app_item"."id", "app_item"."title" FROM "app_item"
INNER JOIN "app_property" ON ("app_item"."id" =
"app_property"."item_id")
LEFT OUTER JOIN "app_property" T4 ON ("app_item"."id" = T4."item_id")
LEFT OUTER JOIN "app_propertyvalue" T5 ON ("app_property"."value_id" =
T5."id")
WHERE (("app_property"."value_id" = 1  AND "app_property"."key" =
'a' ) AND (T5."id" IS NULL AND T4."key" = 'b' ))

The first app_property join corresponds to q1, and the second
corresponds to q2. However, the app_propertyvalue join (corresponding
to the isnull from q2) refers to app_property.value_id (i.e. q1)
instead of T4.value_id (i.e. q2). I think fixing #10790 would fix
this, since removing the join to app_propertyvalue and simply checking
"T4.value_id IS NULL" works as expected, but I'm not sure if this is a
separate problem worthy of another ticket or not. Also (less
importantly), since both criteria (q1 and q2) are checking
props__key='something', I would imagine both joins could be INNER
JOINs, but the isnull seems to promote the second to a LEFT OUTER
JOIN.

I guess I was just wondering if I should open a separate ticket for
this, or is this simply a symptom of #10790? Or am I missing
something?

Regards,
Dan

-- 
You received this message because you are subscribed to the Google Groups 
"Django developers" group.
To post to this group, send email to django-develop...@googlegroups.com.
To unsubscribe from this group, send email to 
django-developers+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/django-developers?hl=en.

Reply via email to