Дерево в select'е

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

Решал я данную задачу двумя разными способами.

Первый способ заключался в создании widget’а для django, который выводил древовидную структуру. Но этот способ мне кажется не сильно хорошим.

Минусы создания widget’а: так как в widget’е нету QuerySet’а, нам нужно опять выполнить запрос, чтобы знать структуру; widget получается довольно специфичным и его нельзя использовать для разных моделей, что опять же накладывает свои ограничения.

Вторим способом был отказ от использования ModelChoiceField в пользу ChoiceField с ручным формированием словаря. В этом случае запрос в базу данных выполнялся один раз и к тексту значения в начале проставлялись пробелы, вернее “ ”.

Пример кода:

def get_childrens(parent):
    choices = ()
    for r in parent.childrens.all():
        label = mark_safe(' '*(parent.level * 2) + r.title)
        choices += (r.pk, label),
        childrens = get_childrens(r)
        if childrens:
            choices = tuple(chain(choices, childrens))

    return choices

TREE_FOR_SELECT = [get_childrens(i) for i in TreeModel.objects.filter(level=0)][0]

class OneForm(forms.Form):
    tree_select = forms.ChoiceField(choices=TREE_FOR_SELECT, required=False)

Плюсами данного метода для меня является то, что он более универсален, чем предыдущий, и если его немного модифицировать, то получится отличный метод.

Но мне кажется, что я рассмотрел не все решения данной задачи.