使用django,我如何从超类对象实例构造代理对象实例?

时间:2010-10-13 05:03:34

标签: python django django-models

我仍然对代理模型与django中的超类之间的关系感到困惑。我现在的问题是如何从已经检索到的超类实例中获取代理模型的实例?

所以,让我说我有:

class Animal(models.Model):
   type = models.CharField(max_length=20)
   name = models.CharField(max_length=40)

class Dog(Animal):  
   class Meta:
       proxy = True

   def make_noise(self):  
       print "Woof Woof"  

Class Cat(Animal):  
   class Meta:
       proxy = True

   def make_noise(self):  
       print "Meow Meow"

animals = Animal.objects.all()
for animal in animals:
   if (animal.type == "cat"):
      animal_proxy = # make me a cat
   elif (animal.type == "dog"):
      animal_proxy = # make me a dog
   animal_proxy.make_noise()

行。那么......“让我成为一只猫”的内容不需要回溯到数据库,例如:

animal_proxy = Cat.objects.get(id=animal.id)

是否有一种简单的方法可以从动物实例中创建一个Cat实例,我知道它是一只猫?

2 个答案:

答案 0 :(得分:5)

您正在尝试为继承层次结构实现持久性。使用一个具体的表和type开关是一个很好的方法。但是我认为你的实现,特别是:

for animal in animals:
   if (animal.type == "cat"): 
      animal_proxy = # make me a cat

违背了Django的内容。开启类型不应该与代理(或模型)类无关。

如果我是你,我会做以下事情:

首先,在代理模型中添加“类型感知”管理器。这将确保Dog.objects始终使用Animal获取type="dog"个实例,Cat.objects将使用Animal获取type="cat"个实例。

class TypeAwareManager(models.Manager):
    def __init__(self, type, *args, **kwargs):
        super(TypeAwareManager, self).__init__(*args, **kwargs)
        self.type = type

    def get_query_set(self):
        return super(TypeAwareManager, self).get_query_set().filter(
              type = self.type)

class Dog(Animal):
    objects = TypeAwareManager('dog')
    ...

class Cat(Animal):
    objects = TypeAwareManager('cat')
    ...

其次,分别获取子类实例。然后,您可以在操作之前将它们组合在一起。我使用itertools.chain来合并两个Querysets

from itertools import chain
q1 = Cat.objects.all() # [<Cat: Daisy [cat]>]

q2 = Dog.objects.all() # [<Dog: Bruno [dog]>]

for each in chain(q1, q2): 
    each.make_noise() 

# Meow Meow
# Woof Woof

答案 1 :(得分:3)

我愿意:

def reklass_model(model_instance, model_subklass):

    fields = model_instance._meta.get_all_field_names()
    kwargs = {}
    for field_name in fields:
        try:
           kwargs[field_name] = getattr(model_instance, field_name)
        except ValueError as e: 
           #needed for ManyToManyField for not already saved instances
           pass

    return model_subklass(**kwargs)

animals = Animal.objects.all()
for animal in animals:
   if (animal.type == "cat"):
      animal_proxy = reklass_model(animal, Cat)
   elif (animal.type == "dog"):
      animal_proxy = reklass_model(animal, Cat)
   animal_proxy.make_noise()

# Meow Meow
# Woof Woof

我没有用&#34;动物园&#34; ;)但我自己的模型似乎工作。