是否有Django模板标签可以让我设置上下文变量?

hek*_*ran 13 django django-templates

我希望能够将模板中的变量设置为字符串值.我写了一个标签,但它似乎没有改变上下文.预期用途是:

{% define "a string" as my_var %}
Run Code Online (Sandbox Code Playgroud)

更新(已解决):

class DefineNode(Node):
    def __init__(self, var, name):
        self.var = var
        self.name = name

    def __repr__(self):
        return "<DefineNode>"

    def render(self, context):
        context[self.name] = self.var
        return ''

@register.tag
def define(parser, token):
    """
    Adds a name to the context for referencing an arbitrarily defined string.

    For example:

        {% define "my_string" as my_string %}

    Now anywhere in the template:

        {{ my_string }}
    """
    bits = list(token.split_contents())
    if (len(bits) != 4 or bits[2] != "as") or \
        not (bits[1][0] in ('"', "'") and bits[1][-1] == bits[1][0]):
        raise TemplateSyntaxError("%r expected format is '\"string\" as name'" % bits[0])
    else:
        value = bits[1][1:-1]
    name = bits[3]
    return DefineNode(value, name)
Run Code Online (Sandbox Code Playgroud)

kir*_*ril 18

Django已经考虑了这个特殊情况并提供了分配标签,这是一种注册标签的特殊方式,可以在上下文中设置变量.

在这种情况下,您无需关心检索,更新和保存上下文.你只需这样做:

@register.assignment_tag
def define(the_string):
  return the_string
Run Code Online (Sandbox Code Playgroud)

你可以用同样的方式使用它,但它更清洁:

{% define "a string" as my_var %}
Run Code Online (Sandbox Code Playgroud)

这是您需要的所有代码.

编辑:正如Dirk Bergstrom指出的那样,因为版本django 1.9 assignment_tag已被弃用.simple_tag是一个完美的替代品.

@register.simple_tag
def define(the_string):
  return the_string
Run Code Online (Sandbox Code Playgroud)

  • assignment_tag自1.9以来已弃用.simple_tag是新的热点:https://docs.djangoproject.com/en/1.11/howto/custom-template-tags/#django.template.Library.simple_tag (2认同)

Joh*_*Mee 11

答案隐藏在文档中更复杂的current_time示例中.

问题

You want to add a variable to the context. But you don't want to go back and add that variable to all the views which call all the templates which invoke the tag. You just want a tag which can add some data to the context wherever its wanted. I'm looking for this kind of thing when rendering those random distractions which get dropped into sidebars and aren't specifically related to the work of the main view, for example.

Method

To inject a variable to the context you need access to the context. To do that your custom tag will inject a node which added the data to the template context.

Example

This example adds a "coming_events" queryset to the context then loops over each result. It does that by declaring a custom tag which renders a node which adds a queryset to the context.

from django import template
from apps.events.models import Event
register = template.Library()

@register.tag
def coming_events(parser, token):
    return EventNode()

class EventNode(template.Node):
    def render(self, context):
        context['coming_events'] = Event.objects.all()
        return ''
Run Code Online (Sandbox Code Playgroud)

You'd use it like this:

{% load events %}
{% coming_events %}
{% for event in coming_events %}
<div class="eventItem">
   <p>{{event.title}} {{event.data}}</p>
</div>
{% endfor %}
Run Code Online (Sandbox Code Playgroud)

Extra Credit

If you're really keen to be able to name the variable arbitrarily eg {% coming_events as events %} then look closely at the example in the documentation and note how they split the token into what's before the ' as ' and what's after and use the latter part to name the context variable. You'd have to implement that.

Note that if I wound up putting the HTML for each event into its own dedicated template then I'd be better off just following the standard inclusion tag example in the documentation. This solution is suggested for when you want the data without any baggage.


Dan*_*man 8

您无需编写自己的标签。内置{% with %}标签就是这样做的。

  • 这不是问题的解决方案。“with”仅在模板的有限部分内临时重命名变量。正如问题所问的那样,它不会将新变量添加到更大的上下文中。 (11认同)
  • 我很惊讶这有一个勾号,因为它没有解决问题:我没有看到 'with' 创建一个新的上下文变量;它只是暂时重命名现有的。 (6认同)

Jam*_*inn 8

如果您希望变量在其他模板块中可用,您应该查看http://od-eon.com/blogs/liviu/scope-variables-template-blocks/.特别是,在自定义标记代码中,您应该替换:

context[some_var_name] = some_val
Run Code Online (Sandbox Code Playgroud)

有:

context.dicts[0][some_var_name] = some_val
Run Code Online (Sandbox Code Playgroud)

这将成功(虽然它可能是一个丑陋的技巧,你应该考虑替代品).