Если у меня есть форма Django, например:
class ContactForm(forms.Form):
subject = forms.CharField(max_length=100)
message = forms.CharField()
sender = forms.EmailField()
И я вызываю метод as_table () экземпляра этой формы, Django будет отображать поля в том же порядке, как указано выше.
Мой вопрос: как Django узнает порядок, в котором определены переменные класса?
(Также как мне переопределить этот порядок, например, когда я хочу добавить поле из метода init класса ?)
источник
Новым в Django 1.9 являются Form.field_order и Form.order_fields () .
# forms.Form example class SignupForm(forms.Form): password = ... email = ... username = ... field_order = ['username', 'email', 'password'] # forms.ModelForm example class UserAccount(forms.ModelForm): custom_field = models.CharField(max_length=254) def Meta: model = User fields = ('username', 'email') field_order = ['username', 'custom_field', 'password']
источник
Я пошел дальше и ответил на свой вопрос. Вот ответ для использования в будущем:
В Django
form.py
творится темная магия, используя__new__
метод для загрузки переменных вашего класса в конечном итоге вself.fields
порядке, определенном в классе.self.fields
являетсяSortedDict
экземпляром Django (определенным вdatastructures.py
).Итак, чтобы переопределить это, скажем, в моем примере вы хотите, чтобы отправитель был первым, но вам нужно добавить его в метод инициализации , вы должны сделать:
class ContactForm(forms.Form): subject = forms.CharField(max_length=100) message = forms.CharField() def __init__(self,*args,**kwargs): forms.Form.__init__(self,*args,**kwargs) #first argument, index is the position of the field you want it to come before self.fields.insert(0,'sender',forms.EmailField(initial=str(time.time())))
источник
self.fields.insert( 0, 'sender', self.fields['sender'] )
Поля перечислены в том порядке, в котором они определены в ModelClass._meta.fields. Но если вы хотите изменить порядок в форме, вы можете сделать это с помощью функции keyOrder. Например :
class ContestForm(ModelForm): class Meta: model = Contest exclude=('create_date', 'company') def __init__(self, *args, **kwargs): super(ContestForm, self).__init__(*args, **kwargs) self.fields.keyOrder = [ 'name', 'description', 'image', 'video_link', 'category']
источник
С Django> = 1.7 вы должны изменить,
ContactForm.base_fields
как показано ниже:from collections import OrderedDict ... class ContactForm(forms.Form): ... ContactForm.base_fields = OrderedDict( (k, ContactForm.base_fields[k]) for k in ['your', 'field', 'in', 'order'] )
Этот трюк используется в Django Admin
PasswordChangeForm
: Source на Githubисточник
PasswordChangeForm
изменили порядок полей, поэтому ваш пример оказался для меня очень полезным. Похоже, это потому,base_fields
что не переносится в подкласс. Решение, кажется, говоритPasswordChangeFormSubclass.base_fields = PasswordChangeForm.base_fields
после определения `PasswordChangeFormSubclassContactForm.base_fields[k]
при построении упорядоченного dict. В ответе опечатка, отредактируюПоля формы имеют атрибут порядка создания, называемый
creation_counter
..fields
attribute - это словарь, поэтому достаточно простого добавления в словарь и измененияcreation_counter
атрибутов во всех полях, чтобы отразить новый порядок (хотя я никогда не пробовал этого).источник
Используйте счетчик в классе Field. Сортировать по этому счетчику:
import operator import itertools class Field(object): _counter = itertools.count() def __init__(self): self.count = Field._counter.next() self.name = '' def __repr__(self): return "Field(%r)" % self.name class MyForm(object): b = Field() a = Field() c = Field() def __init__(self): self.fields = [] for field_name in dir(self): field = getattr(self, field_name) if isinstance(field, Field): field.name = field_name self.fields.append(field) self.fields.sort(key=operator.attrgetter('count')) m = MyForm() print m.fields # in defined order
Выход:
[Field('b'), Field('a'), Field('c')]
источник
В формах Django 1.7 используется OrderedDict, который не поддерживает оператор добавления. Значит, вам придется перестраивать словарь с нуля ...
class ChecklistForm(forms.ModelForm): class Meta: model = Checklist fields = ['name', 'email', 'website'] def __init__(self, guide, *args, **kwargs): self.guide = guide super(ChecklistForm, self).__init__(*args, **kwargs) new_fields = OrderedDict() for tier, tasks in guide.tiers().items(): questions = [(t['task'], t['question']) for t in tasks if 'question' in t] new_fields[tier.lower()] = forms.MultipleChoiceField( label=tier, widget=forms.CheckboxSelectMultiple(), choices=questions, help_text='desired set of site features' ) new_fields['name'] = self.fields['name'] new_fields['email'] = self.fields['email'] new_fields['website'] = self.fields['website'] self.fields = new_fields
источник
Для справки в будущем: все немного изменилось с момента появления новых форм. Это один из способов переупорядочения полей из базовых классов форм, которые вы не контролируете:
def move_field_before(form, field, before_field): content = form.base_fields[field] del(form.base_fields[field]) insert_at = list(form.base_fields).index(before_field) form.base_fields.insert(insert_at, field, content) return form
Кроме того, здесь есть небольшая документация по SortedDict
base_fields
: http://code.djangoproject.com/wiki/SortedDictисточник
Если либо
fields = '__all__'
:class AuthorForm(ModelForm): class Meta: model = Author fields = '__all__'
или
exclude
используются:class PartialAuthorForm(ModelForm): class Meta: model = Author exclude = ['title']
Затем Django ссылается на порядок полей, определенный в модели . Это просто зацепило меня, поэтому я подумал, что упомяну об этом. Он упоминается в документации ModelForm :
источник
Самый простой способ упорядочить поля в формах django 1.9 - использовать
field_order
в вашей форме Form.field_orderВот небольшой пример
class ContactForm(forms.Form): subject = forms.CharField(max_length=100) message = forms.CharField() sender = forms.EmailField() field_order = ['sender','message','subject']
Это покажет все в том порядке, который вы указали в
field_order
dict.источник
Использование
fields
во внутреннемMeta
классе - это то, что у меня сработалоDjango==1.6.5
:#!/usr/bin/env python # -*- coding: utf-8 -*- """ Example form declaration with custom field order. """ from django import forms from app.models import AppModel class ExampleModelForm(forms.ModelForm): """ An example model form for ``AppModel``. """ field1 = forms.CharField() field2 = forms.CharField() class Meta: model = AppModel fields = ['field2', 'field1']
Так просто, как, что.
источник
django.forms
не работаетЯ использовал это для перемещения полей:
def move_field_before(frm, field_name, before_name): fld = frm.fields.pop(field_name) pos = frm.fields.keys().index(before_name) frm.fields.insert(pos, field_name, fld)
Это работает в 1.5, и я вполне уверен, что это все еще работает в более поздних версиях.
источник
Это связано с мета-классом, который используется при определении класса формы. Я думаю, что он хранит внутренний список полей, и если вы вставите его в середину списка, он может сработать. Я давно не смотрел этот код.
источник