【问题标题】:如何在模板代码中设置变量的值?
【发布时间】:2010-11-07 09:50:38
【问题描述】:

假设我有一个模板

<html>
<div>Hello {{name}}!</div>
</html>

在测试时,在不触及调用此模板的 python 代码的情况下定义变量的值会很有用。所以我正在寻找这样的东西

{% set name="World" %}     
<html>
<div>Hello {{name}}!</div>
</html>

Django 中是否存在类似的东西?

【问题讨论】:

    标签: django django-templates


    【解决方案1】:

    您可以使用with 模板标签。

    {% with name="World" %}     
    <html>
    <div>Hello {{name}}!</div>
    </html>
    {% endwith %}
    

    【讨论】:

    【解决方案2】:

    有一些像约翰描述的技巧;但是,Django 的模板语言在设计上不支持设置变量(请参阅Django documentation for templates 中的“哲学”框)。
    因此,更改任何变量的推荐方法通过触摸 Python 代码。

    【讨论】:

    • 感谢您的指点。从设计者的角度来看,有时更容易在设计时快速设置一个变量来测试页面的各种状态。不建议在运行代码中使用这种做法。
    • django1.0 接受“with”标签。所以看起来他们终于要修改他们的理念了:)。
    • 事实上,“with”标签仅用于别名。这可能会对性能(以及可读性!)产生巨大影响,但它并没有真正设置传统编程术语中的变量。
    【解决方案3】:

    另一种不需要将所有内容都放在“with”块中的方法是创建一个自定义标签,将新变量添加到上下文中。如:

    class SetVarNode(template.Node):
        def __init__(self, new_val, var_name):
            self.new_val = new_val
            self.var_name = var_name
        def render(self, context):
            context[self.var_name] = self.new_val
            return ''
    
    import re
    @register.tag
    def setvar(parser,token):
        # This version uses a regular expression to parse tag contents.
        try:
            # Splitting by None == splitting by spaces.
            tag_name, arg = token.contents.split(None, 1)
        except ValueError:
            raise template.TemplateSyntaxError, "%r tag requires arguments" % token.contents.split()[0]
        m = re.search(r'(.*?) as (\w+)', arg)
        if not m:
            raise template.TemplateSyntaxError, "%r tag had invalid arguments" % tag_name
        new_val, var_name = m.groups()
        if not (new_val[0] == new_val[-1] and new_val[0] in ('"', "'")):
            raise template.TemplateSyntaxError, "%r tag's argument should be in quotes" % tag_name
        return SetVarNode(new_val[1:-1], var_name)
    

    这将允许您在模板中编写类似的内容:

    {% setvar "a string" as new_template_var %}
    

    请注意,其中大部分是taken from here

    【讨论】:

    • 如何将变量分配给上下文中存在的其他变量?另一方面:允许模板任意分配上下文变量而不检查它们是否已经存在可能会产生安全隐患。我认为更明智的方法是在尝试分配变量之前检查变量的上下文:
    • if context.get(self.var_name): raise SuspiciousOperation("Attempt to assign variable from template already present in context")
    【解决方案4】:

    一般来说,这不是一个好主意。在python中执行所有逻辑并将数据传递给模板进行显示。模板应尽可能简单,以确保从事设计工作的人可以专注于设计,而不必担心逻辑。

    举个例子,如果你需要模板中的一些派生信息,最好将它放入python代码中的变量中,然后将其传递给模板。

    【讨论】:

      【解决方案5】:

      最好的解决方案是编写一个自定义的assignment_tag。这个解决方案比使用with 标签更干净,因为它实现了逻辑和样式之间的非常清晰的分离。

      首先创建一个模板标签文件(例如appname/templatetags/hello_world.py):

      from django import template
      
      register = template.Library()
      
      @register.simple_tag
      def get_addressee():
          return "World"
      

      现在您可以在模板中使用get_addressee 模板标签:

      {% load hello_world %}
      
      {% get_addressee as addressee %}
      
      <html>
          <body>
              <h1>hello {{addressee}}</h1>
          </body>
      </html>
      

      【讨论】:

      • 对于使用较新 Django 版本的人来说,它现在称为 simple_tag!节省时间找出为什么“注册..”在您的代码中无法识别...
      【解决方案6】:

      创建模板标签:

      应用程序应包含templatetags 目录,与models.pyviews.py 等处于同一级别。如果尚不存在,请创建它 - 不要忘记__init__.py 文件以确保该目录被视为 Python 包。

      使用以下代码在 templatetags 目录中创建一个名为 define_action.py 的文件:

      from django import template
      register = template.Library()
      
      @register.simple_tag
      def define(val=None):
        return val
      

      注意:开发服务器不会自动重启。添加templatetags 模块后,您需要重新启动服务器才能使用模板中的标签或过滤器。


      然后在您的模板中,您可以像这样为上下文分配值:

      {% load define_action %}
      {% if item %}
      
         {% define "Edit" as action %}
      
      {% else %}
      
         {% define "Create" as action %}
      
      {% endif %}
      
      
      Would you like to {{action}} this item?
      

      【讨论】:

      • 在我的情况下,循环后返回旧值:(
      • 在最新版本中,您似乎可以使用 simple_tag 而不是 assignment_tag(它对我有用)。
      • 我使用此解决方案遇到的问题是,您无法覆盖值。
      • 如果你想使用这种技术来设置一个列表而不是一个值,检查这个:stackoverflow.com/a/34407158/2193235
      • 如果你将变量设置为一个整数并且你想增加它(例如),你需要使用add:{% define counter|add:1 as counter %}。其他操作也是如此。
      【解决方案7】:

      在您的模板中,您可以这样做:

      {% jump_link as name %}
      {% for obj in name %}
          <div>{{obj.helo}} - {{obj.how}}</div>
      {% endfor %}
      

      您可以在模板标签中添加这样的标签:

      @register.assignment_tag
      def jump_link():
          listArr = []
          for i in range(5):
              listArr.append({"helo" : i,"how" : i})
          return listArr
      

      【讨论】:

        【解决方案8】:

        也许 default template filter 在 2009 年不是一个选择...

        <html>
        <div>Hello {{name|default:"World"}}!</div>
        </html>
        

        【讨论】:

        • 我必须说这就是我要找的!它也可以与 with 一起使用:{% with state=form.state.value|default:other_context_variable %} 而不是other_context_variable 我们也可以使用任何'string_value' 以及
        • 但它会打印出来,我需要保存以备后用
        【解决方案9】:

        使用with statement

        {% with total=business.employees.count %}
            {{ total }} employee{{ total|pluralize }}
        {% endwith %}
        

        我不能暗示this answer 第一段中的代码。也许模板语言已经弃用了旧格式。

        【讨论】:

          猜你喜欢
          • 2012-02-27
          • 1970-01-01
          • 2019-03-05
          • 2013-04-16
          • 1970-01-01
          • 2015-07-06
          • 2011-08-06
          • 1970-01-01
          • 2012-10-11
          相关资源
          最近更新 更多