How to Access the Child Classes of an Object in Django Without Knowing the Name of the Child Class

How do I access the child classes of an object in django without knowing the name of the child class?

(Update: For Django 1.2 and newer, which can follow select_related queries across reverse OneToOneField relations (and thus down inheritance hierarchies), there's a better technique available which doesn't require the added real_type field on the parent model. It's available as InheritanceManager in the django-model-utils project.)

The usual way to do this is to add a ForeignKey to ContentType on the Parent model which stores the content type of the proper "leaf" class. Without this, you may have to do quite a number of queries on child tables to find the instance, depending how large your inheritance tree is. Here's how I did it in one project:

from django.contrib.contenttypes.models import ContentType
from django.db import models

class InheritanceCastModel(models.Model):
"""
An abstract base class that provides a ``real_type`` FK to ContentType.

For use in trees of inherited models, to be able to downcast
parent instances to their child types.

"""
real_type = models.ForeignKey(ContentType, editable=False)

def save(self, *args, **kwargs):
if self._state.adding:
self.real_type = self._get_real_type()
super(InheritanceCastModel, self).save(*args, **kwargs)

def _get_real_type(self):
return ContentType.objects.get_for_model(type(self))

def cast(self):
return self.real_type.get_object_for_this_type(pk=self.pk)

class Meta:
abstract = True

This is implemented as an abstract base class to make it reusable; you could also put these methods and the FK directly onto the parent class in your particular inheritance hierarchy.

This solution won't work if you aren't able to modify the parent model. In that case you're pretty much stuck checking all the subclasses manually.

How do I know which child class a Django model object is when selected through the parent class?

This is a common issue and still seems to be one of Django's uglier ducklings.

You could at least rearrange for 2 cents of DRY gain:

from django.core.exceptions import ObjectDoesNotExist

@property
def event_type(self):
for et in ('ticketedevent', 'rsvpevent', 'sillyhatsonlyevent', ...):
try:
getattr(self, et)
return et
except ObjectDoesNotExist:
pass

@property
def admin_link(self):
return reverse('admin:events_%s_change' % self.event_type, args=(self.id,))

If you really want to be fancy, you could use Event.__subclasses__ and generate the list of event types.

What's the easiest way of finding a child instance from a parent instance in Django?

Various forms of this question pop up here regularly. This answer demonstrates a generic way to "cast" a parent type to its proper subtype without having to query every subtype table. That way you wouldn't need to define a monster get_absolute_url on the parent which covers all the cases, you'd just convert to the child type and call get_absolute_url normally.

Find django object by .id only (unknown Model)

It is no a dumb question at all.

You may want to take a look at model inheritance:
https://docs.djangoproject.com/en/2.2/topics/db/models/#model-inheritance

You can setup an abstract equipment base model in which you put your id field. Then each of your specific equipment model (camera, display, switcher, etc.) inherit form this base table.

You can bonify your base model with this technic in order to get the child object from a search on its parent.

django - how do i access the child's Meta from the parent?

Try using self._meta for accessing Meta class for self.

Django: Query self referencing objects with no child elements

You can use isnull with the related_query_name:

class Category(models.Model):
# ...
parent = models.ForeignKey('self', null=True, related_name='children', related_query_name='child')

Category.objects.filter(child__isnull=True)

Here, I would recommend to specify at least a meaningful related_name!
If you specify only a related_name, the related_query_name defaults to that name (here: children). If you specify none of the two, the rqn defaults to the model name: category, not category_set

Category.objects.filter(category__isnull=True)  # not so informative


Related Topics



Leave a reply



Submit