Passing request to custom Django template loader

时光总嘲笑我的痴心妄想 提交于 2019-12-07 13:53:07

问题


I want to write custom template loader for my Django app which looks for a specific folder based on a key that is part of the request.

Let me get into more details to be clear. Assume that I will be getting a key on every request(which I populate using a middleware).

Example: request.key could be 'india' or 'usa' or 'uk'.

I want my template loader to look for the template "templates/<key>/<template.html>". So when I say {% include "home.html" %}, I want the template loader to load "templates/india/home.html" or "templates/usa/home.html" or "templates/uk/home.html" based on the request.

Is there a way to pass the request object to a custom template loader?


回答1:


I've been searching for the same solution and, after a couple days of searching, decided to use threading.local(). Simply make the request object global for the duration of the HTTP request processing! Commence rotten tomato throwing from the gallery.

Let me explain:

As of Django 1.8 (according to the development version docs) the "dirs" argument for all template finding functions will be deprecated. (ref)

This means that there are no arguments passed into a custom template loader other than the template name being requested and the list of template directories. If you want to access paramters in the request URL (or even the session information) you'll have to "reach out" into some other storage mechanism.

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

In my case it wasn't the request object (directly) I was after but rather what site (I'm developing a SaaS solution) the template should be rendered for.




回答2:


To find the template to render Django uses the get_template method which only gets the template_name and optional dirs argument. So you cannot really pass the request there.

However, if you customize your render_to_response function to pass along a dirs argument you should be able to do it.

For example (assuming you are using a RequestContext as most people would):

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)


来源:https://stackoverflow.com/questions/23029874/passing-request-to-custom-django-template-loader

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!