在模板标签中获取模板名称(Django)

8
有没有办法在模板标记中获取正在解析的模板名称? 我已经阅读搜索并找不到任何内容,只有这个以前的帖子 Getting the template name in django template 这并没有对我有太大帮助,因为答案依赖于设置settings.DEBUG为true,而在我的情况下无法实现。
我真的不知道从哪里开始,所以欢迎任何建议 :)
编辑
所以基本上我想要创建一个可插入的标记,当渲染它时,它会检查是否存在一个Tag对象,这将是标记对象的来源。
class Tag(models.Model):
    template = models.CharFIeld(max_length=50)
    name = models.CharField(max_length=100)
    plugins = models.ForeignKey(PluginBase)

如果存在标签对象,则显示所有插件对象,否则创建一个与模板标签和模板名称提供的名称唯一的标签对象,如果无法获取模板名称,则可以根据名称使其唯一。整个标签有点像 django-cms 中的占位符。


我怀疑这是不可能的。据我所知,在标签解释之前,模板结构会被解析成树形模型。因此,当模板标签被执行时,您需要的信息可能已经丢失了。这只是一个猜测,但我认为您应该计划另一种替代方法;) - Martin Thurau
2
你的实际使用情况是什么?我怀疑有更好的方法可以实现你想要的。 - Daniel Roseman
2个回答

3

你可以使用上下文处理器来实现这一点,但我不确定这些处理器是否可以访问模板的名称。

有一个可行的方法是为你进行的渲染调用创建一个包装器。比如说你目前正在执行以下操作:

from django.shortcuts import render
def index(request):
    return render(request, 'app/index.html', { 'foo': 'bar', })

如果您为此创建自己的封装,您可以在实际渲染之前将模板名称添加到字典中:
from django.shortcuts import render
def myrender(request, template, dictionary):
    dictionary.update({'template_name': template})
    return render(request, template, dictionary)

然后在你的视图中,按照以下方式更改它(假设你将上述函数保存在myutils.py中,并且该文件可以在你的路径中找到):

#from django.shortcuts import render <- delete this line
from myutils import myrender as render
def index(request):
    return render(request, 'app/index.html', { 'foo': 'bar', })

现在,所有的render调用都将使用模板名称更新字典。在任何模板中,只需使用{{ template_name }}即可获取名称。当然,您也可以以类似的方式更新其他渲染函数,例如render_to_response等。
此外,import myrender as render可能会让您后来感到困惑,因为它的命名方式与Django函数相同...如果是这样,请不带"as render"导入它,并将所有的render调用替换为myrender。个人而言,我更喜欢这种方式,因为它可以作为现有渲染函数的插入式替代品。

谢谢,但是由于这是一个需要访问的模板标签,我并不真正使用视图渲染函数,因为基本上我希望模板标签获取其模板名称并对其进行一些处理。我同意使用上下文处理器,但不知道如何获取名称:( - Paulo
如果你不渲染模板,你怎么使用它? - jro
我的意思是,我不会通过视图来渲染模板,因为它本来就是开源的。 - Paulo
我真的想不出在不修改 Python 代码的情况下如何做到这一点:无论是视图本身还是 Django 源代码,就像 Shawn 在他的答案中提到的那样。猜想最终取决于对目标受众影响最小的那个选项...? - jro

3

从源代码来看,虽然Template对象可以通过.name访问模板名称,但该值从未传递给Parser对象,因此在模板标签中不可用。

有多种方法可以使模板名称对模板本身可用(通过将其添加到上下文中),但在模板标签中不可用。

正如丹尼尔·罗斯曼在评论中提到的那样,如果您可以详细说明您实际想要实现什么,可能会有更好的方法来实现您想要的功能。没有冒犯之意,但这听起来可能是一个XY问题


出于学术兴趣,我进行了一些尝试,看看是否可能。据我所见,这是可能的,但需要更改或猴子补丁django源代码。

注意:以下不是建议的解决方案,仅提供提示,以实际使其工作可能需要做出修改。不要用于生产代码。

通过修改django.template.base.py,进行以下更改,我们向解析器对象添加了.template_name属性,使其可用于模板标签。

  1. compile_string添加了可选参数
  2. 向解析器添加了模板名称作为额外属性
  3. 在调用compile_string()时传入模板名称

为了测试这个方法,我定义了以下标签,它只是将模板名称以大写字母返回:

from django.template.base import Node, Library
register = Library()

class TemplateNameNode(Node):
    def __init__(self, template_name):
        self.name = template_name

    def render(self, context):
        return self.name.upper()

@register.tag
def caps_template_name(parser, token):
     return TemplateNameNode(parser.template_name)

和以下模板:

{% load mytags %}
Template name in caps: {% caps_template_name %}

这段代码在测试时似乎是可行的:

./manage.py shell

>>> from django.template import loader, Context
>>> t = loader.get_template("test.html")
>>> t.render(Context({}))
u'\nTemplate name in caps: TEST.HTML\n'

虽然这似乎有效,但我应该再强调一下,手动修补django源代码永远不是一个好的解决方案,并且在迁移到不同版本时会遭受各种痛苦。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接