如果我有一个Django表格,例如:
class ContactForm(forms.Form): subject = forms.CharField(max_length=100) message = forms.CharField() sender = forms.EmailField()
我调用此表单实例的as_table()方法,Django将按照上面指定的顺序呈现字段.
我的问题是Django如何知道定义类变量的顺序?
(另外我如何覆盖这个顺序,例如当我想从classe的init方法中添加一个字段?)
[注意:这个答案现在已经过时了 - 请参阅下面的讨论,以及最近的答案].
如果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
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
是一个Django SortedDict
实例(在中定义datastructures.py
).
所以要覆盖它,比如在我的例子中你希望发送者先来但需要在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())))
字段按ModelClass._meta.fields中定义的顺序列出.但是如果要在Form中更改顺序,可以使用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'] )
这个技巧用于Github上的 Django Admin PasswordChangeForm
:Source
表单字段具有创建顺序的属性,称为creation_counter
..fields
属性是一个字典,所以简单地添加到字典和更改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')]