我希望能够使用不同的基本模板渲染项目中的部分或全部视图。换句话说,对于网址/some/view
,我希望能够拥有/inline/some/view
并让它呈现相同的内容,但使用不同的基本模板。
修改每个视图以接受其他模板不是一种选择,因为我希望在项目中的所有应用中应用此行为,包括django.contrib.auth
等内容。
到目前为止,我有,在urls.py:
url("^inline/(?P<uri>.*)", format.inline, name='inline'),
视图,format.py:
from django.core.urlresolvers import resolve
def inline(request, uri=''):
# get the view that would normally handle this request
view, args, kwargs = resolve('/' + uri)
# call the view
kwargs['request'] = request
template_response = view(*args, **kwargs)
# ...now what?
我不知道从哪里开始。我可以在致电view()
之前修改整个模板链,以便template_response.render()
做正确的事吗?
也许我完全偏离这种方法并且应该关注中间件解决方案,但我对这种行为的想法很感兴趣,因为它很容易向后面的内容人员解释。
更新
我能够达到我想要的效果,但实施却非常缺乏。这是我做的:
templates/inline/
{% extends base.html %}
替换为{% extends inline/base.html %}
修改了视图:
from django.core.urlresolvers import resolve
def inline(request, uri=''):
# get the view that would normally handle this request
view, args, kwargs = resolve('/' + uri)
# call the view
kwargs['request'] = request
template_response = view(*args, **kwargs)
response.template_name = os.path.join('inline', response.template_name)
return response
我不喜欢这个解决方案,因为它需要管理这些内联模板,在项目中的应用程序发生变化时进行替换/更新,等等。我仍然非常喜欢更清洁的解决方案。
chris-wesseling 100%正确;自定义模板加载器正是我所需要的。对于后代,这是我的实施。
应用程序/ loaders.py:
from django.conf import settings
from django.template.loader import BaseLoader
from django.template.base import TemplateDoesNotExist
import os
class BaseTemplateOverrideLoader(BaseLoader):
"""
Load templates from a specified subdirectory in the current app's directory.
"""
subdir = 'templates'
def load_template_source(self, template_name, template_dirs=None):
template_dir = os.path.join(
os.path.dirname(os.path.realpath(__file__)),
self.subdir
)
try:
t = os.path.join(template_dir, template_name)
with open(t, 'rb') as fp:
return (fp.read().decode(settings.FILE_CHARSET), template_dir)
except IOError:
pass
raise TemplateDoesNotExist(template_name)
class InlineTemplateLoader(BaseTemplateOverrideLoader):
"""
Override the location of base.html for inline views.
"""
is_usable = True
subdir = 'templates/inline'
# ... other custom override classes here ....
应用程序/视图/ inline.py:
from django.conf import settings
from django.core.urlresolvers import resolve
from django.template import loader
def default(request, slug=None):
view, args, kwargs = resolve('/' + slug)
old_loaders = settings.TEMPLATE_LOADERS
# Temporarily insert the inline template loader into TEMPLATE_LOADERS;
# we must also force BaseLoader to reload all templates loaders since
# they are cached at compile time.
settings.TEMPLATE_LOADERS = ('app.loaders.InlineTemplateLoader', ) + \
settings.TEMPLATE_LOADERS
loader.template_source_loaders = None
# now call the original view that handles this request
kwargs['request'] = request
response = view(*args, **kwargs)
response_string = response.render()
# restore the template loaders to their original condition
settings.TEMPLATE_LOADERS = old_loaders
loader.template_source_loaders = None
return response_string
应用程序/模板/内嵌/ base.html文件:
{% comment %}
inline/base.html
-- render just the main content without any styles etc,
for loading as inline content via ajax or whatever.
{% endcomment %}
{% block main %}{% endblock %}
答案 0 :(得分:1)
您可以实施自己的TemplateLoader并在settings.TEMPLATE_LOADERS中进行设置。您可以查看此similar question,了解您要尝试的方法。
基本上您正在寻找的是一种从其他位置加载base.html
的方式。