51👍
At its root, this is part of the mismatch between objects and relational databases. The ORM does a great job in abstracting out the differences, but sometimes you just come up against them anyway.
Basically, you have to choose between abstract inheritance, in which case there is no database relationship between the two classes, or multi-table inheritance, which keeps the database relationship at a cost of efficiency (an extra database join) for each query.
14👍
You can’t query abstract base classes. For multi-table inheritance you can use django-model-utils and it’s InheritanceManager
, which extends standard QuerySet
with select_subclasses()
method, which does right that you need: it left-joins all inherited tables and returns appropriate type instance for each row.
- [Django]-How to make an auto-filled and auto-incrementing field in django admin
- [Django]-Adding a user to a group in django
- [Django]-Django admin, hide a model
11👍
This is an example of polymorphism in your models (polymorph – many forms of one).
Option 1 – If there’s only one place you deal with this:
For the sake of a little bit of if-else code in one or two places, just deal with it manually – it’ll probably be much quicker and clearer in terms of dev/maintenance (i.e. maybe worth it unless these queries are seriously hammering your database – that’s your judgement call and depends on circumstance).
Option 2 – If you do this quite a bit, or really demand elegance in your query syntax:
Luckily there’s a library to deal with polymorphism in django, django-polymorphic – those docs will show you how to do this precisely. This is probably the “right answer” for querying straightforwardly as you’ve described, especially if you want to do model inheritance in lots of places.
Option 3 – If you want a halfway house:
This kind of has the drawbacks of both of the above, but I’ve used it successfully in the past to automatically do all the zipping together from multiple query sets, whilst keeping the benefits of having one query set object containing both types of models.
Check out django-querysetsequence which manages the merge of multiple query sets together.
It’s not as well supported or as stable as django-polymorphic
, but worth a mention nevertheless.
- [Django]-Modulus % in Django template
- [Django]-Django: using more than one database with inspectdb?
- [Django]-Error trying to install Postgres for python (psycopg2)
9👍
Don’t use an abstract base class if you need to query on the base. Use a concrete base class instead.
- [Django]-Variable subtraction in django templates
- [Django]-How can I disable logging while running unit tests in Python Django?
- [Django]-How to access request body when using Django Rest Framework and avoid getting RawPostDataException
1👍
In this case I think there’s no other way.
For optimization, you could avoid inheritance from abstract StellarObject
and use it as separate table connected via FK to Star
and Planet
objects.
That way both of them would have ie. star.stellar_info.description
.
Other way would be to add additional model for handling information and using StellarObject as through
in many2many relation.
- [Django]-Creating my own context processor in django
- [Django]-How to use "get_or_create()" in Django?
- [Django]-Whats the difference between a OneToOne, ManyToMany, and a ForeignKey Field in Django?
1👍
I would consider moving away from either an abstract inheritance pattern or the concrete base pattern if you’re looking to tie distinct sub-class behaviors to the objects based on their respective child class.
When you query via the parent class — which it sounds like you want to do — Django treats the resulting ojects as objects of the parent class, so accessing child-class-level methods requires re-casting the objects into their ‘proper’ child class on the fly so they can see those methods… at which point a series of if statements hanging off a parent-class-level method would arguably be a cleaner approach.
If the sub-class behavior described above isn’t an issue, you could consider a custom manager attached to an abstract base class sewing the models together via raw SQL.
If you’re interested mainly in assigning a discrete set of identical data fields to a bunch of objects, I’d relate along a foreign-key, like bx2 suggests.
- [Django]-Get user information in django templates
- [Django]-Check if key exists in a Python dict in Jinja2 templates
- [Django]-Django development server reload takes too long
0👍
That seems horribly inefficient. Is that the only way?
As far as I know it is the only way with Django’s ORM. As implemented currently abstract classes are a convenient mechanism for abstracting common attributes of classes out to super classes. The ORM does not provide a similar abstraction for querying.
You’d be better off using another mechanism for implementing hierarchy in the database. One way to do this would be to use a single table and “tag” rows using type. Or you can implement a generic foreign key to another model that holds properties (the latter doesn’t sound right even to me).
- [Django]-Prepopulate Django (non-Model) Form
- [Django]-What's the best way to extend the User model in Django?
- [Django]-Django models avoid duplicates