如何获取Django模型的子类对象
假设我有一个这样的 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 个回答
对于那些稍晚于问题发布和接受答案时来查看这个答案的人来说,在更新版本的Django中,这个功能可以更直接地实现,具体可以参考:Django关于多表继承的文档
举个例子,想象一下地方和餐馆。基本对象是一个地方,而子类是餐馆。你可以通过place.restaurant来获取子类,如果这个地方不是餐馆,它会抛出一个异常,你可以捕捉到这个异常。我提到这个是因为被接受的答案可能有点过时,导致我走了错误的方向。
我怎么能在不知道对象所属类的情况下,获取到子类对象呢?
这有什么用呢?如果你不知道想要哪个类,那你也不知道该调用哪些方法或者可以查看哪些属性。
这个想法是加载一个对应的视图,让它来处理事情。我的项目中,这些模型只有一小部分默认的操作,比如查看、编辑、删除等等。我不想通过网址暴露出给定对象的类型,所以“正常的方式”就不适用了。
如果你提前知道了一组模型的子类,或者愿意把它们注册到一个中央视图列表中,你可以这样做:
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')
没有现成的方法可以做到这一点。
也许最好的办法是在你的基类中定义一个 derived_type
字段,这个字段会在派生类保存时自动设置。然后你可以在基类中添加一个 get_derived
方法,这个方法会检查 derived_type
的值,并返回实际的派生对象。