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

查看:17
本文介绍了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 }} 一样输出每个对象.它输出 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

但它需要一些额外的元素才能工作.

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.

基本上,不是返回 Animal 实例(这是你得到的),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天全站免登陆