[英]Polymorphism in Django models
我正在开发django应用程序,我有这样的模型结构
class Animal(models.Model):
aul = models.ForeignKey(Aul)
age = models.IntegerField()
def __unicode__(self):
return u'Animal'
class Sheep(Animal):
wool = models.IntegerField()
def __unicode__(self):
return u'Sheep'
我将animal_set传递给模板并输出像{{ animal }}
这样的每个对象。 它输出Animal ,但我创建了羊类型的对象,并且想要使用羊的__unicode__
方法而不是动物。
多态在Django模型中有效吗? 我找到了几个答案,但是有一些代码片段可以在模型中编写,但我对本机解决方案很感兴趣。
在撰写本文时,Django最新版本为1.2
但它需要一些额外的元素才能工作。
您需要为每个动物模型分配一个自定义models.Manager对象,它将调用自己的自定义QuerySet对象。
基本上,不是返回Animal
实例(这是你得到的), SubclassingQuerySet
调用as_leaf_class()
方法来检查项目的模型是否为Animal
- 如果是,则返回它,否则在其模型上下文中执行搜索。 而已。
#models.py
from django.db import models
from django.contrib.contenttypes.models import ContentType
from django.db.models.query import QuerySet
class SubclassingQuerySet(QuerySet):
def __getitem__(self, k):
result = super(SubclassingQuerySet, self).__getitem__(k)
if isinstance(result, models.Model):
return result.as_leaf_class()
return result
def __iter__(self):
for item in super(SubclassingQuerySet, self).__iter__():
yield item.as_leaf_class()
class AnimalManager(models.Manager):
def get_query_set(self): # Use get_queryset for Django >= 1.6
return SubclassingQuerySet(self.model)
class Animal(models.Model):
name = models.CharField(max_length=100)
content_type = models.ForeignKey(ContentType, editable=False, null=True)
objects = AnimalManager()
def __unicode__(self):
return "Animal: %s" % (self.name)
def save(self, *args, **kwargs):
if not self.content_type:
self.content_type = ContentType.objects.get_for_model(self.__class__)
super(Animal, self).save(*args, **kwargs)
def as_leaf_class(self):
content_type = self.content_type
model = content_type.model_class()
if model == Animal:
return self
return model.objects.get(id=self.id)
class Sheep(Animal):
wool = models.IntegerField()
objects = AnimalManager()
def __unicode__(self):
return 'Sheep: %s' % (self.name)
测试:
>>> from animals.models import *
>>> Animal.objects.all()
[<Sheep: Sheep: White sheep>, <Animal: Animal: Dog>]
>>> s, d = Animal.objects.all()
>>> str(s)
'Sheep: White sheep'
>>> str(d)
'Animal: Dog'
>>>
您可能通过访问{{animal.sheep}}获得成功 - 模型继承不是您想象的,封面下有一个重型元类机制将这种继承“转换”为隐式的OneToOneField关系。
我建议使用Django代理模型,例如,如果您有基本模型Animal,它将由Sheep和Horse子类化,您将使用:
class Animal(models.Model):
pass
class Horse(Animal):
class Meta(Animal.Meta):
proxy = True
class Sheep(Animal):
class Meta(Animal.Meta):
proxy = True
这不是代理模型的目的 ,但我不建议使用Django多态,除非您需要在单独的表中存储模型特定数据的好处。 如果你有一百个特定的属性,都有默认值存储在数据库中,然后只有2个马对象,但有一百万只羊,你就有一百万行,每一行有一百匹特定的值,你不在乎但是,如果你没有足够的磁盘空间,这只是真正相关的,这是不太可能的。 当多态性运行良好时,它很好,但是当它不是时,它就是一种痛苦。
有一个非常简单的django应用程序,称为django-polymorphic模型 ,可以帮助你。 它将为您提供模型本身的downcast()
方法,它将返回您的“子”对象,以及一个特殊的查询集类来处理这些问题!
知道在基础模型的查询集上使用select_related()
也将获得通过OneToOneField
引用的子对象也是非常有用的,这有时可以提升性能!
你应该检查这个答案: https : //stackoverflow.com/a/929982/684253
它提出的解决方案类似于使用django-polymorphic模型,@ lazerscience已经提到过。 但是我会说django-model-utils比django-polymorphic有更好的文档记录,而且库更容易使用。 查看“继承管理器”下的自述文件: https : //github.com/carljm/django-model-utils/#readme
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.