Django class subclass: get a subclass by requesting a superclass

The following code is specified:

class BaseMedium(models.Model): title = models.CharField(max_length=40) slug = models.SlugField() class A(BaseMedium): url = models.URLField() class B(BaseMedium): email = models.EmailField() 

Now I want to request each BaseMedium.

 b = BaseMedium.objects.all() 

How to print each information, including subclass fields, without knowing what type of subclass?

b[0].a will print information if b[0] is actually associated with instance A , but if it is associated with B , it will print DoesNotExist Exception.

This makes sense, but I would like to have a shared variable or method that returns a related object.

Perhaps my database layout is not very good to request this path, if I were happy if you would recommend a better layout.

I was thinking about using GenericForeignKey

 class Generic(models.Model): basemedium = models.ForeignKey('BaseMedium') content_type = models.ForeignKey(ContentType) object_id = models.PositiveIntegerField() object = generic.GenericForeignKey('content_type', 'object_id') 

but this decision seems complicated, and I think you guys have better solutions.

+7
python django django-models
source share
3 answers

You should check out the solution posted by Carl Meyer some time ago. It internally uses the ContentType approach, but it encapsulates it very elegantly.

He also points to an alternative and more efficient solution that does not require storing an additional field in the database, but it will only work for direct child classes. If you have multiple levels of inheritance, the first solution is better.

+3
source share

The only way to do this is to explicitly store which type on the base model. So, BaseMedium has a derived_type field (or something else) and set it to save. Then you can use the get_derived_type method:

 def get_derived_type(self): if self.derived_type == 'A': return self.a elif self.derived_type == 'B': return self.b 

etc.

+2
source share

Thanks. Roseman for your reply. I developed your idea a little further. Here is what I came up with:

 def related_object(self, default_pointer_name='_ptr'): models = [A,B] #models object = None argument = '%s%s' %(self.__class__.__name__.lower(), default_pointer_name) query = { argument : self} for model in models: try: object = model.objects.get(**query) except model.DoesNotExist: pass else: return object if object == None: raise RelatedObjectException return object 

This is the method used by BaseMedium.

+1
source share

All Articles