确定Django中的外键类

时间:2014-08-14 14:32:46

标签: 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(Vehicule):
    length = models.IntegerField()

class Suprise(models.Model):
    items = models.ForeignKey(Vehicule)

Vehicule可能是抽象的。

如果我创建了Car的实例,我可以访问Car的所有属性,还可以访问Vehicule的属性。这是继承的全部要点。

但是,当我尝试在items的实例中确定Surprise的类时,会出现问题。即,如果sSurprise,则代码如下:

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中确定外键类的唯一方法吗?

3 个答案:

答案 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