在Django中动态调用存在的方法

1 投票
2 回答
1978 浏览
提问于 2025-04-16 12:37

我正在用Django创建一个网站(我知道Django是用纯Python写的,所以懂Python的人也许可以帮忙),我需要动态调用一些方法。

举个例子,我的网站里有几个应用(模块),它们的views.py里都有一个叫“do_search()”的方法。然后我有一个叫“search”的模块,我想在这里实现一个功能,可以调用其他应用里的所有“do_search()”方法。当然,我不想一个个地把每个应用都导入,然后直接调用。我需要一种更好的方法来动态实现这个。

我可以从设置中读取INSTALLED_APPS变量,然后遍历所有已安装的应用,寻找特定的方法吗?如果能给我一段代码示例,那就太好了 :)

提前谢谢你们!

Ignas

2 个回答

1

如果你可以通过

import other_app

导入其他应用程序,那么应该可以执行

 method = getattr(other_app, 'do_' + method_name)
    result = method()

不过你这种做法是值得怀疑的。

3

我不太确定我是否真的理解这个问题,如果我理解错了,请在我的回答下留言澄清一下。

# search.py
searchables = []

def search(search_string):
    return [s.do_search(search_string) for s in searchables]

def register_search_engine(searchable):
    if hasattr(searchable, 'do_search'):
        # you want to see if this is callable also
        searchables.append(searchable)
    else:
        # raise some error perhaps


# views.py
def do_search(search_string):
    # search somehow, and return result

# models.py

# you need to ensure this method runs before any attempt at searching can begin
# like in models.py if this app is within installed_apps. the reason being that
# this module may not have been imported before the call to search.
import search
from views import do_search
search.register_search_engine(do_search)

关于在哪里注册你的搜索引擎,django的信号文档里有一些有用的说明。

你可以把信号处理和注册的代码放在任何地方。不过,你需要确保这个模块在早期就被导入,这样信号处理才能在需要发送信号之前注册好。因此,把这些注册代码放在你的应用的 models.py 文件里是个不错的选择。

所以你的 models.py 文件应该是注册搜索引擎的好地方。

我刚想到的另一种答案:

在你的 settings.py 文件里,你可以设置一个声明所有搜索功能的选项。像这样:

# settings.py
SEARCH_ENGINES = ('app1.views.do_search', 'app2.views.do_search')

# search.py
from django.conf import settings
from django.utils import importlib

def search(search_string):
    search_results = []
    for engine in settings.SEARCH_ENGINES
       i = engine.rfind('.')
       module, attr = engine[:i], engine[i+1:]
       mod = importlib.import_module(module)
       do_search = getattr(mod, attr)
       search_results.append(do_search(search_string))
    return search_results

这和注册 MIDDLEWARE_CLASSES 和 TEMPLATE_CONTEXT_PROCESSORS 有点类似。上面的代码都是未经测试的,但如果你查看一下django的源代码,你应该能完善这些内容并修正任何错误。

撰写回答