Opened 16 years ago

Closed 12 years ago

#7700 closed Bug (fixed)

Query parent for child

Reported by: casey@… Owned by: nobody
Component: Core (Other) Version: dev
Severity: Normal Keywords:
Cc: Vlastimil Zíma Triage Stage: Accepted
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

I'm not sure if this is a feature request or a bug fix :) This seemed to work a few weeks ago, and it no longer does. Whether or not the feature was intentional, it was quite useful--being able to query parent models for child instances. Given the following model:

from django.contrib.auth.models import Group

class Team(Group):
    pass

I want to query the Groups to find out which are Teams. This used to work

>>> g = Group.objects.create(name='group1')
>>> t = Team.objects.create(name='team1')
>>> Group.objects.filter(team__pk__isnull=False)
[<Group: team1>]

But instead now I get the following:

>>> Group.objects.filter(team__pk__isnull=False)
[<Group: group1>, <Group: team1>]

Ideally, it would be nice to simplify this to:

>>> Group.objects.filter(team__isnull=False)
[<Group: team1>]

But just getting it to work again would be nice.

Change History (11)

comment:1 by James Turk, 16 years ago

Triage Stage: UnreviewedDesign decision needed

unclear as to why this is advantageous over using Team.objects.all() / using child class directly when only children are wanted, ticket probably needs elaboration

in reply to:  1 comment:2 by anonymous, 16 years ago

Replying to jamesturk:

unclear as to why this is advantageous over using Team.objects.all() / using child class directly when only children are wanted, ticket probably needs elaboration

A more compelling example might be a case where a model only has a foreign key to a parent model. For example:

from django.contrib.auth.models import Group

class Team(Group):
   pass
>>> g = Group.objects.create(name='group1')
>>> t = Team.objects.create(name='team1')
>>> u = User.objects.create(username='val')
>>> u.groups = (g,t)
>>> u.groups.filter(team__isnull=False)
[<Group: team1>]

Of course, this can be done:

>>> u.groups.filter(pk__in=(list(Team.objects.all())))
[<Group: team1>]

But besides code complexity, it also results in an extra database query.

comment:3 by Piotr Lewandowski <django@…>, 16 years ago

Component: UncategorizedCore framework

comment:4 by Malcolm Tredinnick, 14 years ago

Triage Stage: Design decision neededAccepted

If this behaviour is still occurring, it's a flat out bug. The query discussed here is normal reverse-relation querying, as model inheritance is Python syntactic sugar for a one-to-one relation. You should definitely be able to do it and the query returning <Group: group1> in the report is returning an incorrect result. Needs verifying that the reported problem still exists, but, if it does, we should fix it.

comment:5 by cdeccio, 14 years ago

It still seems to be exhibiting the same behavior. Using 1.2.1, I get the following.

Model definition:

from django.contrib.auth.models import Group
class Team(Group):
    pass

Model creation:

>>> g = Group.objects.create(name='group1')
>>> t = Team.objects.create(name='team1')

Expected behavior:

>>> Team.objects.all()
[<Team: team1>]
>>> Group.objects.all()
[<Group: group1>, <Group: team1>]

Unexpected behavior:

>>> Group.objects.filter(team__pk__isnull=False)
[<Group: group1>, <Group: team1>]
>>> Group.objects.filter(team__isnull=False)
[<Group: group1>, <Group: team1>]

in reply to:  5 comment:6 by Vlastimil Zíma, 14 years ago

Cc: Vlastimil Zíma added

Replying to cdeccio:

It still seems to be exhibiting the same behavior. Using 1.2.1, I get the following.

I found out that following works fine and even looks good:

>>> Group.objects.filter(team=None)
[<Group: group1>]
>>> Group.objects.exclude(team=None)
[<Group: team1>]

And SQLs looks like:

SELECT U0."id" FROM "auth_group" U0
    LEFT OUTER JOIN "myapp_team" U1 ON (U0."id" = U1."group_ptr_id") WHERE U1."group_ptr_id" IS NULL

SELECT U0."id" FROM "auth_group" U0 
    WHERE NOT (
        U0."id" IN (
            SELECT U0."id" FROM "auth_group" U0 
                LEFT OUTER JOIN "myapp_team" U1 ON (U0."id" = U1."group_ptr_id")
                WHERE U1."group_ptr_id" IS NULL
        )
    )

comment:7 by Peter Baumgartner, 14 years ago

Severity: Normal
Type: Bug

comment:8 by Aymeric Augustin, 13 years ago

UI/UX: unset

Change UI/UX from NULL to False.

comment:9 by Aymeric Augustin, 13 years ago

Easy pickings: unset

Change Easy pickings from NULL to False.

comment:10 by Marcos Moyano, 12 years ago

The above queries work as they should. I just tested them with django's master branch.

In [1]: Group.objects.filter(team__pk__isnull=True)
Out[1]: [<Group: group1>]

In [2]: Group.objects.filter(team__pk__isnull=False)                                                                                                           
Out[2]: [<Group: team1>]

comment:11 by Marcos Moyano, 12 years ago

Resolution: fixed
Status: newclosed
Note: See TracTickets for help on using tickets.
Back to Top