django中表单验证
Form表单验证
Django表单的实例都有一个内置的is_valid()方法,用来验证接收的数据是否合法。如果所有数据都合法,那么该方法将返回True,并将所有的表单数据转存到它的一个叫做cleaned_data的属性中,该属性是以个字典类型数据。
.表单渲染格式 {{ form.as_table }} 将表单渲染成一个表格元素,每个输入框作为一个<tr>标签 {{ form.as_p }} 将表单的每个输入框包裹在一个<p>标签内 tags {{ form.as_ul }} 将表单渲染成一个列表元素,每个输入框作为一个<li>标签
lable标签可以用label_tag()方法生成
<div class="fieldWrapper"> {{ form.subject.errors }} {{ form.subject.label_tag }} {{ form.subject }} </div>
渲染表单错误信息
{{ form.name_of_field.errors }}模板语法,在表单里处理错误信息。对于每一个表单字段的错误,它其实会实际生成一个无序列表: <ul class="errorlist"> <li>Sender is required.</li> </ul 默认的CSS样式类errorlist,想进一步定制这个样式,可以循环错误列表里的内容,然后单独设置样式 {% if form.subject.errors %} <ol> {% for error in form.subject.errors %} <li><strong>{{ error|escape }}</strong></li> {% endfor %} </ol> {% endif %}
{{ field }} 属性
{{ field }}中的属性,由Django内置的模板语言提供 {{ field.label }} 字段对应的label信息 {{ field.label_tag }} 自动生成字段的label标签,注意与{{ field.label }}的区别。 {{ field.id_for_label }} 自定义字段标签的id {{ field.value }} 当前字段的值,比如一个Email字段的值someone@example.com {{ field.html_name }} 指定字段生成的input标签中name属性的值 {{ field.help_text }} 字段的帮助信息 {{ field.errors }} 包含错误信息的元素 {{ field.is_hidden }} 用于判断当前字段是否为隐藏的字段,如果是,返回True {{ field.field }} 返回字段的参数列表。例如{{ char_field.field.max_length }}
自动渲染与手动渲染
1 <form action="/lx/f/" method="post"> 2 {% csrf_token 3 4 <!-- 手动渲染 --> 5 {{ form.non_field_errors }} 6 <div class="fieldWrapper"> 7 {{ form.subject.errors }} 8 <label for="{{ form.subject.id_for_label }}">Email subject:</label> 9 {{ form.subject }} 10 </div> 11 <div class="fieldWrapper"> 12 {{ form.message.errors }} 13 <label for="{{ form.message.id_for_label }}">Your message:</label> 14 {{ form.message }} 15 </div> 16 <div class="fieldWrapper"> 17 <!-- 显示报错信息 --> 18 {{ form.sender.errors }} 19 <!-- 对错误信息处理后显示 --> 20 {% if form.sender.errors %} 21 <ol> 22 {% for error in form.sender.errors %} 23 <li><strong>{{ error|escape }}</strong></li> 24 {% endfor %} 25 </ol> 26 {% endif %} 27 28 <!-- 自定义label --> 29 <label for="{{ form.sender.id_for_label }}">Your email address:</label> 30 <!-- 自动生成字段的label标签 --> 31 {{ form.sender.label_tag }} 32 33 {{ form.sender }} 34 </div> 35 <div class="fieldWrapper"> 36 {{ form.cc_myself.errors }} 37 <label for="{{ form.cc_myself.id_for_label }}">CC yourself?</label> 38 {{ form.cc_myself }} 39 </div> 40 41 <!-- form模块自带的 --> 42 {{ form.as_p }} 43 44 <p><input type="submit" value="go"></p> 45 </form>
完整实例
1 import re 2 from django import forms 3 from django.core.exceptions import ValidationError 4 from django.contrib import admin 5 6 def mobile_validate(value): 7 mobile_re = re.compile(r'^(13[0-9]|15[0-9]|17[678]|18[0-9]|14[57])[0-9]{8}$') 8 if not mobile_re.match(value): 9 raise ValidationError('手机号码格式错误') 10 11 12 class PublishForm(forms.Form): 13 user_type_choice = ( 14 (0, u'普通用户'), 15 (1, u'高级用户'), 16 ) 17 18 user_type = forms.IntegerField(widget=forms.widgets.Select(choices=user_type_choice, 19 attrs={'class': "form-control"})) 20 21 title = forms.CharField(max_length=20, 22 min_length=5, 23 error_messages={ 24 'required': u'标题不能为空', 25 'min_length': u'标题最少为5个字符', 26 'max_length': u'标题最多为20个字符', 27 }, 28 widget=forms.TextInput(attrs={ 29 'class': "form-control", 30 'placeholder': u'标题5-20个字符', 31 })) 32 33 memo = forms.CharField(required=False, 34 max_length=256, 35 widget=forms.widgets.Textarea(attrs={ 36 'class': "form-control no-radius", 37 'placeholder': u'详细描述', 38 'rows': 3})) 39 40 phone = forms.CharField(validators=[mobile_validate,], 41 error_messages={'required': u'手机不能为空'}, 42 widget=forms.TextInput(attrs={ 43 'class': "form-control", 44 'placeholder': u'邮箱' 45 }))
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Title</title> 6 </head> 7 <body> 8 9 10 <form action="/publish/" method="post"> 11 {% csrf_token %} 12 <p>{{ obj.user_type }} <span>{{ ret.error.user_type.0.message }}</span></p> 13 <p>{{ obj.title }} <span>{{ ret.error.title.0.message }}</span> </p> 14 <p>{{ obj.memo }} <span>{{ ret.error.memo.0.message }}</span> </p> 15 <p>{{ obj.phone }} <span>{{ ret.error.phone.0.message }}</span> </p> 16 17 <p><input type="submit" value="提交"></p> 18 19 20 </form> 21 22 </body> 23 </html>
1 from .Form import PublishForm 2 import json 3 4 5 def publish(request): 6 ret = {'status': False, 'data': '', 'error': '', 'summary': ''} 7 request_form = PublishForm(request.POST) # 获取表单验证对象 8 print("request_form:",request_form) 9 if request.method == 'POST': 10 # request_form = PublishForm(request.POST) 11 if request_form.is_valid(): 12 request_dict = request_form.clean() 13 print('request_dict:', request_dict) 14 ret['status'] = True 15 else: 16 error_msg = request_form.errors.as_json() 17 ret["error"] = json.loads(error_msg) 18 print("ret:", ret) 19 return render(request, 'publish.html', {'obj': request_form, "ret": ret})
表单属性与方法
f = ContactForm() // ContactForm 为forms表单验证类 0. Form.is_bound 表单是否绑定属性,返回True/False 1. Form.clean() 可自定义表单验证功能 2. Form.is_valid() 执行绑定表单的数据验证工作,并返回一个表示数据是否合法True/False 3. Form.errors 保存错误信息字典 >>> f.errors {'sender': ['Enter a valid email address.'], 'subject': ['This field is required.']} 4. Form.errors.as_data() 返回一个字典,它将字段映射到原始的ValidationError实例 >>> f.errors.as_data() {'sender': [ValidationError(['Enter a valid email address.'])], 'subject': [ValidationError(['This field is required.'])]} 5. Form.errors.as_json(escape_html=False) 返回JSON序列化后的错误信息字典 >>> f.errors.as_json() {"sender": [{"message": "Enter a valid email address.", "code": "invalid"}], "subject": [{"message": "This field is required.", "code": "required"}]} 6. Form.add_error(field, error) 向表单特定字段添加错误信息,field参数为字段的名称。如果值为None,error将作为Form.non_field_errors()的一个非字段错误 7. Form.has_error(field, code=None) 判断某个字段是否具有指定code的错误。当code为None时,如果字段有任何错误它都将返回True。 8. Form.non_field_errors() 返回Form.errors中不是与特定字段相关联的错误。
检查表单数据是否被修改
1. Form.has_changed() 当你需要检查表单的数据是否从初始数据发生改变时,可以使用has_changed()方法。 >>> data = {'subject': 'hello', ... 'message': 'Hi there', ... 'sender': 'foo@example.com', ... 'cc_myself': True} >>> f = ContactForm(data, initial=data) >>> f.has_changed() False 提交表单后,我们可以重新构建表单并提供初始值,进行比较: >>> f = ContactForm(request.POST, initial=data) >>> f.has_changed() 如果request.POST与initial中的数据有区别,则返回False,否则返回True。 2. Form.changed_data 返回有变化的字段的列表。 >>> f = ContactForm(request.POST, initial=data) >>> if f.has_changed(): ... print("The following fields changed: %s" % ", ".join(f.changed_data))
访问cleaned_data
Form.cleaned_data Form类中的每个字段不仅负责验证数据,还负责将它们转换为正确的格式。 例如,DateField将输入转换为Python的datetime.date对象。 无论你传递的是普通字符串'1994-07-15'、DateField格式的字符串、datetime.date对象、还是其它格式的数字,Django将始终把它们转换成datetime.date对象。 一旦你创建一个Form实例并通过验证后,你就可以通过它的cleaned_data属性访问干净的数据: >>> data = {'subject': 'hello', ... 'message': 'Hi there', ... 'sender': 'foo@example.com', ... 'cc_myself': True} >>> f = ContactForm(data) >>> f.is_valid() True >>> f.cleaned_data {'cc_myself': True, 'message': 'Hi there', 'sender': 'foo@example.com', 'subject': 'hello'} 如果你的数据没有通过验证,cleaned_data字典中只包含合法的字段: >>> data = {'subject': '', ... 'message': 'Hi there', ... 'sender': 'invalid email address', ... 'cc_myself': True} >>> f = ContactForm(data) >>> f.is_valid() False >>> f.cleaned_data {'cc_myself': True, 'message': 'Hi there'} cleaned_data字典始终只包含Form中定义的字段,即使你在构建Form时传递了额外的数据。 在下面的例子中,我们传递了一组额外的字段给ContactForm构造函数,但是cleaned_data将只包含表单的字段: >>> data = {'subject': 'hello', ... 'message': 'Hi there', ... 'sender': 'foo@example.com', ... 'cc_myself': True, ... 'extra_field_1': 'foo', ... 'extra_field_2': 'bar', ... 'extra_field_3': 'baz'} >>> f = ContactForm(data) >>> f.is_valid() True >>> f.cleaned_data # Doesn't contain extra_field_1, etc. {'cc_myself': True, 'message': 'Hi there', 'sender': 'foo@example.com', 'subject': 'hello'} 当Form通过验证后,cleaned_data将包含所有字段的键和值,即使传递的数据中没有提供某些字段的值。 在下面的例子中,提供的实际数据中不包含nick_name字段,但是cleaned_data任然包含它,只是值为空: >>> from django import forms >>> class OptionalPersonForm(forms.Form): ... first_name = forms.CharField() ... last_name = forms.CharField() ... nick_name = forms.CharField(required=False) >>> data = {'first_name': 'John', 'last_name': 'Lennon'} >>> f = OptionalPersonForm(data) >>> f.is_valid() True >>> f.cleaned_data {'nick_name': '', 'first_name': 'John', 'last_name': 'Lennon'}
表单的HTML生成方式
1 Form的第二个任务是将它渲染成HTML代码,默认情况下,根据form类中字段的编写顺序,在HTML中以同样的顺序罗列。 我们可以通过print方法展示出来: 2 3 >>> f = ContactForm() 4 >>> print(f) 5 <tr><th><label for="id_subject">Subject:</label></th><td><input id="id_subject" type="text" name="subject" maxlength="100" required /></td></tr> 6 <tr><th><label for="id_message">Message:</label></th><td><input type="text" name="message" id="id_message" required /></td></tr> 7 <tr><th><label for="id_sender">Sender:</label></th><td><input type="email" name="sender" id="id_sender" required /></td></tr> 8 <tr><th><label for="id_cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id="id_cc_myself" /></td></tr> 9 如果表单是绑定的,输出的HTML将包含数据。 10 11 >>> data = {'subject': 'hello', 12 ... 'message': 'Hi there', 13 ... 'sender': 'foo@example.com', 14 ... 'cc_myself': True} 15 >>> f = ContactForm(data) 16 >>> print(f) 17 <tr><th><label for="id_subject">Subject:</label></th><td><input id="id_subject" type="text" name="subject" maxlength="100" value="hello" required /></td></tr> 18 <tr><th><label for="id_message">Message:</label></th><td><input type="text" name="message" id="id_message" value="Hi there" required /></td></tr> 19 <tr><th><label for="id_sender">Sender:</label></th><td><input type="email" name="sender" id="id_sender" value="foo@example.com" required /></td></tr> 20 <tr><th><label for="id_cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id="id_cc_myself" checked /></td></tr> 21 注意事项: 22 23 为了灵活性,输出不包含<table>和</table>、<form>和</form>以及<input type="submit">标签。 需要我们程序员手动添加它们。 24 每个字段类型都由一个默认的HTML标签展示。注意,这些只是默认的,可以使用Widget 特别指定。 25 每个HTML标签的name属性名直接从ContactForm类中获取。 26 form使用HTML5语法,顶部需添加<!DOCTYPE html>说明。 27 1. 渲染成文字段落as_p() 28 Form.as_p() 29 30 该方法将form渲染成一系列<p>标签,每个<p>标签包含一个字段; 31 32 >>> f = ContactForm() 33 >>> f.as_p() 34 '<p><label for="id_subject">Subject:</label> <input id="id_subject" type="text" name="subject" maxlength="100" required /></p>\n<p><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" required /></p>\n<p><label for="id_sender">Sender:</label> <input type="text" name="sender" id="id_sender" required /></p>\n<p><label for="id_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_cc_myself" /></p>' 35 >>> print(f.as_p()) 36 <p><label for="id_subject">Subject:</label> <input id="id_subject" type="text" name="subject" maxlength="100" required /></p> 37 <p><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" required /></p> 38 <p><label for="id_sender">Sender:</label> <input type="email" name="sender" id="id_sender" required /></p> 39 <p><label for="id_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_cc_myself" /></p> 40 2. 渲染成无序列表as_ul() 41 Form.as_ul() 42 43 该方法将form渲染成一系列<li>标签,每个<li>标签包含一个字段。但不会自动生成</ul>和<ul>,所以你可以自己指定<ul>的任何HTML属性: 44 45 >>> f = ContactForm() 46 >>> f.as_ul() 47 '<li><label for="id_subject">Subject:</label> <input id="id_subject" type="text" name="subject" maxlength="100" required /></li>\n<li><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" required /></li>\n<li><label for="id_sender">Sender:</label> <input type="email" name="sender" id="id_sender" required /></li>\n<li><label for="id_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_cc_myself" /></li>' 48 >>> print(f.as_ul()) 49 <li><label for="id_subject">Subject:</label> <input id="id_subject" type="text" name="subject" maxlength="100" required /></li> 50 <li><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" required /></li> 51 <li><label for="id_sender">Sender:</label> <input type="email" name="sender" id="id_sender" required /></li> 52 <li><label for="id_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_cc_myself" /></li> 53 3. 渲染成表格as_table() 54 Form.as_table() 55 56 渲染成HTML表格。它与print完全相同,事实上,当你print一个表单对象时,在后台调用的就是as_table()方法: 57 58 >>> f = ContactForm() 59 >>> f.as_table() 60 '<tr><th><label for="id_subject">Subject:</label></th><td><input id="id_subject" type="text" name="subject" maxlength="100" required /></td></tr>\n<tr><th><label for="id_message">Message:</label></th><td><input type="text" name="message" id="id_message" required /></td></tr>\n<tr><th><label for="id_sender">Sender:</label></th><td><input type="email" name="sender" id="id_sender" required /></td></tr>\n<tr><th><label for="id_cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id="id_cc_myself" /></td></tr>' 61 >>> print(f) 62 <tr><th><label for="id_subject">Subject:</label></th><td><input id="id_subject" type="text" name="subject" maxlength="100" required /></td></tr> 63 <tr><th><label for="id_message">Message:</label></th><td><input type="text" name="message" id="id_message" required /></td></tr> 64 <tr><th><label for="id_sender">Sender:</label></th><td><input type="email" name="sender" id="id_sender" required /></td></tr> 65 <tr><th><label for="id_cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id="id_cc_myself" /></td></tr>
为错误信息添加CSS样式
Form.error_css_class Form.required_css_class 为一些特别强调的或者需要额外显示的内容设置醒目的CSS样式是一种常用做法,也是非常有必要的。比如给必填字段加粗显示,设置错误文字为红色等等。 Form.error_css_class和Form.required_css_class属性就是做这个用的: from django import forms class ContactForm(forms.Form): error_css_class = 'error' required_css_class = 'required' # ... and the rest of your fields here 属性名是固定的,不可变(废话),通过赋值不同的字符串,表示给这两类属性添加不同的CSS的class属性。以后Django在渲染form成HTML时将自动为error和required行添加对应的CSS样式。 上面的例子,其HTML看上去将类似: >>> f = ContactForm(data) >>> print(f.as_table()) <tr class="required"><th><label class="required" for="id_subject">Subject:</label> ... <tr class="required"><th><label class="required" for="id_message">Message:</label> ... <tr class="required error"><th><label class="required" for="id_sender">Sender:</label> ... <tr><th><label for="id_cc_myself">Cc myself:<label> ... >>> f['subject'].label_tag() <label class="required" for="id_subject">Subject:</label> >>> f['subject'].label_tag(attrs={'class': 'foo'}) <label for="id_subject" class="foo required">Subject:</label>
将上传的文件绑定到表单
处理带有FileField和ImageField字段的表单比普通的表单要稍微复杂一点。 首先,为了上传文件,你需要确保你的<form>元素定义enctype为"multipart/form-data": <form enctype="multipart/form-data" method="post" action="/foo/"> 其次,当你使用表单时,你需要绑定文件数据。文件数据的处理与普通的表单数据是分开的,所以如果表单包含FileField和ImageField,绑定表单时你需要指定第二个参数,参考下面的例子。 # 为表单绑定image字段 >>> from django.core.files.uploadedfile import SimpleUploadedFile >>> data = {'subject': 'hello', ... 'message': 'Hi there', ... 'sender': 'foo@example.com', ... 'cc_myself': True} >>> file_data = {'mugshot': SimpleUploadedFile('face.jpg', <file data>)} >>> f = ContactFormWithMugshot(data, file_data) 实际上,一般使用request.FILES作为文件数据的源: # Bound form with an image field, data from the request >>> f = ContactFormWithMugshot(request.POST, request.FILES) 构造一个未绑定的表单和往常一样,将表单数据和文件数据同时省略: # Unbound form with an image field >>> f = ContactFormWithMugshot()
创建Widget时使用Widget.attrs参数实现CSS样式
1 class CommentForm(forms.Form): 2 name = forms.CharField(widget=forms.TextInput(attrs={'class': 'special'})) 3 url = forms.URLField() 4 comment = forms.CharField(widget=forms.TextInput(attrs={'size': '40'}))
ModelForm表单验证
核心用法
首先从django.forms导入ModelForm; 编写一个自己的类,继承ModelForm; 在新类里,设置元类Meta; 在Meta中,设置model属性为你要关联的ORM模型,这里是Article; 在Meta中,设置fields属性为你要在表单中使用的字段列表; 列表里的值,应该是ORM模型model中的字段名。
表单属性设置中的映射关系
如果模型字段设置blank=True,那么表单字段的required设置为False。 否则,required=True。 表单字段的label属性根据模型字段的verbose_name属性设置,并将第一个字母大写。 如果模型的某个字段设置了editable=False属性,那么它表单类中将不会出现该字段。 表单字段的help_text设置为模型字段的help_text。 如果模型字段设置了choices参数,那么表单字段的widget属性将设置成Select框,其选项来自模型字段的choices。 选单中通常会包含一个空选项,并且作为默认选择。 如果该字段是必选的,它会强制用户选择一个选项。 如果模型字段具有default参数,则不会添加空选项到选单中。
1 from django.db import models 2 from django.forms import ModelForm 3 4 TITLE_CHOICE = ( 5 ('MR', 'Mr.'), 6 ('MS', 'Ms.'), 7 ('MRS', 'Mrs.'), 8 ) 9 10 11 class Author(models.Model): 12 name = models.CharField(max_length=100) 13 title = models.CharField(max_length=3, choices=TITLE_CHOICE) 14 birth_date = models.DateField(blank=True, null=True) 15 16 def __str__(self): 17 return self.name 18 19 20 class Book(models.Model): 21 name = models.CharField(max_length=100) 22 authors = models.ManyToManyField(Author) 23 24 ########## ModelForm ########### 25 26 class AuthorForm(ModelForm): 27 class Meta: 28 model = Author 29 fields = ['name', 'title', 'birth_date'] 30 31 32 class BookForm(ModelForm): 33 class Meta: 34 fields = ['name', 'authors'] 35 36 ######## Forms ############## 37 38 from django import forms 39 40 class AuthorForm(forms.Form): 41 name = forms.CharField(max_length=100) 42 title = forms.CharField( 43 max_length=3, 44 widget=forms.Select(choices=TITLE_CHOICES), 45 ) 46 birth_date = forms.DateField(required=False) 47 48 class BookForm(forms.Form): 49 name = forms.CharField(max_length=100) 50 authors = forms.ModelMultipleChoiceField(queryset=Author.objects.all())
ModelForm的字段选择
1 fields属性 2 用ModelForm的fields属性,在赋值的列表内,一个一个将要使用的字段添加进去。这样做的好处是,安全可靠。 3 4 __all__属性 5 将fields属性的值设为__all__,表示将映射的模型中的全部字段都添加到表单类中来。 6 7 from django.forms import ModelForm 8 9 class AuthorForm(ModelForm): 10 class Meta: 11 model = Author 12 fields = '__all__' 13 14 exclude属性: 15 16 表示将model中,除了exclude属性中列出的字段之外的所有字段,添加到表单类中作为表单字段。 17 18 class PartialAuthorForm(ModelForm): 19 class Meta: 20 model = Author 21 exclude = ['title'] 22 因为Author模型有3个字段name、birth_date和birth_date,上面的例子会让title和name出现在表单中
自定义ModelForm字段
1 使用Meta类内部的widgets属性接收一个数据字典,其中每个元素的键必须是模型中的字段名之一,键值就是我们要自定义的内容。 2 3 想要让Author模型中的name字段的类型从CharField更改为<textarea>,而不是默认的<input type="text">,可以如下重写字段的Widget: 4 5 from django.forms import ModelForm, Textarea 6 from myapp.models import Author 7 8 class AuthorForm(ModelForm): 9 class Meta: 10 model = Author 11 fields = ('name', 'title', 'birth_date') 12 widgets = { 13 'name': Textarea(attrs={'cols': 80, 'rows': 20}), # 关键是这一行 14 } 15 16 17 Meta类内部error_messages、help_texts和labels属性: 18 19 from django.utils.translation import ugettext_lazy as _ 20 21 class AuthorForm(ModelForm): 22 class Meta: 23 model = Author 24 fields = ('name', 'title', 'birth_date') 25 labels = { 26 'name': _('Writer'), 27 } 28 help_texts = { 29 'name': _('Some useful help text.'), 30 } 31 error_messages = { 32 'name': { 33 'max_length': _("This writer's name is too long."), 34 }, 35 } 36 可以指定field_classes属性将字段类型设置为你自己写的表单字段类型。 37 38 例如,如果你想为slug字段使用MySlugFormField,可以像下面这样: 39 40 from django.forms import ModelForm 41 from myapp.models import Article 42 43 class ArticleForm(ModelForm): 44 class Meta: 45 model = Article 46 fields = ['pub_date', 'headline', 'content', 'reporter', 'slug'] 47 field_classes = { 48 'slug': MySlugFormField, 49 } 50 51 想完全控制一个字段,包括它的类型,验证器,是否必填等等。可以显式地声明或指定这些性质,就像在普通表单中一样。 52 想要指定某个字段的验证器,可以显式定义字段并设置它的validators参数: 53 54 from django.forms import ModelForm, CharField 55 from myapp.models import Article 56 57 class ArticleForm(ModelForm): 58 slug = CharField(validators=[validate_slug]) 59 60 class Meta: 61 model = Article 62 fields = ['pub_date', 'headline', 'content', 'reporter', 'slug']
启用字段本地化
1 默认情况下,ModelForm中的字段不会本地化它们的数据。可以使用Meta类的localized_fields属性来启用字段的本地化功能。 2 3 >>> from django.forms import ModelForm 4 >>> from myapp.models import Author 5 >>> class AuthorForm(ModelForm): 6 ... class Meta: 7 ... model = Author 8 ... localized_fields = ('birth_date',) 9 如果localized_fields设置为__all__这个特殊的值,所有的字段都将本地化。
表单继承
1 ModelForms是可以被继承的。子模型表单可以添加额外的方法和属性,比如下面的例子: 2 3 >>> class EnhancedArticleForm(ArticleForm): 4 ... def clean_pub_date(self): 5 ... ... 6 以上创建了一个ArticleForm的子类EnhancedArticleForm,并增加了一个clean_pub_date方法。 7 8 还可以修改Meta.fields或Meta.exclude列表,只要继承父类的Meta类,如下所示: 9 10 >>> class RestrictedArticleForm(EnhancedArticleForm): 11 ... class Meta(ArticleForm.Meta): 12 ... exclude = ('body',)
提供初始值
1 可以在实例化一个表单时通过指定initial参数来提供表单中数据的初始值。 2 3 >>> article = Article.objects.get(pk=1) 4 >>> article.headline 5 'My headline' 6 >>> form = ArticleForm(initial={'headline': 'Initial headline'}, instance=article) 7 >>> form['headline'].value() 8 'Initial headline'
完整实例
1 class UserModelForm(forms.ModelForm): 2 class Meta: 3 model = models.User 4 # fields = ('username', 'email') # 展示的列 5 exclude = ('email',) # 排除列 6 7 widgets = { 8 'email': forms.PasswordInput(attrs={'class': "alex"}), 9 } 10 11 12 def user(request): 13 if request.method == 'GET': 14 obj = UserModelForm() 15 return render(request, 'lx/user.html', {'obj': obj}) 16 elif request.method == 'POST': 17 obj = UserModelForm(request.POST) 18 if obj.is_valid(): 19 print('obj:', obj) 20 return render(request, 'lx/user.html', {'obj': obj}) 21 else: 22 print('obj.error:', obj.errors) 23 return render(request, 'lx/user.html', {'obj': obj, 'error': obj.errors})
1 class User(models.Model): 2 username = models.CharField(max_length=20) 3 pwd = models.CharField(max_length=30) 4 email = models.EmailField()
1 <form action="/lx/user/" method="post"> 2 {% csrf_token %} 3 <p>{{ obj }}</p> 4 <p>{{ error }}</p> 5 <input type="submit" value="go"> 6 </form>