在渲染模板时是否有一种较低级别的方法来提供加载器列表,而不是始终让 Django 使用该设置?
我只想为几个视图使用自定义模板加载器实例(我有我的理由)。
在渲染模板时是否有一种较低级别的方法来提供加载器列表,而不是始终让 Django 使用该设置?
我只想为几个视图使用自定义模板加载器实例(我有我的理由)。
看起来你必须自己编写一些代码才能做到这一点。让我们看一下加载模板的正常代码路径,如果您使用,例如,源代码render_to_response
的相关部分是:
return HttpResponse(loader.render_to_string(*args, **kwargs), **httpresponse_kwargs)
这是对 的调用django.template.loader.render_to_string
,它通过其他一些函数并最终调用find_template
.
第一次find_template
调用,在初始化全局template_source_loaders
缓存的基础上settings.TEMPLATE_LOADERS
。所以看起来没有你可以传入的额外参数或类似的东西。
一种可能性可能是在django.template.loader.template_source_loaders
该视图的持续时间内添加一些加载器。我不知道这是否会导致其他问题;感觉很脏,但如果它有效,那就很容易了。(只需制作一个视图装饰器即可。)
如果您不想这样做,看起来您必须render_to_string
使用自己的代码复制工作(如果您真的确定要使用按视图模板加载器,我接受它作为这个问题的前提,但我敢打赌实际上没有必要)。那里没有那么多代码,如果您事先知道要使用的特定加载器和单个模板名称,那实际上很容易。(这未经测试,但可能几乎可以工作。)
def render_to_response_with_loader(loader, name,
dictionary=None, context_instance=None, mimetype=None, dirs=None):
# from find_template
t, display_name = loader(name, dirs)
# from get_template
if not hasattr(t, 'render'):
# template needs to be compiled
t = django.template.loader.get_template_from_string(t, origin, template_name)
# from render_to_string
if not context_instance:
rendered = t.render(Context(dictionary))
else:
# Add the dictionary to the context stack, ensuring it gets removed again
# to keep the context_instance in the same state it started in.
context_instance.update(dictionary)
try:
rendered = t.render(context_instance)
finally:
context_instance.pop()
# from render_to_response
return HttpResponse(rendered, mimetype=mimetype)
如果您想支持多个可能的加载器或可能的文件名列表,只需从django.template.loader复制相关代码。
我最终通过按照 Dougal 的建议修改 template_source_loaders 来做到这一点。就像他说的那样,我不确定这是否安全(它会产生竞争条件吗?),但它目前适用于我的特定情况。与 Dougal 建议的其他方式相比,这样做的好处是它确保 {% extends %} 和 {% include %} 也使用修改后的加载器。这是我的带有自定义加载器的 render_to_string:
def render_to_string_with_loader(*args, **kwargs):
""" Call render_to_string using ReportTemplateLoader to find templates. """
import django.template.loader as loader
old_loaders = settings.TEMPLATE_LOADERS
settings.TEMPLATE_LOADERS = ('main.loaders.ReportTemplateLoader',)
loader.template_source_loaders = None # force refresh from settings
try:
out = render_to_string(*args, **kwargs)
finally:
# use finally make sure template errors can't mess up later requests
settings.TEMPLATE_LOADERS = old_loaders
loader.template_source_loaders = None
这是一个老问题,但截至 2021 年(Django 3.2),这就是我所做的。
我需要什么:
(一些多域解决方案是关于创建一个不同的新实例DIRS
)
加入'django.contrib.sites'
进来INSTALLED_APPS
_settings.py
这启用了Django 站点框架
添加'django.contrib.sites.middleware.CurrentSiteMiddleware'
到MIDDLEWARES
您的settings.py
这site
为 Django 处理的每个请求添加了一个属性
在TEMPLATES
中settings.py
例如,我使用 Django 引擎。我再次创建了相同的引擎,并添加DIRS
了可以获取模板的位置。
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')]
,
'APP_DIRS': True,
},
{
'NAME': 'a.local',
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates/a.local'),
os.path.join(BASE_DIR, 'templates')]
,
'APP_DIRS': True,
},
{
'NAME': 'b.local',
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates/b.local'),
os.path.join(BASE_DIR, 'templates')]
,
'APP_DIRS': True,
}
]
using
kwargrender()
设置要使用的渲染引擎render()
前:
render(request, 'template.html', context=context_data)
后:render(request, 'template.html', context=context_data, using=request.site.domain)
(在我的情况下,request.site.domain
是a.local
or b.local
,这正是我刚刚创建的引擎的名称)
避免改变你所有的render
地方。这很恶心,你不应该这样做。移至基于分类的视图。这里是。
def render(request, *args, **kwargs):
return shortcut_render(request, *args, **kwargs, using=request.site.domain)