I'm trying to find the actual class of a django-model object, when using model-inheritance.
Some code to describe the problem:
class Base(models.model): def basemethod(self): ... class Child_1(Base): pass class Child_2(Base): pass
If I create various objects of the two Child classes and the create a queryset containing them all:
Child_1().save() Child_2().save() (o1, o2) = Base.objects.all()
I want to determine if the object is of type Child_1 or Child_2 in basemethod, I can get to the child object via o1.child_1 and o2.child_2 but that reconquers knowledge about the childclasses in the baseclass.
I have come up with the following code:
def concrete_instance(self): instance = None for subclass in self._meta.get_all_related_objects(): acc_name = subclass.get_accessor_name() try: instance = self.__getattribute__(acc_name) return instance except Exception, e: pass
But it feels brittle and I'm not sure of what happens when if I inherit in more levels.
Returning MatPotLib image as string
Separation of ORM and validation
swfupload failing in my django runserver
When you do
Base.object.all(), Django is querying just the Base table, and so has no way of knowing what the child table is.
What is the most efficent way to store a list in the Django models?
Therefore, unfortunately, it's not possible to go directly to the child model instance without additional queries..
Why does Django's signal handling use weak references for callbacks by default?
This snippet shows a common method of adding a ContentType field to the base model:.
How to build an Ecommerce Shopping Cart in Django?
You can then say
from django.contrib.contenttypes.models import ContentType class Base(models.Model): content_type = models.ForeignKey(ContentType,editable=False,null=True) def save(self): if(not self.content_type): self.content_type = ContentType.objects.get_for_model(self.__class__) self.save_base() def as_leaf_class(self): content_type = self.content_type model = content_type.model_class() if(model == Base): return self return model.objects.get(id=self.id)
if Base.content_type.model_class()to determine the type..
Where to put message queue consumer in Django?
Here is another snippet that adds a custom manager into the mix..
Django Model Inheritance And Foreign Keys
As you can see, both of these solutions have the potential to be extremely expensive.
If you have a large number of instances, using the as_leaf_class() method will require one query on each item.. Instead, if you have a known set of child models, simply query each model separately and aggregate the instances into one list..
model-utils requires Django 1.2 or higher..
from model_utils.managers import InheritanceManager class Base(models.Model): objects = InheritanceManager() # ...
Base.objects.all().select_subclasses() # returns instances of child classes
My problem was.
In a view, I had this principal model, lets say "Big_Model" and there were some "Small_Model" related to "Big_Model".
So when I wanted to retrieve all "Small_Model" related to a certain instance of "Big_Model" I did that **_set.all() stuff.
But the point is that Small_Model has Child Classes and I wanted, in views.py, to get which child class was each of the Small_Model instances related to.
My trick was to define boolean methods in model Small_Model like is_child_1() and is_child_2().
And when it is true, you apply the actual child pointer instead of the Small_Model pointer.. Ok...
Thats not clear enough, still I dont have much time to write a good example, so i'll just copy-paste my case here:.
class Cache(models.Model): valor = models.DecimalField(max_digits=9, decimal_places=2, blank= True, null= True) evento=models.ForeignKey(Evento) def __unicode__(self): return u'%s: %s' % (self.evento, self.valor) class Meta: verbose_name='Cachê' verbose_name_plural='Cachês' def is_cb(self): try: self.cache_bilheteria return True except self.DoesNotExist: return False def is_co(self): try: self.cache_outro return True except self.DoesNotExist: return False
from django.contrib.contenttypes.models import ContentType from django.db import models def ParentClass(models.Model): superclass = models.CharField(max_length = 255, blank = True) def save(self, *args, **kwargs): if not self.superclass: self.superclass = ContentType.objects.get_for_model(self.__class__) super(ParentClass, self).save(*args, **kwargs) def getChild(self): s = getattr(self, self.superclass) if hasattr(s, 'pk'): return s else: return None class Child1(ParentClass): pass class Child2(ParentClass): pass
(This is a reprint of an answer in a different context.
See C++ casting programmatically : can it be done ?). Read up on polymorphism.
Almost every "dynamic cast" situation is an example of polymorphism struggling to be implemented.. Whatever decision you're making in the dynamic cast has already been made.
Just delegate the real work to the subclasses.. You left out the most important part of your example.
The useful, polymorphic work.. When you said "I want to determine if the object is of type Child_1 or Child_2..." you left out the "so I can make the object do
aMethod()in a way that's unique to each subclass".
That method is the useful work, and it should simply be a method of both subclasses..
Same method, multiple implementations.
class Base(models.model): def aMethod(self): # base class implementation.
class Child_1(Base): def aMethod(self): # Child_1 override of base class behavior.
class Child_2(Base): def aMethod(self): supert( Child_2, self ).aMethod() # Invoke the base class version # Child_2 extension to base class behavior.
Never a need to "run-time type identification" or determining the concrete class..