如何获取Django模型的子类对象

2 投票
4 回答
950 浏览
提问于 2025-04-15 11:35

假设我有一个这样的 Django 模型类:

class BaseClass(models.Model):
     some_field = models.CharField(max_length = 80)
     ...

还有它的一些子类,比如说:

class SomeClass(BaseClass):
     other_field =  models.CharField(max_length = 80)

那么我知道可以通过调用

base  = BaseClass.objects.get(pk=3)
my_obj= base.someclass

来获取派生的对象。

现在的问题是,我有多个子类,而我手里只有一个基类的实例。那我该怎么在不知道具体子类的情况下,获取到这个子类的对象呢?


这个想法是加载一个对应的视图,让它来处理这些事情。我的项目中,这些模型的功能动作是有限的,比如查看、编辑、删除等等。我不想通过 URL 把对象的类型暴露出去,所以“正常的方法”就不适用了。

4 个回答

2

对于那些稍晚于问题发布和接受答案时来查看这个答案的人来说,在更新版本的Django中,这个功能可以更直接地实现,具体可以参考:Django关于多表继承的文档

举个例子,想象一下地方和餐馆。基本对象是一个地方,而子类是餐馆。你可以通过place.restaurant来获取子类,如果这个地方不是餐馆,它会抛出一个异常,你可以捕捉到这个异常。我提到这个是因为被接受的答案可能有点过时,导致我走了错误的方向。

2

我怎么能在不知道对象所属类的情况下,获取到子类对象呢?

这有什么用呢?如果你不知道想要哪个类,那你也不知道该调用哪些方法或者可以查看哪些属性。


这个想法是加载一个对应的视图,让它来处理事情。我的项目中,这些模型只有一小部分默认的操作,比如查看、编辑、删除等等。我不想通过网址暴露出给定对象的类型,所以“正常的方式”就不适用了。

如果你提前知道了一组模型的子类,或者愿意把它们注册到一个中央视图列表中,你可以这样做:

VIEWS = [('subclass_a', a_views), ('subclass_b', b_views)]

def edit(request):
    base = (get base somehow)

    for attrname, views in VIEWS:
        if getattr(base, attrname) is not None:
            return views['edit']

根据你有多少种不同的视图,你可能会把搜索的过程抽象成一个单独的函数,这样最终的视图就像是:

def edit(request):
    return generic_base_view(request, 'edit')
3

没有现成的方法可以做到这一点。

也许最好的办法是在你的基类中定义一个 derived_type 字段,这个字段会在派生类保存时自动设置。然后你可以在基类中添加一个 get_derived 方法,这个方法会检查 derived_type 的值,并返回实际的派生对象。

撰写回答