代码之家  ›  专栏  ›  技术社区  ›  Mr Shark

如何找到django模型基类的“具体类”

  •  11
  • Mr Shark  · 技术社区  · 17 年前

    在使用模型继承时,我试图找到django模型对象的实际类。

    class Base(models.model):
        def basemethod(self):
            ...
    
    class Child_1(Base):
        pass
    
    class Child_2(Base):
        pass
    

    Child_1().save()
    Child_2().save()
    (o1, o2) = Base.objects.all()
    

    我想出了以下代码:

    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
    

    5 回复  |  直到 17 年前
        1
  •  14
  •   Daniel Naab    11 年前

    Django使用父模型的表和子模型的表之间的OneToOneField实现模型继承。当你这样做的时候 Base.object.all() ,Django只查询基表,因此无法知道子表是什么。因此,不幸的是,如果没有额外的查询,就不可能直接转到子模型实例。

    snippet

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

    Here 是将自定义管理器添加到混合中的另一个代码段。

    相反,如果您有一组已知的子模型,只需分别查询每个模型并将实例聚合到一个列表中。

        2
  •  5
  •   Jan Pöschko    14 年前

    django-model-utils 将其附加到模型将为您提供具体的子类(至少在第一级):

    from model_utils.managers import InheritanceManager
    
    class Base(models.Model):
        objects = InheritanceManager()
    
    # ...
    
    Base.objects.all().select_subclasses() # returns instances of child classes
    

        3
  •  0
  •   Dhiana Deva    16 年前

    好啊这还不够清楚,但我没有太多时间来写一个好的例子,所以我将复制粘贴我的案例:

    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
  •  0
  •   Community Mohan Dere    9 年前

    略加修改的版本 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
  •  -2
  •   Community Mohan Dere    9 年前

    它感觉脆,因为它是。(这是在不同背景下对答案的重印。 See C++ casting programmatically : can it be done ? )

    阅读多态性。几乎每个“动态强制转换”情况都是难以实现的多态性的一个例子。

    你遗漏了例子中最重要的部分。有用的、多态的工作。

    当您说“我想确定对象的类型是Child_1还是Child_2…”时,您省略了“因此我可以让对象执行此操作” aMethod()

    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.
    

    相同的方法,多个实现。不需要“运行时类型标识”或确定具体类。