【问题标题】:Passing request to custom Django template loader将请求传递给自定义 Django 模板加载器
【发布时间】:2023-03-20 19:09:02
【问题描述】:

我想为我的 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”。

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

【问题讨论】:

    标签: django django-templates


    【解决方案1】:

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

    但是,如果您自定义 render_to_response 函数以传递 dirs 参数,您应该可以做到。

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

    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)
    

    【讨论】:

    • 感谢您。这真的很有用。假设我写了这个自定义的 render_to_response,我如何确保 django 使用这个函数?例如,当我写{% include "home.html" %} 时,Django 怎么知道它必须使用自定义的 render_to_response?
    • Django 不会使用自定义的render_to_response,但它应该将dirs 变量传递给模板解析器,以便包含也获取此参数。
    • 我不太明白。如果 Django 不使用这个自定义的render_to_response,那么它将如何传递include 语句将使用的目录?
    • render_to_response 方法只是创建模板加载器、将模板渲染为字符串并从字符串创建 httpresponse 的快捷方式。由于 dirs 参数被传递给加载器,模板对象将获取它并且渲染器将知道您的 dirs 参数。
    【解决方案2】:

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

    让我解释一下:

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

    这意味着除了被请求的模板名称和模板目录列表之外,没有传递给自定义模板加载器的参数。如果您想访问请求 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
    

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

    【讨论】:

      猜你喜欢
      • 2012-02-26
      • 1970-01-01
      • 2019-06-06
      • 1970-01-01
      • 2019-01-29
      • 2014-05-13
      • 2023-04-02
      • 2011-11-10
      • 2011-11-24
      相关资源
      最近更新 更多