Django model subclassing: Get the subclass by querying the superclass

后端 未结 4 1611
渐次进展
渐次进展 2020-12-16 23:01

The following code is given:

class BaseMedium(models.Model):
    title = models.CharField(max_length=40)
    slug = models.SlugField()

class A(BaseMedium):
         


        
相关标签:
4条回答
  • 2020-12-16 23:24

    You should check 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 doesn't need to store an aditional field on the database, but it will only work for direct child classes. If you have several inheritance levels, the first solution is better.

    0 讨论(0)
  • 2020-12-16 23:24

    This worked for me (using self.subclass_name_in_lower_case): In this example subclasses are TextTreeItem, CategoryTreeItem and KeywordTreeItem.

    class TreeItem(MPTTModel):
        parent = TreeForeignKey('self', on_delete=models.CASCADE, verbose_name=_('Parent'),
                                null=True, blank=True, related_name='%(class)s_related')
    
        objects = CustomTreeManager()
    
        @property
        def daughter(self):
            try:
                return self.texttreeitem
            except TreeItem.texttreeitem.RelatedObjectDoesNotExist:
                pass
    
            try:
                return self.categorytreeitem
            except TreeItem.categorytreeitem.RelatedObjectDoesNotExist:
                pass
    
            try:
                return self.keywordtreeitem
            except TreeItem.keywordtreeitem.RelatedObjectDoesNotExist:
                return self
    
    0 讨论(0)
  • 2020-12-16 23:35

    The only way to do this is to explicitly store on the base model what type it is. So have a derived_type (or whatever) field on BaseMedium, and set it on save. Then you can have a 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
    

    and so on.

    0 讨论(0)
  • 2020-12-16 23:43

    Thanks mr. Roseman for your reply. I developed your idea a bit 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 a method used by BaseMedium.

    0 讨论(0)
提交回复
热议问题