2

在渲染模板时是否有一种较低级别的方法来提供加载器列表,而不是始终让 Django 使用该设置?

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

4

3 回答 3

3

看起来你必须自己编写一些代码才能做到这一点。让我们看一下加载模板的正常代码路径,如果您使用,例如,源代码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复制相关代码。

于 2012-06-14T18:14:53.093 回答
1

我最终通过按照 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
于 2013-03-11T02:49:39.133 回答
0

这是一个老问题,但截至 2021 年(Django 3.2),这就是我所做的。


我需要什么:

  • 根据请求提供不同的模板(在我的情况下是使用的域)
  • 仅使用一个 Django 实例(= 1 IP/端口)

(一些多域解决方案是关于创建一个不同的新实例DIRS


对于多站点/多域:

  1. 加入'django.contrib.sites'进来INSTALLED_APPS_settings.py

    这启用了Django 站点框架

  2. 添加'django.contrib.sites.middleware.CurrentSiteMiddleware'MIDDLEWARES您的settings.py

    site为 Django 处理的每个请求添加了一个属性


用于使用按请求模板

  1. 创建额外的引擎

TEMPLATESsettings.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,
    }
]
  1. 使用usingkwargrender()

设置要使用的渲染引擎render()

前: render(request, 'template.html', context=context_data)

后:render(request, 'template.html', context=context_data, using=request.site.domain)

(在我的情况下,request.site.domaina.localor b.local,这正是我刚刚创建的引擎的名称)

  1. 覆盖渲染(可选,hacky)

避免改变你所有的render地方。这很恶心,你不应该这样做。移至基于分类的视图。这里是。

def render(request, *args, **kwargs):
    return shortcut_render(request, *args, **kwargs, using=request.site.domain)
于 2021-11-06T15:59:31.030 回答