2010-10-13 39 views
5

我对django中代理模型与其超类的关系仍有点困惑。我现在的问题是,如何从已获取的超类实例中获取代理模型的实例?使用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) 

有一个简单的方法来从动物的实例创建猫的实例我知道是一只猫?

回答

5

您正试图为继承层次结构实现持久性。使用一个混凝土表和一个type开关是一个很好的方法来做到这一点。但我认为你的实现,具体如下:

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

是违背Django粮食。开启类型不应与代理(或模型)类无关。

如果我是你,我会做到以下几点:

首先,添加一个“类型意识”经理代理模式。这将确保Dog.objects将始终提取Animal实例,type="dog"Cat.objects将使用type="cat"提取Animal实例。

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 
+0

我知道我正在反对Django的谷物。我这样做是因为Django不让我做我想做的事情,它获取存储在同一个表中但具有不同属性而不实际链接在一起的对象的列表。我构建了一个类型感知管理器,但是在超类级别,现在我只需要将返回的超类对象实例“转换”为代理类对象。有没有办法做到这一点? – 2010-10-13 05:56:07

+0

其实,我已经这样做了,但我目前正在回呼数据库,如下所示:animal_proxy = Cat.objects.get(id = animal.id)我需要类似animal_proxy =(Cat)动物的东西。我知道必须有可以为我做到这一点的蟒蛇技巧。 – 2010-10-13 06:01:37

+0

@Bubba:看到这个问题。你可能会感兴趣的答案。 http://stackoverflow.com/questions/2218867/right-way-to-return-proxy-model-instance-from-a-base-model-instance-in-django – 2010-10-13 06:09:07

2

我会做:

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 

我还没有与“动物园”测试它;),但我自己的模型似乎工作。