在Django中动态调用存在的方法
我正在用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的源代码,你应该能完善这些内容并修正任何错误。