У меня есть древовидная структура в памяти, которую я хотел бы отобразить в HTML с помощью шаблона Django.
class Node():
name = "node name"
children = []
Будет некий объект root, который является Node, а children - это список Node. root будет передан в содержимом шаблона.
Я нашел в это одно обсуждение того, как этого можно достичь, но плакат предполагает, что это может быть нехорошо в производственной среде.
Кто-нибудь знает способ лучше?






Я думаю, что канонический ответ: «Не надо».
Вместо этого вам, вероятно, следует распутать эту вещь в вашем коде Посмотреть, так что это просто вопрос повторения (in | de) вмятин в шаблоне. Думаю, я бы сделал это, добавив отступы и отступы к списку во время рекурсии по дереву, а затем отправив этот список «путешествий» в шаблон. (шаблон затем вставит <li> и </li> из этого списка, создав рекурсивную структуру с ее «пониманием».)
Я также почти уверен, что рекурсивное включение файлов шаблонов - это действительно способ неправильный сделать это ...
Конечно. Вы составляете список вроде ['in', 'in', 'blah', 'out', 'blah', 'out'], а затем перебираете его в шаблоне. Если он равен 'in', вы испускаете li, 'out' вы испускаете / li, а в противном случае вы просто сбрасываете сам текст.
Любое разъяснение того, почему это рекурсивное построение меню «действительно неправильно»? Неужели это так дорого?
Что ж, независимо от того, дорого это или нет на практике, это как бы упускает из виду суть, проблема в том, что это логика, и как таковая не относится к стороне презентации. Это больше связано с чистотой, чем с производительностью.
Хотя я согласен с разделением логики / изложения. Это один из редких случаев, когда проблема ЕСТЬ предъявление. Потому что отображается рекурсивная вещь. Одна из проблем с разделением логики / представления заключается в том, где провести линию так, чтобы она на самом деле не вызывала слишком большого количества взаимосвязей из-за того, что требовалась запутанная логика в контроллере, чтобы заставить работать упрощенное представление. Теоретически контроллер не должен понимать представление, он просто должен знать, как передавать ему данные. Но я предполагаю, что это всего лишь один из тех компромиссов с реальностью.
Это не должен быть принятым ответом. Создать простой тег шаблона включения, который рекурсивно включает себя для отображения дерева информации в виде html, - тривиальная задача. Пока каждый рекурсивный вызов не вызывает базу данных и пока реализовано правильное кэширование, это не должно вызывать никаких проблем с производительностью. Гораздо сложнее пытаться написать правильный html в виде конкатенированных строк в представлении; html-код принадлежит шаблонам.
это может быть больше, чем вам нужно, но есть модуль django под названием 'mptt' - он хранит иерархическую древовидную структуру в базе данных sql и включает шаблоны для отображения в коде представления. вы можете найти там что-нибудь полезное.
вот ссылка: джанго-mptt
У меня была аналогичная проблема, однако я сначала реализовал решение с помощью JavaScript, а сразу после этого подумал, как бы я сделал то же самое в шаблонах django.
Я использовал утилиту сериализатора, чтобы превратить список моделей в json, и использовал данные json в качестве основы для своей иерархии.
В Django есть встроенный помощник по шаблонам для этого конкретного сценария:
https://docs.djangoproject.com/en/dev/ref/templates/builtins/#unordered-list
Работает, если все, что вы хотите вывести, это "
У меня была такая же проблема, и я написал тег шаблона. Я знаю, что есть и другие подобные теги, но мне все равно нужно было научиться создавать собственные теги :) Я думаю, что это получилось очень хорошо.
Прочтите документацию для получения инструкций по использованию.
github.com/skid/django-recurse
Может, это правильная ссылка? В профиле skid указано, что его фамилия - Джордановски, а в описании проекта указано a recursive django template tag: github.com/skid/django-recurse.
Это идеальное решение .. Но что, если нам нужно получить доступ к другим данным внутри зацикленной категории .. например: другая информация ..
Используя тег шаблона 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.
Спасибо! Просто и работает. В зависимости от структуры данных вам может даже не понадобиться цикл в основном файле (для корневых объектов)
Да, ты можешь сделать это. Это маленькая уловка, передача имени файла в {% include%} в качестве переменной:
{% with template_name = "file/to_include.html" %}
{% include template_name %}
{% endwith %}
Такой способ вложения хорош и быстр - я использую его сейчас - хотя мне интересно, эффективно ли он (слишком ленив, чтобы самому тестировать). Кто угодно может вмешаться ...
Никто не любит диктат? Мне может здесь чего-то не хватать, но это кажется наиболее естественным способом настройки меню. Использование ключей в качестве записей и значений в качестве ссылок позволяет разместить его в 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 %}
ИМХО Это самая чистая и лучшая абстракция в этой ветке. Милый Артур!
Имейте в виду, что если вы передаете объекты QuerySet в свой шаблон, вам необходимо вызвать all для объекта набора запросов: {% if menu.submenus.all|length %}
Работает как шарм. Но я полагаю, что это решение было доступно только несколько лет, см. соответствующий билет Django. Остальные ответы просто устарели.
ты спаситель!
исправьте это:
{% 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 %}
<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 не являются завершенными по Тьюрингу.
Я не понимаю, как это может сохранить иерархию исходных данных, если вы не визуализируете все это в HTML в своем представлении. Вы можете привести более конкретный пример?