我有以下型号:
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)
Vehicule
可能是抽象的。
如果我创建了Car
的实例,我可以访问Car
的所有属性,还可以访问Vehicule
的属性。这是继承的全部要点。
但是,当我尝试在items
的实例中确定Surprise
的类时,会出现问题。即,如果s
是Surprise
,则代码如下:
for i in s.items.all():
if isinstance(i, Car):
print("It's a car !'")
else :
print("It's not a car !'")
总是输出"它不一辆车!"即使这实际上是Car
。我发现确定items
类型的唯一方法是检查它们是否具有指向外表中对象的car
属性(有关更多信息,请参阅有关multi-table inheritance的官方文档)细节)但对我来说不够干净。
这是在Django中确定外键类的唯一方法吗?
答案 0 :(得分:1)
事实是,当您查询模型时(通过QuerySet方法,或通过ForeignKey间接),您将获得非多态实例 - 与SQLAlchemy相比,您将获得多态实例。< / p>
这是因为获取的数据仅对应于您正在访问的数据(以及它的祖先,因为它们事先是已知的)。默认情况下,Django不会执行任何类型的select_related
来获取子项,因此您仍然坚持使用外键或查询集的基类(即当前)类模型。
这意味着:
Vehicle.objects.get(pk=1).__class__ == Vehicle
将始终为True,并且:
Surprise.objects.get(pk=1).items.all()[0].__class__ == Vehicle
也将始终为True。
(假设对于这些示例,存在pk = 1的车辆,pk = 1存在意外,并且至少有一个项目)
通过了解您的孩子课程,除此之外没有干净的解决方案。如你所说:访问变量,如.car或.truck(考虑Car和Truck类存在)就是这样。 然而如果你选错了儿童课程(例如你vehicle.car
应该vehicle
,实际上是Truck
实例),你会得到{{1}错误。 免责声明:如果您在不同模块中有两个同名的子课程,请不要知道会发生什么。
如果你想拥有多态行为,这可能会使你从测试每个可能的子类中抽象出来,那么应用程序就存在了(实际上并没有使用它):https://django-polymorphic.readthedocs.org/en/latest/
答案 1 :(得分:0)
根据Django文档:
If you have a Place that is also a Restaurant, you can get from the Place object to the Restaurant object by using the lower-case version of the model name:
p = Place.objects.get(id=12)
p.restaurant
除此之外:
但是,如果上例中的p不是Restaurant(它已直接创建为Place对象或是其他类的父对象),则引用p.restaurant会引发一个Restaurant.DoesNotExist异常强>
所以你自己回答了这个问题,你需要检查汽车attr,因为这是指向你正在寻找的模型,如果没有汽车attr那么该对象不是由Car类创建的
答案 2 :(得分:0)
作为另一种解决方法,我编写了这个函数,可以用于相同的目的,而不需要django-polymorphic
:
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