Как динамически вызывать тег шаблона Django из переменной - PullRequest
0 голосов
/ 12 февраля 2019

Я пытаюсь разрешить динамические теги шаблонов.В частности, у меня есть настройки меню, которые я определяю в коде против шаблонов.И я хотел бы сделать метку меню как {{ 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?Это также относится к URL-адресу значения {% provider_login_url "google" next=next %}.

Ответы [ 2 ]

0 голосов
/ 15 февраля 2019

Если я вас хорошо понимаю, вы хотите написать код шаблона, который будет отображаться в коде шаблона, а затем снова обрабатываться.Что-то вроде ... мета-шаблонов?

Я вижу, вы уже разобрались с первой частью, но теперь вам нужно снова проанализировать полученный код, чтобы установить соответствующее значение для {{ 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 экземпляр:

enter image description here

И результат:

enter image description here

0 голосов
/ 14 февраля 2019

Вы можете создать собственный тег шаблона и отобразить их.Вот так

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...