Django - 基于每个请求使用自定义模板加载器?

时间:2012-06-14 17:51:58

标签: django django-templates

渲染模板时是否有提供加载器列表的低级方法,而不是总是让Django使用该设置?

我想只为几个视图使用自定义模板加载器实例(我有我的理由)。

2 个答案:

答案 0 :(得分:3)

看起来你必须自己编写一些代码才能完成它。让我们来看看加载模板的常规代码路径,如果你使用render_to_response,那么the source的相关部分是:

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中的相关代码。

答案 1 :(得分:1)

我最后通过修改template_source_loaders来做这件事,正如Dougal建议的那样。就像他说的那样,我不确定这是否安全(可能会造成竞争条件吗?),但它现在适用于我的特殊情况。通过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