Как я могу визуализировать древовидную структуру (рекурсивную) с помощью шаблона django?

У меня есть древовидная структура в памяти, которую я хотел бы отобразить в HTML с помощью шаблона Django.

class Node():
  name = "node name"
  children = []

Будет некий объект root, который является Node, а children - это список Node. root будет передан в содержимом шаблона.

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

Кто-нибудь знает способ лучше?

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
66
0
32 217
10
Перейти к ответу Данный вопрос помечен как решенный

Ответы 10

Ответ принят как подходящий

Я думаю, что канонический ответ: «Не надо».

Вместо этого вам, вероятно, следует распутать эту вещь в вашем коде Посмотреть, так что это просто вопрос повторения (in | de) вмятин в шаблоне. Думаю, я бы сделал это, добавив отступы и отступы к списку во время рекурсии по дереву, а затем отправив этот список «путешествий» в шаблон. (шаблон затем вставит <li> и </li> из этого списка, создав рекурсивную структуру с ее «пониманием».)

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

Я не понимаю, как это может сохранить иерархию исходных данных, если вы не визуализируете все это в HTML в своем представлении. Вы можете привести более конкретный пример?

slacy 10.11.2009 01:29

Конечно. Вы составляете список вроде ['in', 'in', 'blah', 'out', 'blah', 'out'], а затем перебираете его в шаблоне. Если он равен 'in', вы испускаете li, 'out' вы испускаете / li, а в противном случае вы просто сбрасываете сам текст.

Anders Eurenius 17.11.2009 12:07

Любое разъяснение того, почему это рекурсивное построение меню «действительно неправильно»? Неужели это так дорого?

Yablargo 01.02.2014 06:54

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

Anders Eurenius 01.02.2014 12:27

Хотя я согласен с разделением логики / изложения. Это один из редких случаев, когда проблема ЕСТЬ предъявление. Потому что отображается рекурсивная вещь. Одна из проблем с разделением логики / представления заключается в том, где провести линию так, чтобы она на самом деле не вызывала слишком большого количества взаимосвязей из-за того, что требовалась запутанная логика в контроллере, чтобы заставить работать упрощенное представление. Теоретически контроллер не должен понимать представление, он просто должен знать, как передавать ему данные. Но я предполагаю, что это всего лишь один из тех компромиссов с реальностью.

Shayne 02.09.2018 06:24

Это не должен быть принятым ответом. Создать простой тег шаблона включения, который рекурсивно включает себя для отображения дерева информации в виде html, - тривиальная задача. Пока каждый рекурсивный вызов не вызывает базу данных и пока реализовано правильное кэширование, это не должно вызывать никаких проблем с производительностью. Гораздо сложнее пытаться написать правильный html в виде конкатенированных строк в представлении; html-код принадлежит шаблонам.

kloddant 29.12.2020 03:16

это может быть больше, чем вам нужно, но есть модуль django под названием 'mptt' - он хранит иерархическую древовидную структуру в базе данных sql и включает шаблоны для отображения в коде представления. вы можете найти там что-нибудь полезное.

вот ссылка: джанго-mptt

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

Я использовал утилиту сериализатора, чтобы превратить список моделей в json, и использовал данные json в качестве основы для своей иерархии.

В Django есть встроенный помощник по шаблонам для этого конкретного сценария:

https://docs.djangoproject.com/en/dev/ref/templates/builtins/#unordered-list

Работает, если все, что вы хотите вывести, это "

  • какой-то текст
  • " for each item. If you have a nested hierarchy of more complex items, and you (for example) want each item to be a link, then this tag isn't useful.
    slacy 10.11.2009 01:30

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

    Прочтите документацию для получения инструкций по использованию.

    github.com/skid/django-recurse

    Может, это правильная ссылка? В профиле skid указано, что его фамилия - Джордановски, а в описании проекта указано a recursive django template tag: github.com/skid/django-recurse.

    cod3monk3y 21.11.2013 10:03

    Это идеальное решение .. Но что, если нам нужно получить доступ к другим данным внутри зацикленной категории .. например: другая информация ..

    Suman Astani 25.01.2019 12:30

    Используя тег шаблона with, я мог делать древовидный / рекурсивный список.

    Образец кода:

    основной шаблон: предполагается, что all_root_elems - это список из одного или нескольких корней дерева

    <ul>
    {%for node in all_root_elems %} 
        {%include "tree_view_template.html" %}
    {%endfor%}
    </ul>
    

    tree_view_template.html отображает вложенные ul, li и использует переменную шаблона node, как показано ниже:

    <li> {{node.name}}
        {%if node.has_childs %}
            <ul>
             {%for ch in node.all_childs %}
                  {%with node=ch template_name = "tree_view_template.html" %}
                       {%include template_name%}
                  {%endwith%}
             {%endfor%}
             </ul>
        {%endif%}
    </li>
    

    Хотя я уверен, что есть веские причины не делать то, о чем просили, этот ответ на самом деле позволяет обойти проблему. Производительность снижается, но использование {% with%} для сохранения имени шаблона в переменной предотвращает бесконечное повторение цикла компилятора шаблонов django.

    Brian Arsuaga 01.08.2012 04:06

    Спасибо! Просто и работает. В зависимости от структуры данных вам может даже не понадобиться цикл в основном файле (для корневых объектов)

    Chris Koston 04.07.2014 02:42

    Да, ты можешь сделать это. Это маленькая уловка, передача имени файла в {% include%} в качестве переменной:

    {% with template_name = "file/to_include.html" %}
    {% include template_name %}
    {% endwith %}
    

    Такой способ вложения хорош и быстр - я использую его сейчас - хотя мне интересно, эффективно ли он (слишком ленив, чтобы самому тестировать). Кто угодно может вмешаться ...

    JxAxMxIxN 16.02.2017 08:20

    Никто не любит диктат? Мне может здесь чего-то не хватать, но это кажется наиболее естественным способом настройки меню. Использование ключей в качестве записей и значений в качестве ссылок позволяет разместить его в DIV / NAV, и вперед!

    С вашей базы

    # Base.html
    <nav>
    {% with dict=contents template = "treedict.html" %}
     {% include template %}
    {% endwith %}
    <nav>
    

    назови это

    # TreeDict.html
    <ul>
    {% for key,val in dict.items %}
     {% if val.items %}
      <li>{{ key }}</li>
      {%with dict=val template = "treedict.html" %}
       {%include template%}
      {%endwith%}
     {% else %} 
      <li><a href = "{{ val }}">{{ key }}</a></li>
     {% endif %}
    {% endfor %} 
    </ul>
    

    Он еще не пробовал стандартные или заказанные, возможно, вы это сделали?

    Я опоздал. Все вы используете столько ненужных тегов с, вот как я делаю рекурсию:

    В «основном» шаблоне:

    <!-- lets say that menu_list is already defined -->
    <ul>
        {% include "menu.html" %}
    </ul>
    

    Затем в menu.html:

    {% for menu in menu_list %}
        <li>
            {{ menu.name }}
            {% if menu.submenus|length %}
                <ul>
                    {% include "menu.html" with menu_list=menu.submenus %}
                </ul>
            {% endif %}
        </li>
    {% endfor %}
    

    ИМХО Это самая чистая и лучшая абстракция в этой ветке. Милый Артур!

    Neil 17.04.2018 03:23

    Имейте в виду, что если вы передаете объекты QuerySet в свой шаблон, вам необходимо вызвать all для объекта набора запросов: {% if menu.submenus.all|length %}

    Behdad 01.12.2019 13:50

    Работает как шарм. Но я полагаю, что это решение было доступно только несколько лет, см. соответствующий билет Django. Остальные ответы просто устарели.

    natka_m 14.07.2020 16:15

    ты спаситель!

    Sudesh Chaudhary 18.01.2021 15:42

    исправьте это:

    root_comment.html

    {% extends 'students/base.html' %}
    {% load i18n %}
    {% load static from staticfiles %}
    
    {% block content %}
    
    <ul>
    {% for comment in comments %}
        {% if not comment.parent %}                   ## add this ligic
        {% include "comment/tree_comment.html" %}
        {% endif %}
    {% endfor %}
    </ul>
    
    {% endblock %}
    

    tree_comment.html

    <li>{{ comment.text }}
        {%if comment.children %}
            <ul>
             {% for ch in comment.children.get_queryset %}     # related_name in model
                  {% with comment=ch template_name = "comment/tree_comment.html" %}
                       {% include template_name %}
                  {% endwith %}
             {% endfor %}
             </ul>
        {% endif %}
    </li>
    

    например - модель:

    from django.db import models
    from django.contrib.auth.models import User
    from django.utils.translation import ugettext_lazy as _
    
    
    # Create your models here.
    class Comment(models.Model):
        class Meta(object):
            verbose_name = _('Comment')
            verbose_name_plural = _('Comments')
    
        parent = models.ForeignKey(
            'self',
            on_delete=models.CASCADE,
            parent_link=True,
            related_name='children',
            null=True,
            blank=True)
    
        text = models.TextField(
            max_length=2000,
            help_text=_('Please, your Comment'),
            verbose_name=_('Comment'),
            blank=True)
    
        public_date = models.DateTimeField(
            auto_now_add=True)
    
        correct_date = models.DateTimeField(
            auto_now=True)
    
        author = models.ForeignKey(User)
    

    Жестокое злоупотребление системой include, но она работает! Мне это нравится! И тот факт, что он делает возможной рекурсию, заставляет меня переосмыслить свою позицию о том, что шаблоны djangos не являются завершенными по Тьюрингу.

    Shayne 02.09.2018 06:24

    Другие вопросы по теме