Como posso renderizar uma estrutura de árvore (recursiva) usando um modelo Django?
Pergunta
Tenho uma estrutura de árvore na memória que gostaria de renderizar em HTML usando um template Django.
class Node():
name = "node name"
children = []
Haverá algum objeto root
Aquilo é um Node
, e children
é uma lista de Node
S. root
será passado no conteúdo do modelo.
eu encontrei esse uma discussão sobre como isso pode ser alcançado, mas o pôster sugere que isso pode não ser bom em um ambiente de produção.
Alguém sabe de uma maneira melhor?
Solução
Acho que a resposta canônica é:"Não".
O que você provavelmente deveria fazer é desvendar a coisa em seu visualizar código, então é apenas uma questão de iterar sobre (in|de)dentes no modelo.Acho que faria isso anexando recuos e recuos a uma lista enquanto percorre a árvore e depois envia a lista de "diário de viagem" para o modelo.(o modelo então inseriria <li>
e </li>
dessa lista, criando a estrutura recursiva com "entendê-la".)
Também tenho certeza de que incluir recursivamente arquivos de modelo é realmente uma errado maneira de fazer isso...
Outras dicas
Usando with
tag de modelo, eu poderia fazer uma lista de árvore/recursiva.
Código de amostra:
modelo principal:assumindo que 'all_root_elems' é uma lista de uma ou mais raízes da árvore
<ul>
{%for node in all_root_elems %}
{%include "tree_view_template.html" %}
{%endfor%}
</ul>
tree_view_template.html renderiza o aninhado ul
, li
e usa node
variável de modelo conforme abaixo:
<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>
isso pode ser muito mais do que você precisa, mas existe um módulo Django chamado 'mptt' - ele armazena uma estrutura de árvore hierárquica em um banco de dados sql e inclui modelos para exibição no código de visualização.você pode encontrar algo útil lá.
aqui está o link: Django-mptt
Estou muito tarde) todos vocês usam muito desnecessários com tags, é assim que eu faço recuesive:
no modelo principal:
<!-- lets say that menu_list is already defined -->
<ul>
{% include "menu.html" %}
</ul>
então em 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 %}
Sim, você pode fazer isso.É um pequeno truque, passando o nome do arquivo para { % incluir %} como uma variável:
{% with template_name="file/to_include.html" %}
{% include template_name %}
{% endwith %}
O Django possui um modelo auxiliar integrado para este cenário exato:
https://docs.djangoproject.com/en/dev/ref/templates/builtins/#unordered-list
Eu tive o mesmo problema e escrevi uma tag de modelo.Eu sei que existem outras tags como essa por aí, mas eu precisava aprender a fazer tags personalizadas de qualquer maneira :) Acho que ficou muito bom.
Leia a documentação para obter instruções de uso.
Ninguém gosta de dictos?Posso estar faltando alguma coisa aqui, mas parece a maneira mais natural de configurar menus.Usando chaves como entradas e valores como links, coloque-o em um DIV/NAV e pronto!
Da sua base
# Base.html
<nav>
{% with dict=contents template="treedict.html" %}
{% include template %}
{% endwith %}
<nav>
chame isso
# 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>
Ele ainda não tentou o padrão ou o pedido, talvez você tenha?
corrija isso:
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>
por exemplo - modelo:
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)
Eu tive um problema semelhante, porém primeiro implementei a solução usando JavaScript e só depois considerei como teria feito a mesma coisa nos modelos Django.
Usei o utilitário serializador para transformar uma lista de modelos em json e usei os dados json como base para minha hierarquia.