首先,在视图中通常需要设置上下文变量。在模板中放置逻辑代码会使代码更加混乱。即便如此,有时候你仍然需要使用它。由于 {% with %} 标签必须以 {% endwith %} 结尾,并且会丢失变量,所以在这种情况下会让事情变得更加混乱。我遇到的问题是,我无法在传递值的同时包含一个模板。我想要执行以下操作:
{% if criteria %}
{% define 'foo' as some_option %}
{% else %}
{% define 'bar' as some_option %}
{% endif %}
{% include "some_template_partial.html" %}
使用{% with %}标签而不重复代码来完成此操作是不可能的:
{% if criteria %}
{% with 'foo' as some_option %}
{% include "some_template_partial.html" %}
{% endwith %}
{% else %}
{% with 'bar' as some_option %}
{% include "some_template_partial.html" %}
{% endwith %}
{% endif %}
虽然现在看起来很好,但随着案例的增加,这将会变得非常混乱。因此,编写了以下代码:
from django import template
from django.conf import settings
import logging
import re
register = template.Library()
NAMESPACE_PROTECTION = settings.DEBUG
class define_node(template.Node):
def __init__(self, value, key, parse):
self.value = value
self.key = key
self.parse = parse
def render(self, context):
if NAMESPACE_PROTECTION:
if self.key in context:
raise Exception("EPIC NAMESPACE FAIL, CONTEXT HAZ A %s" % self.key)
if self.parse:
context[self.key] = context[self.value]
else:
context[self.key] = self.value
return ''
@register.tag
def define(parser, token):
"""Definition template tag. Use to define variables in your context within the template.
Sorta like the {% with "blah" as blah %} tag, but without the {% endwith %} mess.
Supports two modes:
Literal mode: argument is encapsulated with quotes (e.g. "blah" or 'blah')
variable, is set to the string literal, ex:
{% define "fish" as foo %}
Variable mode: argument is prefixed with a $ (e.g. $blah or $monkey)
variable is copied from another context variable, ex:
{% define $fish as foo %}
Namespace protection is also provided if django.conf.settings.DEBUG is True.
You will get an epic namespace fail if that occurs (please fix it before you deploy)
TODO:
* define override nomenclature if you REALLY want to overwrite a variable
- should decide what nomeclature to use first
* expand on variables so that {% define $array.blah as foo %} will work
(this currently WILL NOT)
"""
try:
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
value, key = m.groups()
if (value[0] == value[-1] and value[0] in ('"', "'")):
ret = value[1:-1]
parse = False
elif (value[0] == '$'):
ret = value[1:]
parse = True
else:
raise template.TemplateSyntaxError, "%r tag's first argument indeciperable" % tag_name
return define_node(ret, key, parse)