将请求传递给自定义 Django 模板加载器

UnT*_*hie 4 django django-templates

我想为我的 Django 应用程序编写自定义模板加载器,它会根据作为请求一部分的键查找特定文件夹。

让我详细了解一下。假设我将获得每个请求的密钥(我使用中间件填充)。

示例:request.key 可以是 'india' 或 'usa' 或 'uk'。

我希望我的模板加载器查找模板“ templates/<key>/<template.html>”。因此,当我说{% include "home.html" %},我希望模板加载器根据请求加载“templates/india/home.html”或“templates/usa/home.html”或“templates/uk/home.html”。

有没有办法将请求对象传递给自定义模板加载器?

小智 5

我一直在寻找相同的解决方案,经过几天的搜索,我决定使用 threading.local()。只需在 HTTP 请求处理期间将请求对象设为全局即可!开始从画廊扔烂番茄。

让我解释:

从 Django 1.8(根据开发版本文档)开始,所有模板查找函数的“dirs”参数都将被弃用。(参考)

这意味着除了被请求的模板名称和模板目录列表之外,没有任何参数传递给自定义模板加载器。如果您想访问请求 URL 中的参数(甚至会话信息),您将不得不“接触”其他一些存储机制。

import threading
_local = threading.local()

class CustomMiddleware:

    def process_request(self, request):
         _local.request = request

def load_template_source(template_name, template_dirs=None):
    if _local.request:
        # Get the request URL and work your magic here!
        pass
Run Code Online (Sandbox Code Playgroud)

在我的情况下,它不是我所追求的请求对象(直接),而是模板应该呈现给哪个站点(我正在开发 SaaS 解决方案)。


Wol*_*lph 2

为了找到渲染模板,Django 使用get_template仅获取template_name和 可选dirs参数的方法。所以你不能真正在那里传递请求。

但是,如果您自定义render_to_response函数来传递dirs参数,您应该能够做到这一点。

例如(假设您RequestContext像大多数人一样使用 a ):

from django import shortcuts
from django.conf import settings

def render_to_response(template_name, dictionary=None, context_instance=None, content_type=None, dirs):
    assert context_instance, 'This method requires a `RequestContext` instance to function'
    if not dirs:
        dirs = []
    dirs.append(os.path.join(settings.BASE_TEMPLATE_DIR, context_instance['request'].key)
    return shortcuts.render_to_response(template_name, dictionary, context_instance, content_type, dirs)
Run Code Online (Sandbox Code Playgroud)