Django:从该模型的实例中获取模型的最佳实践方法

82

假设my_instance是模型MyModel的一个实例。
我正在寻找一种好的方法来做:

my_model = get_model_for_instance(my_instance)

我还没有找到任何直接的方法来做到这一点。 目前,我想到了这个:

from django.db.models import get_model

my_model = get_model(my_instance._meta.app_label, my_instance.__class__.__name__)
这样做可以吗?这是最佳实践吗?
还有一个 _meta.object_name ,它似乎提供了与 __class__.__name__ 相同的内容。 它是更好还是更差? 如果是,为什么?
此外,如果在项目范围内多次出现应用标签(例如来自'django.contrib.auth'的'auth'和'myproject.auth'),那么我如何知道我获取的是正确的模型?
在这种情况下,get_model 可能不可靠吗?
感谢任何提示、指针和经验分享!

3
__class__ 必须完全是实例所属的类,这一点没有任何可能的歧义。这是 Python 的工作原理。你在问什么? - S.Lott
嗯,我在这里有一些理解上的限制。 对我来说,模糊不清的是可能存在多个应用标签/类名组合,它们位于不同的模块中。然而,get_model没有接收模块作为输入。那么它会提供哪个模型呢? 另一件事是我不明白object_name有什么用处,因为它返回与__class__.__name__相同的字符串,而且有多少人选择在get_model或其他地方使用这两者中的哪一个。 - Geradeausanwalt
3个回答

128
my_model = type(my_instance)

为了证明它,您可以创建另一个实例:

my_new_instance = type(my_instance)()

这就是为什么没有直接的方法来实现它,因为Python对象已经具有此功能。
更新...
我喜欢marcinn的回答,使用type(x)。这与原始答案使用的相同(x.__class__),但我更喜欢使用函数而不是访问魔术属性。以这种方式,我更喜欢使用vars(x)而不是x.__dict__len(x)而不是x.__len__等。
更新2...
对于延迟实例(在评论中提到的@Cerin),您可以通过instance._meta.proxy_for_model访问原始类。

3
这无法与延迟加载实例或使用 only() 查询的实例一起使用。 - Cerin
非常感谢您提供的“更新2”。我花了很长时间才找到如何访问原始类。 - andreibosco

25
my_new_instance = type(my_instance)()

19

至少对于Django 1.11,这应该可以工作(对于延迟实例也是如此):

def get_model_for_instance(instance):
    return instance._meta.model

在这里查看源代码


3
虽然这个方法可行,而且我之前不幸地用过它,但是就“最佳实践”而言,_meta.model 不在 _meta API中,不应该使用,type() 更好、更符合 Python 风格。 - Andy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接