Django:从字符串中获取模型?


133

在Django中,您可以指定如下关系:

author = ForeignKey('Person')

然后在内部必须将字符串“ Person”转换为模型Person

该功能在哪里?我想使用它,但是找不到。

Answers:


167

从Django 3.0开始, AppConfig.get_model(model_name, require_ready=True)

从Django 1.9开始,方法为django.apps.AppConfig.get_model(model_name)
- 丹尼普

从Django 1.7开始,django.db.models.loading不推荐使用(将在1.9中删除),以支持新的应用程序加载系统。
- 斯科特·伍德Scott Woodall)


找到了。它在这里定义:

from django.db.models.loading import get_model

定义为:

def get_model(self, app_label, model_name, seed_cache=True):

11
此解决方案在Django 1.7中已弃用,请参见此解决方案的其他答案:stackoverflow.com/a/26126935/155987
Tim Saylor 2015年

4
嗨@mpen,我建议您更新答案。在django 1.9上,在AppConfig上定义了get_modelfrom django.apps import AppConfig
dani herrera,

1
django.apps.AppConfig是无法像模型对象一样工作的生成器类型。
Neeraj Kumar

2
在Django 1.7+中,最好在Django应用程序注册表上使用get_model(),可通过访问django.apps.apps.get_model(model_name)。AppConfig对象旨在用于其他用途,并且需要您创建AppConfig实例才能调用get_model()
zlovelady

2
Django 1.11需要@luke_aus提供的答案
Georg Zimmer

132

django.db.models.loading在Django 1.7已弃用在1.9删除),以支持新的应用程序加载系统

Django 1.7文档为我们提供了以下内容:

>>> from django.apps import apps
>>> User = apps.get_model(app_label='auth', model_name='User')
>>> print(User)
<class 'django.contrib.auth.models.User'>

我曾经使用pydoc的“定位”功能...不确定此处的区别,但是为了保留在Django中,我已切换到此方法。谢谢。
warath-coder

61

仅适用于任何陷入困境的人(就像我一样):

from django.apps import apps

model = apps.get_model('app_name', 'model_name')

app_name应该使用引号列出,也应该这样model_name(即不要尝试将其导入)

get_model 接受小写或大写的'model_name'


32

大多数模型“字符串”以“ appname.modelname”形式出现,因此您可能要在get_model上使用此变体

from django.db.models.loading import get_model

your_model = get_model ( *your_string.split('.',1) )

Django的代码,通常变成这样的字符串转换为模型的部分是一个稍微复杂一些这种由django/db/models/fields/related.py

    try:
        app_label, model_name = relation.split(".")
    except ValueError:
        # If we can't split, assume a model in current app
        app_label = cls._meta.app_label
        model_name = relation
    except AttributeError:
        # If it doesn't have a split it's actually a model class
        app_label = relation._meta.app_label
        model_name = relation._meta.object_name

# Try to look up the related model, and if it's already loaded resolve the
# string right away. If get_model returns None, it means that the related
# model isn't loaded yet, so we need to pend the relation until the class
# is prepared.
model = get_model(app_label, model_name,
                  seed_cache=False, only_installed=False)

对我而言,这似乎是将其拆分为核心代码中的单个函数的一个好案例。但是,如果您知道字符串为“ App.Model”格式,则上面的两个衬里将起作用。


3
我认为第二行应该是:your_model = get_model(*your_string.rsplit('.', 1))。应用标签有时为点分格式,但是型号名称始终是有效的标识符。
Rockallite 2014年

1
看起来新版本中没有必要这样做apps.get_model。“作为快捷方式,此方法还接受形式为的单个参数app_label.model_name。”
瑞恩·埃弗里特

16

在Django 1.7+中实现此目的的一种好方法是:

import django
model_cls = django.apps.apps.get_model('app_name', 'model_name')

因此,在所有框架教程的规范示例中:

import django
entry_cls = django.apps.apps.get_model('blog', 'entry')  # Case insensitive

9

如果您不知道模型存在于哪个应用程序中,可以通过以下方式进行搜索:

from django.contrib.contenttypes.models import ContentType 
ct = ContentType.objects.get(model='your_model_name') 
model = ct.model_class()

请记住,your_model_name必须为小写。


4

我不确定它在Django中完成了什么,但是您可以这样做。

通过反射将类名映射到字符串。

classes = [Person,Child,Parent]
def find_class(name):
 for clls in classes:
  if clls.__class__.__name__ == name:
   return clls

1
是clls .__ class __.__ name__还是clls .__ name__?
Vinayak Kaniyarakkal,2017年

4

另一种翻译形式,懒惰代码更少。在Django 2+中测试

from django.apps import apps
model = apps.get_model("appname.ModelName") # e.g "accounts.User"

1

这是从字符串中获取类的一种不太Django的方法:

mymodels = ['ModelA', 'ModelB']
model_list = __import__('<appname>.models', fromlist=mymodels)
model_a = getattr(model_list, 'ModelA')

或者你可以使用导入库如图所示在这里

import importlib
myapp_models = importlib.import_module('<appname>.models')
model_a = getattr(myapp_models, 'ModelA')

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.