How do I find the “concrete class” of a django model baseclass


How do I find the “concrete class” of a django model baseclass



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

1:



Separation of ORM and validation
Django implements model inheritance with a OneToOneField between the parent model's table and the child model's table.


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?
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) 
You can then say 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..


2:


Have a look at InheritanceManager in django-model-utils – attaching it to a model gives you the concrete child classes (at least at the first level):.
from model_utils.managers import InheritanceManager  class Base(models.Model):     objects = InheritanceManager()  # ... 

Base.objects.all().select_subclasses() # returns instances of child classes
model-utils requires Django 1.2 or higher..


3:


Well...

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 


4:


Slightly modified version of what Daniel Naab proposed:.
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 


5:


It feels brittle because it is.

(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..
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.

Same method, multiple implementations.

Never a need to "run-time type identification" or determining the concrete class..



82 out of 100 based on 72 user ratings 622 reviews

*