form组件

form组件

一、form组件简介

  1、form在组件的两大功能:

  • 数据重置
  • 校验规则

  2、form组件于传统form表单对比

  • 当我们用传统的form表单提交时会刷新页面,如果这个我们表单中的某项填错了,刷新后我们正确的选项也没有了.
  • 传统的form表单需要我们自己亲自校验每一项,其工作量太大
  • form组件前端自动生成表单元素。

  • form组件可自动验证表单内容信息。

  • form组件可保留用户上次输入的信息。

但是form表单的输出不包含submit 按钮,和表单的<form> 标签。 你必须自己提供。

二、form组件生成方法(三种)

1、方法一

1
2
3
4
5
6
7
<form action="/login/" method="post" novalidate>
    {% csrf_token %}
    {{ form_obj.as_p }}                  #{{ form.as_p }}将它们渲染在<p> 标签中       
    {{ form_obj.as_table }}                #{{ form.as_table }} 以表格的形式将它们渲染在<tr> 标签中
    {{ form_obj.as_ul }}                  #{{ form.as_ul }将它们渲染在<li> 标签中
    <p><input type="submit" value="提交"></p>
</form>But:你必须自己提供<ul> 或 <table> 元素。

 方式一示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#HTML
 
<form action="/login/" method="post" novalidate>     #novalidate不对输入进行验证的表单
    {% csrf_token %}
    {{ form_obj.as_p }}
    <p><input type="submit" value="提交"></p>
</form>
 
 
#views
 
from . import models
from django import forms
from django.forms import widgets
from django.core.exceptions import NON_FIELD_ERRORS,ValidationError
 
 
class LoginForm(forms.Form):
    user = forms.CharField(max_length=12,min_length=5,
                        label="用户名",
                        help_text="6~16个字符,区分大小写",
                        error_messages={"required":"不能为空",
                                        "min_length":"最小长度为5",})
 
    pwd = forms.CharField(
        help_text= "6~16个字符,区分大小写",
        error_messages={
            "invalid":"格式错误"
 
        },
        widget = widgets.PasswordInput(attrs={"class":"active"})
 
    )<br><br>def login(request):<br><br>    if request.method == "POST":<br><br>        form_obj = LoginForm(request.POST)<br>        if form_obj.is_valid():<br>            # 数据全部合格<br>            #取出合格数据<br>            return HttpResponse("success")<br>        else:<br>            # 最少存在一个字段的错误<br>            #取出错误信息<br>            return render(request, "login.html", {"form_obj": form_obj})    #存放错误信息<br>    form_obj = LoginForm()<br>    return render(request,"login.html",{"form_obj":form_obj})

  

2、方法二(在任意标签中渲染)

1
2
3
4
5
6
7
8
9
10
11
12
13
<form action="/login/" method="post" novalidate>    {# novalidate不对输入进行验证的表单
   {% csrf_token %}
    <div>
    <label for="user">用户名:</label>
    {{ form_obj.user }}
        <span>{{ form_obj.errors.user.0 }}</span>
    </div>
    <div>
    <label for="pwd">密码:</label>
    {{ form_obj.pwd }}<span>{{ form_obj.errors.pwd.0 }}</span>
    </div>
    <p><input type="submit" value="提交"><span>{{ ret.0 }}</span></p>
</form>

  

 

3、方法三(for循环生成)

1
2
3
4
5
6
7
8
<form action="/login/" method="post" novalidate>
   {% csrf_token %}
    {% for field in form_obj %}
        <div>
        <lable>{{ field.label }}</lable>
        {{ field }}
        </div>
    {% endfor %}

  

 三、表单验证的model加form方法

调取数据库进行验证:在models.py文件中创建一个类,在数据库中生成

创建的一个类:

 

生成的数据库:

 

 

views及forms代码:

form组件代码可建立一个form.py文件,然后在views中引入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
#form代码
 
class RegForm(forms.Form):
    user = forms.CharField(min_length=5,max_length=10,
                           error_messages={"required": "不能为空",
                                           "min_length": "最小长度为5",
                                           })
    pwd = forms.CharField(
        help_text="6~16个字符,区分大小写",
        widget=widgets.PasswordInput(attrs={"class": "active"}),
        error_messages={"required": "不能为空",
                        })
 
    repwd = forms.CharField(
        help_text="6~16个字符,区分大小写",
        widget=widgets.PasswordInput(attrs={"class": "active"}),
        error_messages={"required": "不能为空",
                        }
    )
    email = forms.EmailField(
                error_messages={"required": "不能为空",
                                "invalid": "格式错误"
                                },
    )
    tel = forms.CharField(
        error_messages={"required": "不能为空",
                        }
    )
    def clean_user(self):
        val = self.cleaned_data.get("user")
        if val.isdigit():
            raise ValidationError("不能为数字")
        else:
            ret = UserInfo.objects.filter(name=val)
            if not ret:
                return val
            else:
                raise ValidationError("该用户已注册")
 
    def clean_tel(self):
        val = self.cleaned_data.get("tel")
        import re               #引入正则
 
        ret = re.search("^1[3578]\d{9}$",val)
        if ret:
            return val
        else:
            raise ValidationError("手机号码格式")
 
    def clean(self):
        repwd = self.cleaned_data.get("repwd")
        pwd = self.cleaned_data.get("pwd")
 
        if repwd == pwd:
            return self.cleaned_data
        else:
            raise ValidationError("两次密码不一致")
 
 
views代码
 
def reg(request):
    if request.method == "POST":
        reg_form = RegForm(request.POST)
        if reg_form.is_valid():
            name = reg_form.cleaned_data.get("user")
            pwd = reg_form.cleaned_data.get("pwd")
            UserInfo.objects.create(name=name,pwd=pwd)
            return redirect("/login/")
        else:
            all_error = reg_form.errors.get("__all__")
            return render(request, "register.html", {"reg_form": reg_form,"all_error":all_error})
 
    reg_form = RegForm()
    return render(request,"register.html",{"reg_form":reg_form})
 
 
 
 
 
#html代码
 
<h1>注册页面</h1>
    <form action="/reg/" method="post" novalidate>
        {% csrf_token %}
        {% for field in reg_form %}
            <div>
                <lable>{{ field.label }}</lable>
                {{ field }}
                <span>{{ field.errors.0 }}</span>
                {% if field.label == "Repwd" %}        {#field.label == "Repwd" Repwd是页面渲染后的名称#}
                    <span>{{ all_error.0 }}</span>
                {% endif %}
            </div>
        {% endfor %}
    <p><input style="margin-left: 100px" type="submit" value="注册">
 
    </form>

四、form组件中常用字段及插件 

    Django中form的创建涉及到一些字段及插件

    字段用于对用户请求数据的验证,插件用于自动生成HTML

1.Django内置字段

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
Field
        required=True,               是否允许为空
        widget=None,                 HTML插件
        label=None,                  用于生成Label标签或显示内容
        initial=None,                初始值
        help_text='',                帮助信息(在标签旁边显示)
        error_messages=None,         错误信息 {'required': '不能为空', 'invalid': '格式错误'}
        show_hidden_initial=False,   是否在当前插件后面再加一个隐藏的且具有默认值的插件(可用于检验两次输入是否一直)
        validators=[],               自定义验证规则
        localize=False,              是否支持本地化
        disabled=False,              是否可以编辑
        label_suffix=None            Label内容后缀
 
 
    CharField(Field)
        max_length=None,             最大长度
        min_length=None,             最小长度
        strip=True                   是否移除用户输入空白
 
    IntegerField(Field)
        max_value=None,              最大值
        min_value=None,              最小值
 
    FloatField(IntegerField)
        ...
 
    DecimalField(IntegerField)
        max_value=None,              最大值
        min_value=None,              最小值
        max_digits=None,             总长度
        decimal_places=None,         小数位长度
 
    BaseTemporalField(Field)
        input_formats=None          时间格式化
 
    DateField(BaseTemporalField)    格式:2015-09-01
    TimeField(BaseTemporalField)    格式:11:12
    DateTimeField(BaseTemporalField)格式:2015-09-01 11:12
 
    DurationField(Field)            时间间隔:%d %H:%M:%S.%f
        ...
 
    RegexField(CharField)
        regex,                      自定制正则表达式
        max_length=None,            最大长度
        min_length=None,            最小长度
        error_message=None,         忽略,错误信息使用 error_messages={'invalid': '...'}
 
    EmailField(CharField)
        ...
 
    FileField(Field)
        allow_empty_file=False     是否允许空文件
 
    ImageField(FileField)
        ...
        注:需要PIL模块,pip3 install Pillow
        以上两个字典使用时,需要注意两点:
            - form表单中 enctype="multipart/form-data"
            - view函数中 obj = MyForm(request.POST, request.FILES)
 
    URLField(Field)
        ...
 
 
    BooleanField(Field)
        ...
 
    NullBooleanField(BooleanField)
        ...
 
    ChoiceField(Field)
        ...
        choices=(),                选项,如:choices = ((0,'上海'),(1,'北京'),)
        required=True,             是否必填
        widget=None,               插件,默认select插件
        label=None,                Label内容
        initial=None,              初始值
        help_text='',              帮助提示
 
 
    ModelChoiceField(ChoiceField)
        ...                        django.forms.models.ModelChoiceField
        queryset,                  # 查询数据库中的数据
        empty_label="---------",   # 默认空显示内容
        to_field_name=None,        # HTML中value的值对应的字段
        limit_choices_to=None      # ModelForm中对queryset二次筛选
 
    ModelMultipleChoiceField(ModelChoiceField)
        ...                        django.forms.models.ModelMultipleChoiceField
 
 
 
    TypedChoiceField(ChoiceField)
        coerce = lambda val: val   对选中的值进行一次转换
        empty_value= ''            空值的默认值
 
    MultipleChoiceField(ChoiceField)
        ...
 
    TypedMultipleChoiceField(MultipleChoiceField)
        coerce = lambda val: val   对选中的每一个值进行一次转换
        empty_value= ''            空值的默认值
 
    ComboField(Field)
        fields=()                  使用多个验证,如下:即验证最大长度20,又验证邮箱格式
                                   fields.ComboField(fields=[fields.CharField(max_length=20), fields.EmailField(),])
 
    MultiValueField(Field)
        PS: 抽象类,子类中可以实现聚合多个字典去匹配一个值,要配合MultiWidget使用
 
    SplitDateTimeField(MultiValueField)
        input_date_formats=None,   格式列表:['%Y--%m--%d', '%m%d/%Y', '%m/%d/%y']
        input_time_formats=None    格式列表:['%H:%M:%S', '%H:%M:%S.%f', '%H:%M']
 
    FilePathField(ChoiceField)     文件选项,目录下文件显示在页面中
        path,                      文件夹路径
        match=None,                正则匹配
        recursive=False,           递归下面的文件夹
        allow_files=True,          允许文件
        allow_folders=False,       允许文件夹
        required=True,
        widget=None,
        label=None,
        initial=None,
        help_text=''
 
    GenericIPAddressField
        protocol='both',           both,ipv4,ipv6支持的IP格式
        unpack_ipv4=False          解析ipv4地址,如果是::ffff:192.0.2.1时候,可解析为192.0.2.1, PS:protocol必须为both才能启用
 
    SlugField(CharField)           数字,字母,下划线,减号(连字符)
        ...
 
    UUIDField(CharField)           uuid类型
        ...
 
    # 注:UUID是根据MAC以及当前时间等创建的不重复的随机字符串
       >>> import uuid
 
        # make a UUID based on the host ID and current time
        >>> uuid.uuid1()    # doctest: +SKIP
        UUID('a8098c1a-f86e-11da-bd1a-00112444be1e')
 
        # make a UUID using an MD5 hash of a namespace UUID and a name
        >>> uuid.uuid3(uuid.NAMESPACE_DNS, 'python.org')
        UUID('6fa459ea-ee8a-3ca4-894e-db77e160355e')
 
        # make a random UUID
        >>> uuid.uuid4()    # doctest: +SKIP
        UUID('16fd2706-8baf-433b-82eb-8c7fada847da')
 
        # make a UUID using a SHA-1 hash of a namespace UUID and a name
        >>> uuid.uuid5(uuid.NAMESPACE_DNS, 'python.org')
        UUID('886313e1-3b8a-5372-9b90-0c9aee199e5d')
 
        # make a UUID from a string of hex digits (braces and hyphens ignored)
        >>> x = uuid.UUID('{00010203-0405-0607-0809-0a0b0c0d0e0f}')
 
        # convert a UUID to a string of hex digits in standard form
        >>> str(x)
        '00010203-0405-0607-0809-0a0b0c0d0e0f'
 
        # get the raw 16 bytes of the UUID
        >>> x.bytes
        b'\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f'
 
        # make a UUID from a 16-byte string
        >>> uuid.UUID(bytes=x.bytes)
        UUID('00010203-0405-0607-0809-0a0b0c0d0e0f')

2.Django内置插件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
   ------------------
   TextInput(Input)
   NumberInput(TextInput)
   EmailInput(TextInput)
   URLInput(TextInput)
   PasswordInput(TextInput)
   HiddenInput(TextInput)
   Textarea(Widget)
   DateInput(DateTimeBaseInput)
   DateTimeInput(DateTimeBaseInput)
   TimeInput(DateTimeBaseInput)
   CheckboxInput
   Select
   NullBooleanSelect
   SelectMultiple
   RadioSelect
   CheckboxSelectMultiple
   FileInput
   ClearableFileInput
   MultipleHiddenInput
   SplitDateTimeWidget
   SplitHiddenDateTimeWidget
   SelectDateWidget
   ------------------
常用选择插件
       # 单radio,值为字符串
       # user = fields.CharField(
       #     initial=2,
       #     widget=widgets.RadioSelect(choices=((1,'上海'),(2,'北京'),))
       # )
 
       # 单radio,值为字符串
       # user = fields.ChoiceField(
       #     choices=((1, '上海'), (2, '北京'),),
       #     initial=2,
       #     widget=widgets.RadioSelect
       # )
 
       # 单select,值为字符串
       # user = fields.CharField(
       #     initial=2,
       #     widget=widgets.Select(choices=((1,'上海'),(2,'北京'),))
       # )
 
       # 单select,值为字符串
       # user = fields.ChoiceField(
       #     choices=((1, '上海'), (2, '北京'),),
       #     initial=2,
       #     widget=widgets.Select
       # )
 
       # 多选select,值为列表
       # user = fields.MultipleChoiceField(
       #     choices=((1,'上海'),(2,'北京'),),
       #     initial=[1,],
       #     widget=widgets.SelectMultiple
       # )
 
 
       # 单checkbox
       # user = fields.CharField(
       #     widget=widgets.CheckboxInput()
       # )
 
 
       # 多选checkbox,值为列表
       # user = fields.MultipleChoiceField(
       #     initial=[2, ],
       #     choices=((1, '上海'), (2, '北京'),),
       #     widget=widgets.CheckboxSelectMultiple
       # )
 
   # 在使用选择标签时,需要注意choices的选项可以从数据库中获取,但是由于静态字段×××获取的值
   # 无法实时更新×××,那么需要自定义构造方法从而达到此目的。
   方法一.
       from django.forms import Form
       from django.forms import widgets
       from django.forms import fields
       from django.core.validators import RegexValidator
 
       class MyForm(Form):
 
           user = fields.ChoiceField(
               # choices=((1, '上海'), (2, '北京'),),
               initial=2,
               widget=widgets.Select
           )
 
           def __init__(self, *args, **kwargs):
               super(MyForm,self).__init__(*args, **kwargs)
               # self.fields['user'].widget.choices = ((1, '上海'), (2, '北京'),)
               # 或
               self.fields['user'].widget.choices = models.Classes.objects.all().value_list('id','caption')
   方法二.
       # 使用django提供的ModelChoiceField和ModelMultipleChoiceField字段来实现
       from django import forms
       from django.forms import fields
       from django.forms import widgets
       from django.forms import models as form_model
       from django.core.exceptions import ValidationError
       from django.core.validators import RegexValidator
 
       class FInfo(forms.Form):
           authors = form_model.ModelMultipleChoiceField(queryset=models.NNewType.objects.all())
           # authors = form_model.ModelChoiceField(queryset=models.NNewType.objects.all())

五、form组件的校验

  form组件自定义校验规则:

自定义校验规则中也会使用到局部钩子 跟 全局钩子  前边小例子中有涉及

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
方式一:
    from django.forms import Form
    from django.forms import widgets
    from django.forms import fields
    from django.core.validators import RegexValidator<br>   form diango.
 
    class MyForm(Form):
        user = fields.CharField(
            validators=[RegexValidator(r'^[0-9]+$', '请输入数字'), RegexValidator(r'^159[0-9]+$', '数字必须以159开头')],
        )
 
方式二:
    import re
    from django.forms import Form
    from django.forms import widgets
    from django.forms import fields
    from django.core.exceptions import ValidationError
 
 
    # 自定义验证规则
    def mobile_validate(value):
        mobile_re = re.compile(r'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$')
        if not mobile_re.match(value):
            raise ValidationError('手机号码格式错误')
 
 
    class PublishForm(Form):
 
 
        title = fields.CharField(max_length=20,
                                min_length=5,
                                error_messages={'required': '标题不能为空',
                                                'min_length': '标题最少为5个字符',
                                                'max_length': '标题最多为20个字符'},
                                widget=widgets.TextInput(attrs={'class': "form-control",
                                                              'placeholder': '标题5-20个字符'}))
 
 
        # 使用自定义验证规则
        phone = fields.CharField(validators=[mobile_validate, ],
                                error_messages={'required': '手机不能为空'},
                                widget=widgets.TextInput(attrs={'class': "form-control",
                                                              'placeholder': u'手机号码'}))
 
        email = fields.EmailField(required=False,
                                error_messages={'required': u'邮箱不能为空','invalid': u'邮箱格式错误'},
                                widget=widgets.TextInput(attrs={'class': "form-control", 'placeholder': u'邮箱'}))
 
方法三:自定义方法
    from django import forms
        from django.forms import fields
        from django.forms import widgets
        from django.core.exceptions import ValidationError
        from django.core.validators import RegexValidator
 
        class FInfo(forms.Form):
            username = fields.CharField(max_length=5,
                                        validators=[RegexValidator(r'^[0-9]+$', 'Enter a valid extension.', 'invalid')], )
            email = fields.EmailField()
 
            def clean_username(self):
                """
                Form中字段中定义的格式匹配完之后,执行此方法进行验证
                :return:
                """
                value = self.cleaned_data['username']
                if "666" in value:
                    raise ValidationError('666已经被玩烂了...', 'invalid')
                return value
 
方法四:同时生成多个标签进行验证
    from django.forms import Form
    from django.forms import widgets
    from django.forms import fields
 
    from django.core.validators import RegexValidator
 
 
    ############## 自定义字段 ##############
    class PhoneField(fields.MultiValueField):
        def __init__(self, *args, **kwargs):
            # Define one message for all fields.
            error_messages = {
                'incomplete': 'Enter a country calling code and a phone number.',
            }
            # Or define a different message for each field.
            f = (
                fields.CharField(
                    error_messages={'incomplete': 'Enter a country calling code.'},
                    validators=[
                        RegexValidator(r'^[0-9]+$', 'Enter a valid country calling code.'),
                    ],
                ),
                fields.CharField(
                    error_messages={'incomplete': 'Enter a phone number.'},
                    validators=[RegexValidator(r'^[0-9]+$', 'Enter a valid phone number.')],
                ),
                fields.CharField(
                    validators=[RegexValidator(r'^[0-9]+$', 'Enter a valid extension.')],
                    required=False,
                ),
            )
            super(PhoneField, self).__init__(error_messages=error_messages, fields=f, require_all_fields=False, *args,
                                             **kwargs)
 
        def compress(self, data_list):
            """
            当用户验证都通过后,该值返回给用户
            :param data_list:
            :return:
            """
            return data_list
 
    ############## 自定义插件 ##############
    class SplitPhoneWidget(widgets.MultiWidget):
        def __init__(self):
            ws = (
                widgets.TextInput(),
                widgets.TextInput(),
                widgets.TextInput(),
            )
            super(SplitPhoneWidget, self).__init__(ws)
 
        def decompress(self, value):
            """
            处理初始值,当初始值initial不是列表时,调用该方法
            :param value:
            :return:
            """
            if value:
                return value.split(',')
            return [None, None, None]

  

 局部钩子跟全局钩子案例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
from django import forms                #调用forms模块
    from django.forms import widgets        #调用widgets模块,用来对form组件的参数配置。
    from django.core.exceptions import ValidationError  #调用 ValidationError 模块。用来手动触发raise错误。
    from fileupdate.models import *      #载入必要的数据库列表。
 
 
    class FormReg(forms.Form):
 
        name = forms.CharField(min_length=4, widget=widgets.TextInput(attrs={'class': 'form-control '}), label='姓名',
                               error_messages={'required': '*不能为空', })
        pwd = forms.CharField(min_length=4, widget=widgets.PasswordInput(attrs={'class': 'form-control'}), label='密码')
        r_pwd = forms.CharField(min_length=4, widget=widgets.PasswordInput(attrs={'class': 'form-control'}),
                                label='确认密码')
        email = forms.EmailField(widget=widgets.EmailInput(attrs={'class': 'form-control'}), label='邮箱')
        tel = forms.CharField(max_length=13, label='电话', widget=widgets.TextInput(attrs={'class': 'form-control'}))
        ##字段的校验,通过对widget的属性设置,可定义INPUT标签的type类型,以及标签的其他属性。通过对label设置,可以自定义form渲染时的标签名,
        ##另外,通过对error_messages属性设置,可对验证信息进行自定义。注意:字典中错误信息的key值是固定的
     
        def clean_name(self):    #局部钩子   注意:名字必须为clean_%s ,这是根据源码来设置的。
                                #其原理是,当字段校验完毕后,再进行查找是否有以clean_开头的函数名,如果有,就调用该函数,
                                #运行我们自定义的函数,如果满足条件就返回当前被校验字段的内容。否则手动触发ValidationError错误,源码中会捕获并将值返回。
            val = self.cleaned_data.get('name')     #通过cleaned_data获得对应字段的'干净数据'
            user_obj = User.objects.filter(name=val).first()  #与对应的数据库中字段相比较,并获得一个字段对象
            if not user_obj:   #对字段进行判断,如果为空(数据库中没有对应的名字),那么返回这个校验值。
                return val
            else:
                raise ValidationError('名字存在')   #如果存在,那么手动触发异常(异常名为ValidationError),并设置自定义内容。
     
        def clean(self):   #全局钩子  注意:名字必须为clean,这是根据源码来设置的。
                         #其原理是对校验完毕的字段,再进行字段间的校验。当字段校验完毕,查找是否有clean的函数,如果有就运行该
                         #函数,其功能是对所有校验的字段进行校验比对。如果满足条件,就将cleaned_data返回(这与源码相匹配)
                         #如果不满足就手动触发ValidationError错误。
            pwd = self.cleaned_data.get('pwd')
            r_pwd = self.cleaned_data.get('r_pwd')
            if pwd and r_pwd:   #如果两个字段中一个为空值那么就不用再进行校验。直接返回cleaned_data,通过校验功能返回错误信息。
                if pwd == r_pwd:
                    return self.cleaned_data
                else:
                    raise ValidationError('两次密码不一致!')
            else:
                return self.cleaned_data
 
    def reg(request):
     
        if request.method == 'POST'#如果是一次POST提交,那么进行校验。
            formreg = FormReg(request.POST)  #对提交的信息实例化。
     
            if formreg.is_valid():  #通过is_valid()方法进行判断,(注意:当执行这个函数时,将对所有字段进行校验,运行局部钩子和全局钩子)
                return HttpResponse('OK')
            else:
                print('cleaneddata', formreg.cleaned_data)
                print('errordata', formreg.errors)
                error = formreg.errors.get('__all__') #当设置了全局钩子时,要设置一个变量来获得全局钩子返回的错误信息。
                            #这是由于,全局钩子的错误在form对象的errors中,当clean()方法抛出异常时,源码会自动捕获,并将错误
                            #存储在errors字典中,其中键名'__all__'就是全局钩子的变量。
                return render(request, 'reg.html', locals())
     
        formreg = FormReg()   #当为get请求时,实例化一个空的对象,通过这个空的实例化对象可以渲染前段,自动生成form表单。
        return render(request,'reg.html', locals())

  

 

 

 

 

 

posted @   HelloBaby!  阅读(1495)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示