我正在尝试使用动态模板标签。具体来说,我有一个菜单设置,该菜单设置是在代码和模板中定义的。我想将菜单标签呈现为{{ request.user }}
。因此,如何在Python中将其定义为字符串,并允许模板按预期方式解析和呈现该字符串。不仅是变量,还有模板标签({% provider_login_url 'google' next=next %}
)。
我想念什么?
使用代码更新:
我专门使用django-navutils
设计菜单,但这并不重要(基本上,程序包只存储定义的数据,然后使用模板来呈现它)。
from navutils import menu
top_horizontal_nav = menu.Menu('top_nav')
left_vertical_nav = menu.Menu('left_nav')
menu.register(top_horizontal_nav)
menu.register(left_vertical_nav)
sign_in = menu.AnonymousNode(
id='sign_in',
label='Sign In',
url='{% provider_login_url "google" next=next %}',
template='nav_menu/signin_node.html',
)
user = menu.AuthenticatedNode(
id='user_menu',
label='{{ request.user }}',
url='#',
template='nav_menu/username_node.html'
)
top_horizontal_nav.register(sign_in)
top_horizontal_nav.register(user)
我想要要做的是现在在模板中呈现这些字符串值('{{ request.user }}'
)
{% load navutils_tags %}
<li
class="{% block node_class %}nav-item menu-item{% if node.css_class %} {{ node.css_class }}{% endif %}{% if is_current %} {{ menu_config.CURRENT_MENU_ITEM_CLASS }}{% endif %}{% if has_current %} {{ menu_config.CURRENT_MENU_ITEM_PARENT_CLASS }}{% endif %}{% if viewable_children %} has-children has-dropdown{% endif %}{% endblock %}"
{% for attr, value in node.attrs.items %} {{ attr }}="{{ value }}"{% endfor %}>
<a href="{{ node.get_url }}" class="nav-link"{% for attr, value in node.link_attrs.items %} {{ attr }}="{{ value }}"{% endfor %}>{% block node_label %}{{ node.label }}{% endblock %}</a>
{% if viewable_children %}
<ul class="{% block submenu_class %}sub-menu dropdown{% endblock %}">
{% for children_node in viewable_children %}
{% render_node node=children_node current_depth=current_depth|add:'1' %}
{% endfor %}
</ul>
{% endif %}
</li>
因此,对于上述情况,我在渲染{{ node.label }}
的地方,如何才能将存储在node.label
中的值实际解析为request.user
?这同样适用于值{% provider_login_url "google" next=next %}
的URL。
答案 0 :(得分:3)
您可以创建一个自定义模板标签并进行渲染。像这样
from django import template
register = template.Library()
@register.simple_tag(takes_context=True)
def render_nested(context, template_text):
# create template from text
tpl = template.Template(template_text)
return tpl.render(context)
然后进入模板
...
<a href="{{ node.get_url }}" class="nav-link"
{% for attr, value in node.link_attrs.items %} {{ attr }}="{{ value }}"{% endfor %}>
{% block node_label %}{% render_nested node.label %}{% endblock %}
</a>
...
还没有测试,但我认为它可以工作。
有关模板的更多信息:https://docs.djangoproject.com/en/dev/ref/templates/api/#rendering-a-context
有关自定义标签的更多信息:https://docs.djangoproject.com/en/dev/howto/custom-template-tags/#writing-custom-template-tags
答案 1 :(得分:0)
如果我对您的理解很好,您希望编写可渲染为模板代码的模板代码,然后再次进行处理。像...元模板一样?
我可以看到您已经弄清楚了第一部分,但是现在您需要再次解析结果代码,以便为{{ request.user }}
设置相应的值。
我是通过使用中间件来实现的,但是由于解析模板是一项昂贵的操作,因此我实现了一种机制,将“重新解析”过程仅应用于我选择的URL /视图。
class ReparsingTarget(models.Model):
url_name = models.CharField(max_length=255)
很简单,只是一个用于存储那些我希望受到中间件影响的URL名称的模型。
class ReparsingMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
# We are no interested in whatever happens before
# self.get_response is called.
response = self.get_response(request)
# Now we will re-parse response just if the requested url
# is marked as target for re-parse.
if self._marked(request) and isinstance(response, TemplateResponse):
# Decode the template response code ...
content = response.content.decode('utf-8')
# Create a Template object ...
template = Template(content)
# Provide request to de context ...
context_data = response.context_data
context_data.update({'request': request})
# ... and renders the template back the the response.
response.content = template.render(Context(response.context_data))
return response
def _marked(self, request):
url_name = resolve(request.path_info).url_name
return ReparsingTarget.objects.filter(url_name=url_name).exists()
这是一个非常简单的实现,对我来说,棘手的部分是弄清楚如何将该想法放入Django代码中。
某些型号。
class Foo(models.Model):
label = models.CharField(max_length=255)
模板:
{% for foo in foos %}
{% comment %} Remember foo.label == '{{ request.user }}' {% endcomment %}
<p> Username: {{ foo.label }} </p>
{% endfor %}
存储的Foo
实例:
结果: