Code

Opened 6 years ago

Closed 17 months ago

#7700 closed Bug (fixed)

Query parent for child

Reported by: casey@… Owned by: nobody
Component: Core (Other) Version: master
Severity: Normal Keywords:
Cc: vzima 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.

Attachments (0)

Change History (11)

comment:1 follow-up: Changed 6 years ago by jamesturk

  • Needs documentation unset
  • Needs tests unset
  • Patch needs improvement unset
  • Triage Stage changed from Unreviewed to Design 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

comment:2 in reply to: ↑ 1 Changed 6 years ago by anonymous

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 Changed 6 years ago by Piotr Lewandowski <django@…>

  • Component changed from Uncategorized to Core framework

comment:4 Changed 4 years ago by mtredinnick

  • Triage Stage changed from Design decision needed to Accepted

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 follow-up: Changed 4 years ago by cdeccio

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>]

comment:6 in reply to: ↑ 5 Changed 4 years ago by vzima

  • Cc vzima 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 Changed 3 years ago by baumer1122

  • Severity set to Normal
  • Type set to Bug

comment:8 Changed 2 years ago by aaugustin

  • UI/UX unset

Change UI/UX from NULL to False.

comment:9 Changed 2 years ago by aaugustin

  • Easy pickings unset

Change Easy pickings from NULL to False.

comment:10 Changed 17 months ago by marcosmoyano

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 Changed 17 months ago by marcosmoyano

  • Resolution set to fixed
  • Status changed from new to closed

Add Comment

Modify Ticket

Change Properties
<Author field>
Action
as closed
as The resolution will be set. Next status will be 'closed'
The resolution will be deleted. Next status will be 'new'
Author


E-mail address and user name can be saved in the Preferences.

 
Note: See TracTickets for help on using tickets.