问题描述
我正在开发django应用程序,我有这样的模型结构
I'm developing django application, and I have such a model structure
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}}
。它输出动物,但是我创建了羊类型的对象,并希望使用不是动物的羊的 __ unicode __
方法。
And I pass animal_set to template and output every object like this {{ animal }}
. It outputs Animal, but I created objects of sheep type and want to use __unicode__
method of sheep not of animal.
Django模型中是否使用多态性?我已经找到了几个答案,但是有一些代码写在里面的模型,但我对本机解决方案感兴趣。
Do polymorphism work in Django models? I have found several answers, but there are snippets of code to write inside models, but I'm interested in native solutions.
推荐答案
在撰写本文时,Django最新版本为1.2
At the time of writing, Django latest version was 1.2
但是它需要一些额外的元素才能正常工作。
But it needs some additional elements to work.
您需要为每个动物模型分配一个自定义的models.Manager对象,该对象将调用其自己的自定义QuerySet对象。
You need to assign a custom models.Manager object for each animal model which will call its own custom QuerySet object.
基本上,而不是返回动物
实例(这是你得到的), SubclassingQuerySet
调用 as_leaf_class()
方法来检查项目的模型是否为 Animal
或者如果是,那么只需返回它,否则在模型上下文中执行搜索。这是这样的。
Basically, instead of returning Animal
instances (this is what you get), SubclassingQuerySet
calls as_leaf_class()
method to check if item's model is Animal
or not - if it is, then just return it, otherwise perform search in its model context. Thats it.
#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'
>>>
这篇关于Django模型中的多态性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!