Довольно часто в форумах, либо в рассылках попадаются вопрос типа: "как изменить порядок вывода полей в форме?". Решение на самом деле тривиальное, но нигде явно не описано. Надо этот пробел заполнить:-).
Задача изменения порядка вывода полей формы актуальная для форм, которые создаются на базе моделей (позволю себе такое определение) автоматически, т.е. через ModelForm. В таких случаях иной раз нет возможности редактировать саму модель. Порядок играет роль при итерации по полям или при использовании стандартных хелперов рендеринга (as_p, as_table и т.п.).
А откуда же вообще берется очерёдность полей? Очевидно, что она зависит от того, как объявлены поля в определении модели (кстати, для тех форм, где поля декларируются вручную, это тоже справедливо). Это делается через хитрый механизм со статическим счетчиком (creation_counter'ом) и SortedDict внутри джанги. Но это отдельная тема для обсуждения. Вернемся к порядку :-).
Для форм, которые созданы на базе моделей или вручную, порядок полей можно легко изменить. Поможет в этом сам SortedDict. Для примера возьмем форму для редактирования стандартной модели User c некоторым подмножеством полей:
class UserForm(forms.ModelForm):
class Meta:
model = User
fields = ("username", "first_name", "last_name", "email")
Поля класс формы держит в атрибуте base_fields, который и есть SortedDict:
>>> UserForm.base_fields.__class__
<class 'django.utils.datastructures.SortedDict'>
>>> [(name, f) for name, f in UserForm.base_fields.items()]
[('username', <django.forms.fields.CharField object at 0x877c06c>),
('first_name', <django.forms.fields.CharField object at 0x877c82c>),
('last_name', <django.forms.fields.CharField object at 0x877f06c>),
('email', <django.forms.fields.EmailField object at 0x877f8ac>)]
Если посмотреть реализацию SortedDict, то станет понятно, что "порядок хранится" в списке keyOrder, в котором перечислены ключи в нужной последовательности:
>>> UserForm.base_fields.keyOrder
['username', 'first_name', 'last_name', 'email']
А раз это обычный список, то и делать с ним можно всё что угодно. Например развернуть:
>>> UserForm.base_fields.keyOrder.reverse()
>>> UserForm.base_fields.keyOrder
['email', 'last_name', 'first_name', 'username']
>>> [(name, f) for name, f in UserForm.base_fields.items()]
[('email', <django.forms.fields.EmailField object at 0x877f8ac>),
('last_name', <django.forms.fields.CharField object at 0x877f06c>),
('first_name', <django.forms.fields.CharField object at 0x877c82c>),
('username', <django.forms.fields.CharField object at 0x877c06c>)]
Или поставить email сразу после username:
>>> UserForm.base_fields.keyOrder.insert(1, UserForm.base_fields.keyOrder.pop(-1))
>>> UserForm.base_fields.keyOrder
['username', 'email', 'first_name', 'last_name']
>>> [(name, f) for name, f in UserForm.base_fields.items()]Out[4]:
[('username', <django.forms.fields.CharField object at 0x877c06c>),
('email', <django.forms.fields.EmailField object at 0x877f88c>),
('first_name', <django.forms.fields.CharField object at 0x877c80c>),
('last_name', <django.forms.fields.CharField object at 0x877f04c>)]
После таких манипуляций все объекты этой формы будут иметь заданный порядок полей. Кстати, сами объекты формы хранят поля в своём атрибуте fields, над которым тоже можно издеваться, но это уже будет иметь эффект только на данный объект.
Удобно, правда?
Комментарии 12
Действительно очень удобно, спасибо за пост. Не всегда можно менять модели, да и в разных местах приложения бывает, требуется разный порядок полей. А этот способ (для простых форм) позволяет не писать дополнительный код с ручным выводом формы.
PS: У вас в fields класса UserForm скобки разные стоят.
PPS: Если комментарий не сразу добавлять, а делать "просмотр", при его сохранении получается "страница не найдена".
Оставлен 07 Январь 2009 в 21:18 ¶Привет, Александр.
Вопрос не совсем в тему поста, но рядом.
Как наиболее правильно автоматически создать форму из N моделей, при этом изменить порядок полей в форме?
Оставлен 08 Январь 2009 в 09:35 ¶а как в таких формах с валидацией, в каком порядке она будет проходить для сортированных таким образом полей?
P.S. если форма комментария не прошла валидацию - капча не отображается
Оставлен 08 Январь 2009 в 14:56 ¶За багрепорты спасибо. При следующем апдейте учту.
Оставлен 08 Январь 2009 в 19:26 ¶Я бы попробовал через
Оставлен 08 Январь 2009 в 19:31 ¶fields_for_modelсобрать все поля со всех моделей и потом на базе них сделать форму. И в ней уже тасовал бы поля.В заданном порядке. Т.е. все операции с полями будут происходить в новом указанном порядке.
Оставлен 08 Январь 2009 в 19:32 ¶И здесь явно не описано. ;) надо заполнить.
в данном случае, порядок берется из списка полей. Можно завести отдельный список.
Оставлен 11 Январь 2009 в 03:44 ¶Очень символично, что теперь ты даже не указываешь инструмент, о котором повествуешь :-).
p.s. Я и сам за собой такое замечал, в контексте Linux.
..bw
Оставлен 13 Январь 2009 в 17:30 ¶Ну ладно тебе, тег то у поста тематический выставлен:-) На него и надо ориентироваться:-)
Оставлен 13 Январь 2009 в 19:24 ¶Да я так, просто Django не люблю ;-). Да и просто, стоит иногда опускаться до мерских проблем... (Не все используют Django, не все работают в Linux.)
p.s. Получил через "контакты" сообщение про комментарии?
..bw
Оставлен 14 Январь 2009 в 21:00 ¶Не, джангу надо любить:-)
Да, спасибо. В очередной раз помог;-)
Оставлен 15 Январь 2009 в 00:48 ¶Да Саша описал проблему но не дал решения.
Сергей Шепелев вроде дал единственное исправление
class MyForm(forms.ModelForm):
Наверное это даже можно вынести куда нибудь в одно место. и упорядоченность будет подчинятся fields.
Оставлен 19 Январь 2009 в 18:42 ¶Пингбеки 1
Пост на эту тему — http://webnewage.org/2009/01/08/k-poryadku/
Комментирование данного поста закрыто.