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                             }))
Form.py
 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>
publish.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})
views.py

表单属性与方法

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>
View Code

为错误信息添加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())
Forms与ModelForm对比

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']
自定义ModelForm字段

启用字段本地化

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})
views.py
1 class User(models.Model):
2     username = models.CharField(max_length=20)
3     pwd = models.CharField(max_length=30)
4     email = models.EmailField()
models.py
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>
user.html

 

posted @ 2018-07-02 15:18  ︻◣_蝸犇り~  阅读(277)  评论(0编辑  收藏  举报