Django入门到放弃之forms组件

简介: Django入门到放弃之forms组件

1.介绍

1

2

3

4

5

6

7

8

1 注册功能,登录功能,前端需要校验(字段长度,邮箱是否合法。。。)

2 前端校验可以没有,后端校验是必须的,使用传统方式  if判断写的很多

3 借助于forms组件,可以快速实现字段的校验

    from django.forms import Form

总结一下,其实form组件的主要功能如下:

    生成页面可用的HTML标签

    对用户提交的数据进行校验

    保留上次输入内容

2.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

133

134

Field

    required=True,               是否允许为空

    widget=None,                 HTML插件

    label=None,                  用于生成Label标签或显示内容

    initial=None,                初始值

    help_text='',                帮助信息(在标签旁边显示)

    error_messages=None,         错误信息 {'required''不能为空''invalid''格式错误'}

    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)            时间间隔:%%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类型

3.forms校验字段功能

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

### 1 写一个类,类里写要校验的字段

class MyForm(forms.Form):

    # 校验这个字段,最大长度是32,最小长度是3

    # required=Ture表示不能为空 为False表示可以为空,但是如果有值则进行校验

    name = forms.CharField(required=False, max_length=32, min_length=3,label='用户名')

    email = forms.EmailField(label='邮箱')

    age=forms.IntegerField(max_value=200,min_value=0,label='年龄')

    

    

### 2 视图函数中使用

def register(request):

    # 数据可以是从前端传过来的,也可以是自己后台的数据

 

    # 我现在有以下数据

    data={'name':'lqz','email':'33333@qq.com','age':900}

    # data={'email':'33333@qq.com','age':100}

    # data={'age':100}

    # 校验数据是否合法

    # 实例化得到form对象,把要校验的数据传入

    form=myforms.MyForm(data)

    # 校验数据:form.is_valid() 返回布尔类型

 

    if form.is_valid():

        print('校验通过')

        # 校验通过的数据

        print(form.cleaned_data) #无论是否校验通过,都可以获取 cleaned_data,但是必须在is_valid之后

    else:

        print(form.cleaned_data) # form.cleaned_data 不一定是上面传入的数据,只包含校验通的的字段

        print('校验失败')

        # 哪个字段失败了?失败的原因是什么

        print(form.errors)

        print(type(form.errors))

        from django.forms.utils import ErrorDict

        #### 重写了__str__

        print(form.errors.as_json())   #可以返回多种不同格式的数据

        print(form.errors.as_data())

 

        # form.errors.as_ul()  # 是为了渲染模板

 

 

    return HttpResponse('ok')

4.组件参数配置

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

# 定制模板中的显示样式,及配置类

# widget=widgets.PasswordInput(attrs={'class': 'form-control'})

# 错误信息中文显示

    error_messages={'min_length''太短了小伙子'}

 

from django import forms

from django.forms import widgets

 

from django.forms import ValidationError

class Myform(forms.Form):

    name = forms.CharField(required=False, max_length=32, min_length=3, label='用户名',

                           widget=widgets.TextInput(attrs={'class''form-control'}),

                           error_messages={'min_length''太短了小伙子'})

    password = forms.CharField(required=False, max_length=32, min_length=3, label='密码',

                               widget=widgets.PasswordInput(attrs={'class''form-control'}),

                               error_messages={'min_length''太短了小伙子'})

    re_password = forms.CharField(required=False, max_length=32, min_length=3, label='确认密码',

                                  widget=widgets.PasswordInput(attrs={'class''form-control'}),

                                  error_messages={'min_length''太短了小伙子'})

    email = forms.EmailField(label='邮箱', error_messages={'required''小惠子,这个必填'},

                             widget=widgets.TextInput(attrs={'class''form-control'}))

    age = forms.IntegerField(max_value=200, min_value=0, label='年龄',

                             widget=widgets.TextInput(attrs={'class''form-control'}))

    text = forms.CharField(label='个人简介', widget=widgets.Textarea(attrs={'class''form-control'}))

    date = forms.DateField(label='日期', widget=forms.DateInput(attrs={'type':'date','class''form-control'}))

 

 

 

    def clean_name(self):

        name = self.cleaned_data.get('name')

        if name.startswith('sb'):

            raise ValidationError('不能以sb开头')

        else:

            return name

 

    def clean(self):

        password = self.cleaned_data.get('password')

        re_password = self.cleaned_data.get('re_password')

        if password == re_password:

            return self.cleaned_data

        else:

            raise ValidationError('两次密码不一致')

 

 

 

class LgoinForm(forms.Form):

    name = forms.CharField(

        required=True,

        strip=True,

        help_text='不能小于六位',

        max_length=16,

        initial='狗剩',

        min_length=6,

        label="用户名",

        error_messages={

            "max_length":"太长了",

            "min_length":"太短了了",

        },

        widget=widgets.TextInput(attrs={'class':'form-control'})

    )

    password = forms.CharField(

        max_length=16,

        min_length=6,

        label="密码",

        widget=widgets.PasswordInput(attrs={'class':'form-control'})

    )

    sex = forms.ChoiceField(

        label='性别',

        initial=3,

        choices=((1,'男'),(2,'女'),(3,'保密')),

        widget=widgets.RadioSelect()

 

    )

    city = forms.ChoiceField(

        label='籍贯',

        initial=1,

        choices=((1'上海'), (2'北京'), (3'芜湖')),

        widget=widgets.Select()

    )

 

    hobby = forms.MultipleChoiceField(

        label='爱好',

        initial=[1,3],

        choices=((1'抽烟'), (2'喝酒'), (3'烫头')),

        widget=widgets.CheckboxSelectMultiple,

    )

 

    girls = forms.MultipleChoiceField(

        label='女朋友',

        choices=((1'红旭妹妹'), (2'相熙哥哥'), (3'程根姐姐')),

        widget=widgets.SelectMultiple,

    )

 

    status = forms.ChoiceField(

        label='remeber me',

        choices=(('True''红旭妹妹'),('False''程根姐姐')),

        widget=widgets.CheckboxInput

    )

 

    birthday = forms.CharField(

        label='生日',

        widget=widgets.TextInput(attrs={'type':'date'})

    )

5.RegexValidator验证器

1

2

3

4

5

6

7

8

9

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.CharField(

        validators=[RegexValidator(r'^[0-9]+$''请输入数字'), RegexValidator(r'^159[0-9]+$''数字必须以159开头')],

    )

6.自定义验证函数

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

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'邮箱'}))

7.forms渲染模板功能

forms类

1

2

3

4

5

6

7

8

9

10

from django import forms

 

 

# 写一个类,写字段

class MyForm(forms.Form):

    # 校验这个字段,最大长度是32,最小长度是3

    # required=Trues时字段允许不传,如果传则必须符合校验

    name = forms.CharField(required=False, max_length=32, min_length=3,label='用户名')

    email = forms.EmailField(label='邮箱')

    age=forms.IntegerField(max_value=200,min_value=0,label='年龄')

视图函数

1

2

3

4

5

6

7

8

9

10

11

12

13

14

from app01 import myforms

def register(request):

    if request.method=='GET':

        form=myforms.MyForm()  #获取form

        return render(request,'register.html',{'form':form})

    elif request.method=='POST':

        # 数据校验

        form=myforms.MyForm(request.POST)

        if form.is_valid():

            print('校验通过,存数据库')

        else:

            print(form.errors.as_data())

            print('校验失败,返回错误')

        return HttpResponse('ok')

模板

手动创建

1

2

3

4

5

6

7

<h1>手动创建模板</h1>

<form action="" method="post">

    <p>用户名:<input type="text" name="name"></p>

    <p>邮箱:<input type="text" name="email"></p>

    <p>年龄:<input type="text" name="age"></p>

    <p><input type="submit" value="提交"></p>

</form>

半自动渲染模板1

1

2

3

4

5

6

7

<h1>半自动渲染模板1</h1>

<form action="" method="post">

    <p>用户名:{{ form.name }}</p>

    <p>邮箱:{{ form.email }}</p>

    <p>年龄:{{ form.age }}</p>

    <p><input type="submit" value="提交"></p>

</form>

半自动渲染模板2

1

2

3

4

5

6

7

<h1>半自动渲染模板2</h1>

<form action="" method="post">

    <p>{{ form.name.label }}--{{ form.name }}</p>

    <p>{{ form.email.label }}---{{ form.email }}</p>

    <p>{{ form.age.label }}---{{ form.age }}</p>

    <p><input type="submit" value="提交"></p>

</form>

半自动渲染模板3(使用最多)

1

2

3

4

5

6

7

8

<h1>半自动渲染模板3(用的最多)</h1>

<form action="" method="post">

    {% for foo in form %}

       <p>{{ foo.label }} :{{ foo }}</p>

    {% endfor %}

 

    <p><input type="submit" value="提交"></p>

</form>

全自动

1

2

3

4

5

6

7

8

9

10

<h1>全自动(了解)</h1>

<form action="" method="post">

{#    {{ form.as_ul }}#}

    {{ form.as_p }}

{#    <table>#}

{#        {{ form.as_table }}#}

{#    </table>#}

 

    <p><input type="submit" value="提交"></p>

</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

1 form对象.errors 字典

2 name对象.errors

 

## 视图函数

def register(request):

    if request.method=='GET':

        form=myforms.MyForm()

        return render(request, 'register.html',{'form':form})

    else:

        form=myforms.MyForm(request.POST)

        if form.is_valid():

            return redirect('http://www.baidu.com')

        else:

            return render(request, 'register.html',{'form':form})

## 模板

 <form action="" method="post" novalidate>

    {% for foo in form %}

    <div class="form-group">

        <label for="">{{ foo.label }}</label>

            {{ foo }}

            # foo.errors 每一个form字段的错误

            <span class="text-danger pull-right">{{ foo.errors }}</span>

        </div>

    {% endfor %}

    <div class="text-center">

        <input type="submit" value="提交" class="btn btn-danger">

        # form.errors 所有的报错信息

        <span>{{ form.errors }}</span> 

    </div>

</form>

8.Hook钩子方法

局部钩子

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

# 对特定字段进行校验

class LoginForm(forms.Form):

    username = forms.CharField(

        min_length=8,

        label="用户名",

        initial="张三",

        error_messages={

            "required""不能为空",

            "invalid""格式错误",

            "min_length""用户名最短8位"

        },

        widget=forms.widgets.TextInput(attrs={"class""form-control"})

    )

    ...

    # 定义局部钩子clean_fieldName,用来校验username字段,之前的校验股则还在,给你提供了一个添加一些校验功能的钩子

    def clean_username(self):

        value = self.cleaned_data.get("username")

        if "666" in value:

            raise ValidationError("光喊666是不行的")

        else:

            return value

全局钩子

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

class LoginForm(forms.Form):

    ...

    password = forms.CharField(

        min_length=6,

        label="密码",

        widget=forms.widgets.PasswordInput(attrs={'class''form-control'}, render_value=True)

    )

    re_password = forms.CharField(

        min_length=6,

        label="确认密码",

        widget=forms.widgets.PasswordInput(attrs={'class''form-control'}, render_value=True)

    )

    ...

    # 定义全局的钩子,用来校验密码和确认密码字段是否相同,执行全局钩子的时候,cleaned_data里面肯定是有了通过前面验证的所有数据

    def clean(self):

        password_value = self.cleaned_data.get('password')

        re_password_value = self.cleaned_data.get('re_password')

        if password_value == re_password_value:

            return self.cleaned_data #全局钩子要返回所有的数据

        else:

            self.add_error('re_password''两次密码不一致'#在re_password这个字段的错误列表中加上一个错误,并且clean_data里面会自动清除这个re_password的值,所以打印clean_data的时候会看不到它

            raise ValidationError('两次密码不一致')

            

   # form.errors.get('__all__')  python中获取全局错误

9.ModelForm

创建modelform

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

#首先导入ModelForm

 

from django.forms import ModelForm

#在视图函数中,定义一个类,比如就叫StudentList,这个类要继承ModelForm,在这个类中再写一个原类Meta(规定写法,并注意首字母是大写的)

#在这个原类中,有以下属性(部分):

 

class StudentList(ModelForm):

    class Meta:

        model =Student #对应的Model中的类

        fields = "__all__" #字段,如果是__all__,就是表示列出所有的字段

        exclude = None #排除的字段

        #error_messages用法:

        error_messages = {

        'name':{'required':"用户名不能为空",},

        'age':{'required':"年龄不能为空",},

        }

        #widgets用法,比如把输入用户名的input框给为Textarea

        #首先得导入模块

        from django.forms import widgets as wid #因为重名,所以起个别名

        widgets = {

        "name":wid.Textarea(attrs={"class":"c1"}) #还可以自定义属性

        }

        #labels,自定义在前端显示的名字

        labels= {

        "name":"用户名"

        }

        

然后在url对应的视图函数中实例化这个类,把这个对象传给前端

def student(request):

 

    if request.method == 'GET':

        student_list = StudentList()

        return render(request,'student.html',{'student_list':student_list})

 

然后前端只需要 {{ student_list.as_p }} 一下,所有的字段就都出来了,可以用as_p显示全部,也可以通过for循环

<body>

<div class="container">

    <h1>student</h1>

    <form method="POST" novalidate>

        {% csrf_token %}

        {# {{ student_list.as_p }}#}

        {% for student in student_list %}

            <div class="form-group col-md-6">

                {# 拿到数据字段的verbose_name,没有就默认显示字段名 #}

                <label class="col-md-3 control-label">{{ student.label }}</label>

                <div class="col-md-9" style="position: relative;">{{ student }}</div>

            </div>

        {% endfor %}

        <div class="col-md-2 col-md-offset-10">

            <input type="submit" value="提交" class="btn-primary">

        </div>

    </form>

</div>

</body>

添加纪录

1

2

3

4

5

6

7

8

9

10

def student(request):

 

    if request.method == 'GET':

         student_list = StudentList()

         return render(request,'student.html',{'student_list':student_list})

    else:

         student_list = StudentList(request.POST)

         if student_list.is_valid():

         student_list.save()

         return redirect(request,'student_list.html',{'student_list':student_list}

编辑数据

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

from django.shortcuts import render,HttpResponse,redirect

from django.forms import ModelForm

# Create your views here.

from app01 import models

def test(request):

    # model_form = models.Student

    model_form = models.Student.objects.all()

    return render(request,'test.html',{'model_form':model_form})

 

class StudentList(ModelForm):

    class Meta:

        model = models.Student #对应的Model中的类

        fields = "__all__" #字段,如果是__all__,就是表示列出所有的字段

        exclude = None #排除的字段

        labels = None #提示信息

        help_texts = None #帮助提示信息

        widgets = None #自定义插件

        error_messages = None #自定义错误信息

        #error_messages用法:

        error_messages = {

        'name':{'required':"用户名不能为空",},

        'age':{'required':"年龄不能为空",},

        }

        #widgets用法,比如把输入用户名的input框给为Textarea

        #首先得导入模块

        from django.forms import widgets as wid #因为重名,所以起个别名

        widgets = {

        "name":wid.Textarea

        }

        #labels,自定义在前端显示的名字

        labels= {

        "name":"用户名"

        }

def student(request):

    if request.method == 'GET':

        student_list = StudentList()

        return render(request,'student.html',{'student_list':student_list})

    else:

        student_list = StudentList(request.POST)

        if student_list.is_valid():

            student_list.save()

            return render(request,'student.html',{'student_list':student_list})

 

def student_edit(request,pk):

    obj = models.Student.objects.filter(pk=pk).first()

    if not obj:

        return redirect('test')

    if request.method == "GET":

        student_list = StudentList(instance=obj)

        return render(request,'student_edit.html',{'student_list':student_list})

    else:

        student_list = StudentList(request.POST,instance=obj)

        if student_list.is_valid():

            student_list.save()

            return render(request,'student_edit.html',{'student_list':student_list})

10.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

def full_clean(self):

    """

    Clean all of self.data and populate self._errors and self.cleaned_data.

    """

    self._errors = ErrorDict()

    if not self.is_bound:  # Stop further processing.

        return

    self.cleaned_data = {}

    # If the form is permitted to be empty, and none of the form data has

    # changed from the initial data, short circuit any validation.

    if self.empty_permitted and not self.has_changed():

        return

 

    # 为什么全局钩子是在以上所有校验通过才走

    self._clean_fields() 局部钩子

    self._clean_form()   全句钩子

    self._post_clean()

    

 

 

 

def _clean_fields(self):

    for name, field in self.fields.items():

        # value_from_datadict() gets the data from the data dictionaries.

        # Each widget type knows how to retrieve its own data, because some

        # widgets split data over several HTML fields.

        if field.disabled:

            value = self.get_initial_for_field(field, name)

        else:

            value = field.widget.value_from_datadict(self.data, self.files, self.add_prefix(name))

        try:

            # 字段自己的校验完成后才执行局部钩子

            if isinstance(field, FileField):

                initial = self.get_initial_for_field(field, name)

                value = field.clean(value, initial)

            else:

                value = field.clean(value)

            self.cleaned_data[name] = value

            # 为什么名字一定要叫clean_字段名,

            if hasattr(self'clean_%s' % name):

                value = getattr(self'clean_%s' % name)() #执行局部钩子

                # 为什么成功要把字段值返回,

                self.cleaned_data[name] = value  # 把局部钩子的返回结果覆盖到字段执行结果中

            # 为失败抛出ValidationError  

    except ValidationError as e:

            self.add_error(name, e)  #如果发生错误,给字段添加错误

 

            

def _clean_form(self):

    try:

        cleaned_data = self.clean()

    except ValidationError as e:

        self.add_error(None, e)

    else:

        if cleaned_data is not None:

            # 为什么在视图函数中拿到的就是返回的

            self.cleaned_data = cleaned_data  #如果全局钩子有返回则覆盖所有返回内容

            为什么全局钩子返回一个自己写的字典 ?


相关文章
|
17天前
|
前端开发 关系型数据库 Python
Django入门到放弃之分页器
Django入门到放弃之分页器
|
19天前
|
JSON 前端开发 API
Django 后端架构开发:通用表单视图、组件对接、验证机制和组件开发
Django 后端架构开发:通用表单视图、组件对接、验证机制和组件开发
40 2
|
17天前
|
关系型数据库 MySQL 机器人
Django入门到放弃之数据库配置
Django入门到放弃之数据库配置
|
17天前
|
缓存 中间件 数据库
Django入门到放弃之缓存及信号机制
Django入门到放弃之缓存及信号机制
|
17天前
|
前端开发 数据库 数据安全/隐私保护
Django入门到放弃之Auth模块
Django入门到放弃之Auth模块
|
17天前
|
JSON 前端开发 数据安全/隐私保护
Django入门到放弃之CSRF_TOKEN
Django入门到放弃之CSRF_TOKEN
|
17天前
|
前端开发 中间件 索引
Django入门到放弃之中间件
Django入门到放弃之中间件
|
17天前
|
缓存 数据库 数据安全/隐私保护
Django入门到放弃之session
Django入门到放弃之session
|
17天前
|
JavaScript 前端开发 数据安全/隐私保护
Django入门到放弃之cookies
Django入门到放弃之cookies
|
17天前
|
JSON 前端开发 JavaScript
Django入门到放弃之ajax
Django入门到放弃之ajax