Тег шаблона Django для отображения содержимого дословно, а также в виде рендеринга

Я пытаюсь сделать шаблонный тег, который будет показывать участок кода дословно, а также рендерить его, это поможет мне продемонстрировать некоторый код для моего собственного инструментария.

Допустим, у меня есть следующее в шаблоне:

{% example %}import * as fancy from "{% static 'jslib/fancy.min.js' %}";{% endexample %}

Я хочу вывести его в виде (я добавлю несколько div'ов и стилизацию, но это упрощение проблемы):

import * as fancy from "{% static 'jslib/fancy.min.js' %}";
import * as fancy from "/static/jslib/fancy.min.js";

Я посмотрел на тег django {% verbatum %} и попытался скопировать логику:

# django.template.defaulttags.py
@register.tag
def verbatim(parser, token):
    nodelist = parser.parse(('endverbatim',))
    parser.delete_first_token()
    return VerbatimNode(nodelist.render(Context()))

nodelist.render(Context()) выводит текстовые узлы для тега django verbatim, но если я скопирую код, мой пример тега выведет скажем StaticNodes и другие типы узлов.

Причина в том, что я думаю, что парсер django имеет некоторые специальные проверки, чтобы увидеть, является ли это дословным узлом и обрабатывает его по-разному, как показано в коде ниже:

# django.template.base.py -> def create_token
                if self.verbatim:
                    # Then a verbatim block is being processed.
                    if content != self.verbatim:
                        return Token(TokenType.TEXT, token_string, position, lineno)
                    # Otherwise, the current verbatim block is ending.
                    self.verbatim = False
                elif content[:9] in ('verbatim', 'verbatim '):
                    # Then a verbatim block is starting.
                    self.verbatim = 'end%s' % content
                return Token(TokenType.BLOCK, content, position, lineno)

Это означает, что я проверил узлы списка узлов на предмет наличия у них какого-то метода "получить исходную строку", но ничего не нашел.

Как сделать тег, чтобы получить отрендеренный и неотрендеренный текст внутри пары тегов?

Самое неэлегантное решение, забейте на него. Просто загрузите файл и используйте regex для удаления части

import re

from django import template

register = template.Library()


@register.tag
def story(parser, token):
    """Usage: {% story verbatim_1 %} <div>{{ foo }}</div> {% endstory %}
    @verbatim_id: str
        Attribute value that starts with the text 'verbatim', following it
        should be a unique id, e.g. `verbatim_1`, `verbatim_2` etc.
        This unique verbatim id is used to open the file and perform a regex
        match to find the code and read it verbatim.
    """
    bits = token.contents.split()    
    verbatim_id = next(filter(lambda x: 'verbatim' in x, bits), None)
    nodelist = parser.parse(('endstory',))
    parser.delete_first_token()
    return StoryNode(nodelist,verbatim_id)


class StoryNode(template.Node):
    def __init__(self, nodelist, dark, verbatim_id):
        self.nodelist = nodelist
        self.verbatim_id = verbatim_id

    def render(self, context):
        example = self.nodelist.render(context)        
        if self.verbatim_id:
            file = self.origin.name
            with open(file, 'r') as f:
                content = f.read()
            pattern = r'{%\s*stZory[^%]*' + self.verbatim_id + r'[^%]*%}(.+?){% endstory %}'
            match = re.search(pattern, content, flags=re.M | re.DOTALL)
            if not match:
                raise ValueError(
                    f"ERROR: Could not find verbatim_id: '{self.verbatim_id}', line: {self.token.lineno}, file: {self.origin.name}"
                )
            inner_html = match.group(1).strip()
            code = inner_html
        else:
            code = example
        print('The verbatim code is', code)   
        print('The rendered example is', example)
        return mark_safe('')
Вернуться на верх