确定Django中外键的类别
我有以下型号:确定Django中外键的类别,django,Django,我有以下型号: class Vehicule(models.Model): brand = models.CharField() description = models.TextField() color = models.CharField() class Car(Vehicule): wheels = models.IntegerField(editable=False, default=4) class Boat(Vehi
class Vehicule(models.Model):
brand = models.CharField()
description = models.TextField()
color = models.CharField()
class Car(Vehicule):
wheels = models.IntegerField(editable=False, default=4)
class Boat(Vehicule):
length = models.IntegerField()
class Suprise(models.Model):
items = models.ForeignKey(Vehicule)
车辆
可以是抽象的
如果我创建了Car
的实例,我可以访问Car
的所有属性,也可以访问vehicleue
的属性。这就是继承的全部意义
但是,当我在惊喜
的实例中尝试确定项的类别时,出现了一个问题。即,如果s
是一个惊喜
,则以下代码:
for i in s.items.all():
if isinstance(i, Car):
print("It's a car !'")
else :
print("It's not a car !'")
将始终输出“它不是一辆车!”即使这实际上是一辆车。我发现确定项目类型的唯一方法是检查它们是否具有指向外部表中对象的car
属性(有关更多详细信息,请参阅官方文档),但这对我来说不够干净
这是确定Django中外键类别的唯一方法吗?根据Django文档:
如果您有一个同时也是餐厅的地方,您可以使用模型名称的小写版本从地点对象到餐厅对象:
p = Place.objects.get(id=12)
p.restaurant
除此之外:
但是,如果上面示例中的p不是餐厅(它是直接作为Place对象创建的,或者是其他类的父对象),引用p.Restaurant将引发Restaurant.DoesNotExist异常。
因此,您自己回答了这个问题,您需要检查car attr,因为这是指向您要查找的模型的内容,如果没有car attr,则对象不是由car类创建的。事实是,当您查询模型时(通过QuerySet方法,或间接通过ForeignKey)您得到的是非多态实例——与SQLAlchemy不同,SQLAlchemy得到的是多态实例
这是因为获取的数据只对应于您正在访问的数据(因为它们是预先知道的祖先数据)。默认情况下,Django不会执行任何类型的select_related
来获取子项,因此您只能使用外键或查询集的基本(即当前)类模型
这意味着:
Vehicle.objects.get(pk=1).__class__ == Vehicle
将永远是真实的,并且:
Surprise.objects.get(pk=1).items.all()[0].__class__ == Vehicle
也永远是真的
(假设这些示例中存在pk=1的车辆,存在pk=1的惊喜,并且至少有一个项目)
除了了解你的孩子的课程之外,没有干净的解决办法。正如您所说:访问.car或.truck之类的变量(考虑到存在car和truck类)是一种方法但是如果您点击了错误的子类(例如,当车辆
实际上应该是卡车
实例时,您点击了车辆.汽车
),您将得到一个ObjectDoesNotExist
错误免责声明:不知道如果在不同模块中有两个同名的子类,会发生什么情况
如果您想拥有多态性行为,它可以将您从测试每个可能的子类中抽象出来,那么存在一个应用程序(实际上没有使用它):作为另一种解决方法,我编写了这个函数,它可以用于相同的目的,而不需要django多态性
:
def is_model_instance(object, model):
'''
`object` is expected to be a subclass of models.Model
`model` should be a string containing the name of a models.Model subclass
Return true if `object` has a reference to a `model` instance, false otherwise.
'''
model_name = model.lower()
if model_name in dir(object):
try:
statement = "object." + model_name
exec(statement)
return True
except object.DoesNotExist:
return False
else :
return False
然后我可以很容易地做一些像
>>> is_model_instance(Surprise.objects.get(pk=1).items.all()[0], Car)
True # this is indeed a Car
谢谢,这个django多态性似乎正是我所需要的。