древовидная структура родительско-дочерних отношений в шаблонах django - PullRequest
4 голосов
/ 08 марта 2011

как мне реализовать древовидную структуру в шаблонах django без использования django-mptt.

у меня есть модель.

class Person(TimeStampedModel):
    name  = models.CharField(max_length=32)
    parent      = models.ForeignKey('self', null=True, blank=True, related_name='children')

теперь я хочу ..

 Parent
    Child 1
         subchild 1.1
         subchild 1.2
             nextsubchild 1.2.1
    Child 2
    Child 3

там имена должны кликнуть, чтобы показать их профиль.

Ответы [ 4 ]

11 голосов
/ 15 апреля 2011

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

Решение, которое я реализовал, очень просто: я просто повторяю в представлении (в моем случае универсальную вспомогательную функцию) и сглаживаю иерархическую структуру в простой список. Затем в моем шаблоне я просто использую цикл for для перебора списка.

Каждый элемент в списке может быть одним из трех: «in», объект или «out». В моем случае я создаю серию элементов ul li в представлении, поэтому, когда я сталкиваюсь с "in", я создаю новый ul, когда я сталкиваюсь с "out", я закрываю ul. В противном случае, я отрисовываю предмет.

Мой код шаблона выглядит так:

                          {% for item in sub_nav %}     
                                {% if item == "in" %}         
                                    <ul>   
                                {% else %}                    
                                    {% if item == "out" %}            
                                            </ul>                 
                                        </li>                 
                                    {% else %}                    

                                            <li>                          
                                                <a href='{{item.full_url}}'>{{item.name}}</a>
                                                {% if item.leaf %}        
                                                </li>                     
                                                {% endif %}           

                                    {% endif %}           
                                {% endif %}           
                            {% endfor %}   

Код во вспомогательной функции выглядит следующим образом:

def get_category_nav(request,categories=None):
"""Recursively build a list of product categories. The resulting list is meant to be iterated over in a view"""
if categories==None:
    #get the root categories
    categories = ProductCategory.objects.filter(parent=None)
    categories[0].active=True
else:
    yield 'in'

for category in categories:
    yield category
    subcats = ProductCategory.objects.select_related().filter(parent=category)
    if len(subcats):
        category.leaf=False
        for x in get_category_nav(request,subcats):
            yield x
    else:
        category.leaf=True
yield 'out'

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

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

10 голосов
/ 08 марта 2011

из Django while loop вопрос и

http://docs.djangoproject.com/en/dev/howto/custom-template-tags/#inclusion-tags

# view.py

@register.inclusion_tag('children.html')
def children_tag(person):
    children = person.children.all()
    return {'children': children}

# children.html

<ul>
    {% for child in children %}
    <li> <a href="{{ child.get_absolute_url }}">{{ child }}</a></li>
        {% if child.children.count > 0 %}
        {% children_list child %}
        {% endif %}
    {% endfor %}
</ul>


# your template

{% children_tag parent %}
3 голосов
/ 28 марта 2012

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

class RecursiveThing(models.Model):

    name = models.CharField(max_length=32)
    parent = models.ForeignKey('self', related_name='children', blank=True, null=True)

    def as_tree(self):
        children = list(self.children.all())
        branch = bool(children)
        yield branch, self
        for child in children:
            for next in child.as_tree():
                yield next
        yield branch, None

А затем в вашем шаблоне:

<ul>
    {% for thing in things %}
        {% for branch, obj in thing.as_tree %}
            {% if obj %}
                <li>{{ obj.name }}
                {% if branch %}
                    <ul>
                {% else %}
                    </li>
                {% endif %}
            {% else %}
                {% if branch %}
                    </ul>
                {% endif %}
            {% endif %}
        {% endfor %}
    {% endfor %}
</ul>
0 голосов
/ 06 августа 2013

Это очень просто

Все, что вам нужно сделать, это получить все объекты:

people = Person.objects.all()

Затем в вашем шаблоне:

{% for person in people %}
  <li>- {{person.name}} </li>
  {% for child in person.children.all %}
     <ul>* {{child.nom}} </ul>
  {% endfor %}
 </li>          
{% endfor %}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...