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

更新时间:2024-02-09 下载TXT文档 下载Word文档

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

一些代码来描述问题:

class Base(models.model):
    def basemethod(self):
        ...

class Child_1(Base):
    pass

class Child_2(Base):
    pass

如果我创建两个Child类的各种对象,并创建一个包含所有对象的查询集:

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

我想确定对象在基本方法中是类型为Child_1还是Child_2,我可以通过o1.child_1和o2.child_2到达子对象,但这可以重新获得有关基类中子类的知识。

我想出了以下代码:

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

但这感觉很脆弱,我不确定如果继承更多级别会发生什么。

Django通过父模型表与子模型表之间的OneToOneField实现模型继承。当您执行Base.object.all()时,Django仅查询基本表,因此无法知道子表是什么。因此,不幸的是,没有其他查询就不可能直接进入子模型实例。

此代码段显示了将ContentType字段添加到基本模型的常用方法:

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()以确定类型。

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

如您所见,这两种解决方案都可能非常昂贵。如果您有大量实例,则使用as_leaf_class()方法将需要对每个项目进行一次查询。 短码网-DuanMa.NET

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

  • 我不知道是否是因为我在django 1.4上安装了Im,但这在我使用if (not self.content_type_id)而不是self.content_type之前不起作用。显然Django正在尝试加载self.content_type,因此导致DoesNotExist
  • AFAIK这正是此程序包的功能:django-polymorphic.readthedocs.org/en/latest即使您使用BaseClass.objects.filter(),它也会返回具体的子类。
  • 如何保证子id与父id相匹配?

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

from model_utils.managers import InheritanceManager

class Base(models.Model):
    objects = InheritanceManager()

# ...

Base.objects.all().select_subclasses() # returns instances of child classes

model-utils需要Django 1.2或更高版本。

Daniel Naab提出的内容的略微修改版本:

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

好吧...我的问题是。在一个视图中,我有这个主要模型,可以说" Big_Model",并且有一些与" Big_Model"相关的" Small_Model"。因此,当我想检索与" Big_Model"的某个实例相关的所有" Small_Model"时,我做了** _ set.all()东西。但关键是Small_Model具有子类,我想在views.py中获取与每个Small_Model实例相关的子类。我的窍门是在模型Small_Model中定义is_child_1()和is_child_2()之类的布尔方法。并且当它为true时,您将应用实际的子指针而不是Small_Model指针。

好的...还不够清楚,我仍然没有太多时间写一个很好的例子,所以我只在这里复制粘贴我的案子:

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

因为它确实很脆。 (这是在不同上下文中的答案的重印。请参见以编程方式进行C ++强制转换:可以做到吗?)

阅读多态性。几乎每种"动态转换"情况都是要实现的多态性示例。

您在动态转换中做出的任何决定都已经做出。只需将实际工作委托给子类。

您忽略了示例中最重要的部分。有用的多态工作。

当您说"我想确定对象的类型为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.

相同的方法,多种实现。无需"运行时类型标识"或确定具体类。

  • 但是他没有引用Child模型实例。 Base.objects管理器仅返回Base的实例。
  • @Daniel:通常我们处理Child_1.objects.all()和Child_2.objects.all();几乎没有要求将两个子类型合并。
  • 通常,但这不是问题。
  • @Daniel:这是一个非常常见的n00b问题,表明无法利用多态性。消除问题的设计更改可能是更有用的答案。
  • 此行为与问题所提出的完全相反。

以上就是短码网小编为大家整理的《python 如何找到django模型基类的“具体类”》相关内容,希望大家喜欢。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。

如若内容造成侵权/违法违规/事实不符,请将联系本站反馈,一经查实,立即处理!

python 如何找到django模型基类的“具体类”》文档下载仅供参考学习,下载后请在24小时内删除。

转载注明出处:https://www.duanma.net/article/c39fea4a819.html

回到顶部