There are a couple approaches you can take to handling the QuerySet
s of "mixed models" that you obtain when you perform this kind of query. A lot of it depends on your ultimate goal.
The "simple and dumb" way, which I use a lot, is to manage the results with utility functions. If you plan to process the result of Build.objects.filter(project="myproject")
in a template, for example, you could use custom template tags or filters to take special action. Assume in the below code build_objects
contains the result of your filter():
{% for build in build_objects %}
{% if build|is_custom_build %}
<p>This is a custom build of custom type {{ build.custom_build.custom_type }}!</p>
{% endif %}
<p>This is a custom build OR a standard build</p>
{% endfor %}
The obvious problem here is if you have numerous subclasses, writing template filters may be impractical or grow tedious. However, in my experience I usually have a half-dozen subclasses at most so this is not always a problem.
You could also write a parameterized filter like so:
{% if build|is_of_buildtype:"custom_build" %}
With the filter code as follows:
def is_of_buildtype_filter(value, arg):
if hasattr(value, arg): return True
else: return False
This filter simply checks for the presence of the argument as an attribute on the build
object (passed in as value
). The argument string should be the name of the automatically generated OneToOneField
that you want to detect, in this case custom_build
.
For view code, similar sorts of helper functions would work the same way but are even easier because you don't need to write custom filters or tags.
This approach works in many cases, but there are more complicated scenarios where it might not be practical. Unfortunately, Django cannot natively provide you with a QuerySet
that contains subclass instances when you perform operations on the base class (ie. a QuerySet
that truly contains "mixed models"). You may require this in situations where processing the results with helper functions is not possible.
I personally avoid these situations entirely, usually by rethinking my model design. But if that's not possible, there are many interesting attempts at solutions, like this Inheritance MixIn. There are also several Django snippets on the subject. Be aware, though, that almost any solution like this will be performance-limited.