2

I have these two simple models, A and B:

from django.db import models

class A(models.Model):
  name = models.CharField(max_length=10)

class B(A):
  age = models.IntegerField()

Now, how can I query for all instances of A which do not have an instance of B?

The only way I found requires an explicitly unique field on each subclass, which is NOT NULL, so that I can do A.objects.filter(b__this_is_a_b=None), for example, to get instances that are not also B instances. I'm looking for a way to do this without adding an explicit silly flag like that.

I also don't want to query for all of the objects and then filter them in Python. I want to get the DB to do it for me, which is basically something like SELECT * FROM A WHERE A.id in (SELECT id from B)

ironfroggy
  • 7,991
  • 7
  • 33
  • 44

3 Answers3

2

Since some version of django or python this works as well:

A.Objects.all().filter(b__isnull=True)

because if a is an A object a.b gives the subclass B of a when it exists

I Know this is an old question, but my answer might help new searchers on this subject.

see also:

multi table inheritance

And one of my own questions about this: downcasting a super class to a sub class

Community
  • 1
  • 1
michel.iamit
  • 5,788
  • 9
  • 55
  • 74
1

I'm not sure it's possible to do this purely in the DB with Django's ORM, in a single query. Here's the best I've been able to do:

A.objects.exclude(id__in=[r[0] for r in B.objects.values_list("a_ptr_id")])

This is 2 DB queries, and works best with a simplistic inheritance graph - each subclass of A would require a new database query.


Okay, it took a lot of trial and error, but I have a solution. It's ugly as all hell, and the SQL is probably worse than just going with two queries, but you can do something like so:

A.objects.exclude(b__age__isnull=True).exclude(b__age_isnull=False)

There's no way to get Django to do the join without referencing a field on b. But with these successive .exclude()s, you make any A with a B subclass match one or the other of the excludes. All you're left with are A's without a B subclass.

Anyway, this is an interesting use case, you should bring it up on django-dev...

AdamKG
  • 13,678
  • 3
  • 38
  • 46
  • I would accept this answer, but it doesn't seem like any answer is really "correct" in a good sense. I'll bring it up with django-dev as you suggest. – ironfroggy Feb 26 '09 at 16:05
0

I don't work with django, but it looks like you want the isinstance(obj, type) built-in python method.

Edit:
Would A.objects.exclude(id__exact=B__id) work?

tgray
  • 8,826
  • 5
  • 36
  • 41
  • Unfortunately, no. I'm trying to give the django ORM the right instructions to generate the SQL to do this for me, rather than filter them on the client side. – ironfroggy Feb 26 '09 at 15:03