Django:从字符串得到模型

Django: Get model from string?

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

1
author = ForeignKey('Person')

然后在内部,它必须将字符串"person"转换为模型Person

做这个的函数在哪里?我想用,但找不到。


As of Django 1.9 the method is django.apps.AppConfig.get_model(model_name).
-- danihp

As of Django 1.7 the django.db.models.loading is deprecated (to be removed in 1.9) in favor of the the new application loading system.
-- Scott Woodall

找到它了。定义如下:

1
from django.db.models.loading import get_model

定义为:

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


从Django 1.7开始,为了支持新的应用程序加载系统,不推荐使用django.db.models.loading(将在1.9中删除)。1.7文件提供了以下信息:

1
2
3
4
5
6
7
$ python manage.py shell
Python 2.7.6 (default, Mar  5 2014, 10:59:47)
>>> from django.apps import apps
>>> User = apps.get_model(app_label='auth', model_name='User')
>>> print User
<class 'django.contrib.auth.models.User'>
>>>

根据tttthomassss注释编辑。


对于任何一个被卡住的人(就像我一样):

1
2
3
from django.apps import apps

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

app_name应使用引号列出,model_name也应使用引号列出(即不要试图导入)。

get_model接受小写或大写的‘型号名称’


大多数模型"字符串"以"appname.modelname"的形式出现,因此您可能希望在get_模型上使用此变体。

1
2
3
from django.db.models.loading import get_model

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

django代码中通常将这些字符串转换为模型的部分比django/db/models/fields/related.py中的代码要复杂一些:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
    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"格式,那么上面的两个行程序就可以工作了。


在Django 1.7+中这样做的幸运方式是:

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

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

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

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

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

请记住,您的型号名称必须是小写。


我不知道在姜戈的什么地方,但你可以这样做。

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

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


下面是从字符串中获取类的一种不太特定于django的方法:

1
2
3
mymodels = ['ModelA', 'ModelB']
model_list = __import__('.models', fromlist=mymodels)
model_a = getattr(model_list, 'ModelA')

或者可以使用importlib,如下所示:

1
2
3
import importlib
myapp_models = importlib.import_module('.models')
model_a = getattr(myapp_models, 'ModelA')