Django如何将字符串转换为模块?

rslzwgfq  于 2023-05-19  发布在  Go
关注(0)|答案(3)|浏览(118)

我在试图理解Django的另一个神奇之处:它可以将字符串转换为模块。
settings.py中,INSTALLED_APPS的声明如下:

INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
)

它包含的都是字符串。但是django会将这些字符串转换为模块,并在稍后导入它们。
我想做的是能够做同样的事情。但我不知道怎么做。我在www.example.com中有一个渲染器调度器的字典settings.py:

RESOUCE_RENDERER = {
    'video': 'video_player',
    'audio': 'audio_player', 
}

我想在以后使用它,就像这样:RESOURCE_RENDERER['video'](MyVideo)
我不能直接指定函数名(例如video_player),因为它位于需要settings.py的模块中。

p4tfgftt

p4tfgftt1#

从Django 1.7开始,有一个简单的函数来实现这一点。例如:

from django.utils.module_loading import import_string
my_module = import_string('path.to.my_module')

你也可以从模块中获取类:

MyClass = import_string('path.to.my_module.MyClass')
9vw9lbht

9vw9lbht2#

看一下django.conf.__init__.py,但基本上它使用importlib如下:

try:
    mod = importlib.import_module(self.SETTINGS_MODULE)
except ImportError, e:
    raise ImportError("Could not import settings '%s' 
               (Is it on sys.path? Does it have syntax errors?):
                %s" % (self.SETTINGS_MODULE, e))

# Settings that should be converted into tuples if they're mistakenly entered
# as strings.
tuple_settings = ("INSTALLED_APPS", "TEMPLATE_DIRS")

编辑:应OP的要求,我扩展了示例,并在下面贡献了更多内容。

现在,假设你在这个模块中有一个函数列表,在例如FUNCTIONS TO CALL中定义,一个函数列表。然后,您可以像这样调用每个:

ARGUMENTS = '()'

for FUNCTION in FUNCTIONS_TO_CALL:
    function_string = FUNCTION + ARGUMENTS
    exec(function_string)

这假设每个函数都有相同的定义参数集。您可以使用if语句来检测用户列出的函数名,并根据其内容提供自定义参数。您也可以通过阅读python文件来评估参数应该是什么。
您还可以在调用exec()eval()之前检查模块对象(我假设这是可能的,我不知道),看看该函数是否存在。我也不知道,是否可以从函数对象中计算出它的参数。我怀疑是这样,但这是一个单独的(可能已经回答了?)提问。

chhkpiq4

chhkpiq43#

您可以使用import_string()导入带有点线模块路径的模型,如文档所示:
导入点线模块路径并返回由路径中的姓氏指定的属性/类。如果导入失败,则引发ImportError。
例如,您在my_app/models.py中有Person模型,如下所示:

# "my_app/models.py"

class Person(models.Model):
    name = models.CharField(max_length=20)

然后,您可以在my_app/views.py中导入Person模型和import_string(),如下所示:

# "my_app/views.py"

from django.http import HttpResponse
from django.utils.module_loading import import_string

def test(request): # ↓ Imports "Person" model ↓
    Person = import_string('my_app.models.Person')
    print(Person.objects.all())
    return HttpResponse("Test")

上面的代码与下面的代码相同:

# "my_app/views.py"

from django.http import HttpResponse
from .models import Person # Imports "Person" model

def test(request):
    print(Person.objects.all())
    return HttpResponse("Test")

然后,控制台上的输出是相同的:

<QuerySet [<Person: Person object (1)>, <Person: Person object (2)>]>

相关问题