I have the following model inheritance structure in Django:
class Parent(models.Model):
# stuff
class A(Parent):
# stuff
class B(Parent):
# stuff
class C(Parent):
# stuff
and the list goes on.
I am using InheritanceManager of django-model-utils to filter objects like:
Parent.objects.filter(foo=bar).select_subclasses()
This works well when I want to filter all subclasses. What I want to do is to filter A and B objects, but not C objects. I want to do this with a single query like
Parent.objects.filter(foo=bar, __class__.__name__=A, __class__.__name__=B).select_subclasses()
Is it possible to do such a filtering operation, and if possible how?
It certainly is possible to do this in a single query!
It all comes from the way Django builds up fields to refer to the relationships between the parent and child models. Each child has a parent-ref
of some sort, which has a related_name
. You can query on these.
You'll probably find it easiest to start up a ./manage.py shell
, and import your parent model class, and then perform a nonsense query:
Parent.objects.filter(foo='bar')
This should show you the available fields for querying: you can then work out how to build the query:
Parent.objects.filter(is_active=True).filter(
models.Q(a__isnull=False) |
models.Q(b__isnull=False)
).select_subclasses()
This will perform a single query that will fetch all objects of A, all objects of B, that have is_active
set to True
, and downcast them.
The thing it is worth pointing out is that .select_subclasses()
is unable to detect which models are going to be included, so it joins in all subclasses.
However... you can pass values to select_subclasses
so it only joins (and downcasts) to those subclasses:
Parent.objects.filter(is_active=True).filter(
models.Q(a__isnull=False) |
models.Q(b__isnull=False)
).select_subclasses('a', 'b')
Now, we are no longer joining to tables "c" through "z"!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With