Django如何知道渲染表单字段的顺序?
如果我有一个Django表单,比如:
class ContactForm(forms.Form):
subject = forms.CharField(max_length=100)
message = forms.CharField()
sender = forms.EmailField()
当我调用这个表单实例的as_table()方法时,Django会按照上面指定的顺序来显示这些字段。
我想知道Django是怎么知道这些类变量的定义顺序的?
(另外,我该如何改变这个顺序,比如当我想在类的init方法中添加一个字段时?)
17 个回答
90
[注意:这个回答现在已经过时了 - 请查看下面的讨论和更新的回答]。
如果 f
是一个表单,它的字段可以通过 f.fields
来访问,这个字段是一个 django.utils.datastructures.SortedDict
类型(它会按照添加的顺序来展示项目)。在表单构建完成后,f.fields
会有一个叫做 keyOrder 的属性,这个属性是一个列表,里面包含了字段名称,按照应该展示的顺序排列。你可以把这个顺序设置成正确的顺序(不过要小心,确保不要漏掉任何项目或多加项目)。
下面是我在当前项目中创建的一个例子:
class PrivEdit(ModelForm):
def __init__(self, *args, **kw):
super(ModelForm, self).__init__(*args, **kw)
self.fields.keyOrder = [
'super_user',
'all_districts',
'multi_district',
'all_schools',
'manage_users',
'direct_login',
'student_detail',
'license']
class Meta:
model = Privilege
103
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']
40
我自己回答了自己的问题。为了将来参考,这里是答案:
在Django中,form.py
通过使用 __new__
方法做了一些神奇的事情,把你的类变量加载到 self.fields
中,并按照类中定义的顺序排列。self.fields
是一个Django的 SortedDict
实例(在 datastructures.py
中定义)。
所以如果你想要改变这个顺序,比如在我的例子中想让 sender 先出现,但又需要在 init 方法中添加它,你可以这样做:
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())))