我仍然对代理模型与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实例,我知道它是一只猫?
答案 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; ;)但我自己的模型似乎工作。