Django模型中的多态性 [英] Polymorphism in Django models

查看:146
本文介绍了Django模型中的多态性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发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模型中的多态性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆