2010-10-13 13 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 

我還沒有與「動物園」測試它;),但我自己的模型似乎工作。