问题 如何找到django模型基类的“具体类”
我正在尝试使用模型继承时找到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()
我想确定对象是否在basemethod中是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
但它感觉很脆弱,如果我继承更多级别,我不确定会发生什么。
9048
2017-12-08 11:11
起源
答案:
Django使用父模型表和子模型表之间的OneToOneField实现模型继承。当你这样做 Base.object.all()
,Django只查询Base表,因此无法知道子表是什么。因此,遗憾的是,如果没有其他查询,则无法直接转到子模型实例。
这个 片段 显示了将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()方法将需要对每个项目进行一次查询。
相反,如果您有一组已知的子模型,只需单独查询每个模型并将实例聚合到一个列表中。
13
2017-12-08 13:05
答案:
Django使用父模型表和子模型表之间的OneToOneField实现模型继承。当你这样做 Base.object.all()
,Django只查询Base表,因此无法知道子表是什么。因此,遗憾的是,如果没有其他查询,则无法直接转到子模型实例。
这个 片段 显示了将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()方法将需要对每个项目进行一次查询。
相反,如果您有一组已知的子模型,只需单独查询每个模型并将实例聚合到一个列表中。
13
2017-12-08 13:05
看看中的InheritanceManager Django的模型utils的 - 将它附加到模型为您提供具体的子类(至少在第一级):
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或更高版本。
5
2017-12-12 17:59
嗯......我的问题是。在一个视图中,我有这个主要模型,让我们说“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
0
2018-05-29 19:19
稍微修改过的版本 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
0
2017-07-03 08:56
它感觉很脆弱,因为它是。 (这是在不同背景下的答案的再版。 以编程方式查看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.
相同的方法,多个实现。从不需要“运行时类型识别”或确定具体类。
-2
2017-12-08 11:23