Предположим что у нас есть древовидная структура, например таблица с полями (id, parent_id, name). Это может быть структура папок, иерархия животного мира, или например дерево категорий в магазине продуктов. Пример такой структуры:
Холоднокровные
Млекопитающие
-насекомоядные
—кроты
—землеройки
-грызуны
—мыши
—белки
—бобры
Как видно, из-за древовидности придется воспользоваться подходом с применением рекурсии. Однако своего велосипеда можно не изобретать, для django есть модуль, как раз работающий с подобной структурой — django-mptt . Основная документация есть на сайте http://django-mptt.github.io/django-mptt/tutorial.html#getting-started , однако мне потребовалось реализовать функционал, где листья деревьев раскрываются лишь в том случае, если выбран потомок. Таким образом, если мы выбрали бобра, то отобразиться должно вот так:
Холоднокровные
Млекопитающие
-насекомоядные
-грызуны
—мыши
—белки
—БОБРЫ
Переходим к реализации. Сперва создаем модель:
from django.db import models from mptt.models import MPTTModel, TreeForeignKey class Category(MPTTModel): name = models.CharField(max_length=64, unique=True) parent = TreeForeignKey('self', null=True, blank=True, related_name='children') class MPTTMeta: order_insertion_by = ['name']
Далее переходим во views.php
from django.shortcuts import render from django.shortcuts import render_to_response from django.http import Http404, HttpResponse from django.template import loader, Context, RequestContext from versane.models import Category def category_page(request, category_id): #getting detail information about current object current_category = Category.objects.get(id=category_id) root_category_id = current_category.get_root().id #render return render_to_response("category_page.html", { 'nodes':Category.objects.all(), 'current_category':current_category, 'root_category_id':root_category_id }, context_instance=RequestContext(request))
И самая фишка, это конечно шаблон. Дефолтный шаблон, выводит все листья, здесь же мы выводим только те категории, которые видны например при работе с папками.
{% load mptt_tags %} <h3>Categories</h3> {% load mptt_tags %} <ul> {% recursetree nodes %} <li> <a href="/category/{{ node.id }}/"> {{ node.name }} {{ node.id }} {{ node.level }} </a> {% if node.is_root_node %} {% ifequal node.id root_category_id %} {% if not node.is_leaf_node %} <ul class="children"> {{ children }} </ul> {% endif %} {% endifequal %} {% else %} {% if not node.is_leaf_node %} {% if current_category.id == node.id %} <ul class="children"> {{ children }} </ul> {% elif node.level < current_category.level %} <ul class="children"> {{ children }} </ul> {% endif %} {% endif %} {% endif %} </li> {% endrecursetree %} </ul>
Обратите внимание, на использование ключевых слов node, children а также их свойств node.is_root_node, node.level, node.is_leaf_node и.т.д. С помощью изменения шаблона, можно отобразить практически любую древовидную структуру так как нам надо, используя описанную модель MPTTModel