我试图围绕代理模型的工作原理。假设我有一个称为Animal的基类,并且我想实现两个子类:Dog和Cow。它们具有相同的数据要求,所以我真的不想创建两个单独的表。所以我正在尝试使用代理模型:
class Animal(models.Model):
name = models.CharField()
animal_type = models.CharField(choices=(('Dog','Dog'),('Cow','Cow')))
def get_sound(self):
if animal_type == 'Dog':
return self.dog.get_sound() #doesn't work
elif self.animal_type == 'Cow':
return self.cow.get_sound() #doesn't work
class Dog(Animal):
class Meta:
proxy=True
def get_sound(self):
return 'Woof'
class Cow(Animal):
class Meta:
proxy=True
def get_sound(self):
return 'Moo'
我的问题是,如何从父类访问子类方法?我的名字是self.dog.get_sound()
。在多表继承中这是可能的,但在代理模型中不起作用。
>>obj = Animal.objects.create(name='Max', animal_type='Dog')
>>obj.get_sound()
'Woof' <-- what I'd like it to return
代理模型是错误的方法吗?希望保留一张桌子。
答案 0 :(得分:0)
是的,那是行不通的。在幕后,Django为每个继承的模型创建了一个OneToOne外键,关于代理模型(docs的情况除外),您是对的。代理模型并非要以这种方式使用,它们的工作原理与原始模型完全相同,有时在原始表的子集(如您的示例),其他方法等中使用。如果您使用代理模型,则不需要根据需要使用原始表。
我为您提供一些建议:
class DogManager(Manager):
def get_queryset(self):
queryset = super().get_queryset()
return queryset.filter(kind='Dog') # Literal is not good
def create(self, **kwargs):
kwargs.update({'kind': 'Dog'})
return super().create(**kwargs)
class CowManager(Manager):
def get_queryset(self):
queryset = super().get_queryset()
return queryset.filter(kind='Cow') # Literal is not good
def create(self, **kwargs):
kwargs.update({'kind': 'Cow'})
return super().create(**kwargs)
class Animal(models.Model):
name = models.CharField()
# I've changed the name because I don't like variables with 'type' in the name
kind = models.CharField(choices=(('Dog','Dog'),('Cow','Cow')))
class Dog(Animal):
objects = DogManager()
class Meta:
proxy=True
def get_sound(self):
return 'Woof'
class Cow(Animal):
objects = CowManager()
class Meta:
proxy=True
def get_sound(self):
return 'Moo'
现在您无需调用Animal
类,因为在这两个代理模型proxy managers中有原始数据的子集。
instance = Dog.objects.create(name='Max')
instance.get_sound() # Woof
Dog.objects.all() # all animals with kind 'Dog'
Cow.objects.all() # all animals with kind 'Cow'
答案 1 :(得分:0)
给你:
class Animal(models.Model):
class Type(models.TextChoices):
Dog = ('dog', 'Dog')
Cow = ('cow', 'Cow')
name = models.CharField()
animal_type = models.CharField(choices=Type.choices)
def get_subclass_instance(self):
subclasses = {
self.Type.choices.Dog: Dog,
self.Type.choices.Cow: Cow,
}
instance = subclasses[self.type].objects.get(id=self.id)
return instance
def get_sound(self):
self.get_subclass_instance().get_sound()
class Dog(Animal):
class Meta:
proxy=True
def get_sound(self):
return 'Woof'
class Cow(Animal):
class Meta:
proxy=True
def get_sound(self):
return 'Moo'