Como posso renderizar uma estrutura de árvore (recursiva) usando um modelo Django?

StackOverflow https://stackoverflow.com/questions/32044

  •  09-06-2019
  •  | 
  •  

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 NodeS. 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?

Foi útil?

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.

github.com/skid/django-recurse

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.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top