Дерево в 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)
Плюсами данного метода для меня является то, что он более универсален, чем предыдущий, и если его немного модифицировать, то получится отличный метод.
Но мне кажется, что я рассмотрел не все решения данной задачи.