Django之Form、ModelForm 组件

 Django之Form、ModelForm 组件

 

【Django的Form组件】

Django的Form主要具有一下几大功能:

  • 生成HTML标签
  • 验证用户数据(显示错误信息)
  • HTML Form提交保留上次提交数据
  • 初始化页面显示内容

Form类的使用:

1、定义规则:

1
2
3
4
from  django.forms import Form
from  django.forms import fields
class  xxx(Form):
     xx = fields.CharField(max_lenghth=,min_lenghth=,required=True,error_message=)

2、使用:

1
2
3
4
5
6
7
8
9
10
11
12
obj = xxx(request.POST)
# 是否校验成功
v = obj.is_valid()
     # html标签name属性 = Form类字段名
 
obj.is_valid()验证通过返回True,失败则返回False
 
# 所有错误信息
obj.errors
 
# 正确信息
obj.cleaned_data

登录和注册案例:

 1 from django.shortcuts import render,HttpResponse,redirect
 2 
 3 from django.forms import Form
 4 from django.forms import fields
 5 class LoginForm(Form):
 6     # 正则验证: 不能为空,6-18
 7     username = fields.CharField(
 8         max_length=18,
 9         min_length=6,
10         required=True,
11         error_messages={
12             'required': '用户名不能为空',
13             'min_length': '太短了',
14             'max_length': '太长了',
15         }
16     )
17     # 正则验证: 不能为空,16+
18     password = fields.CharField(min_length=16,required=True)
19     # email = fields.EmailField()
20     # email = fields.GenericIPAddressField()
21     # email = fields.IntegerField()
22 
23 
24 def login(request):
25     if request.method == "GET":
26         return render(request,'login.html')
27     else:
28        obj = LoginForm(request.POST)
29        if obj.is_valid():
30            # 用户输入格式正确
31            print(obj.cleaned_data) # 字典类型
32            return redirect('http://www.baidu.com')
33        else:
34            # 用户输入格式错误
35            return render(request,'login.html',{'obj':obj})
36 
37 views.py
View Code
 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>Title</title>
 6 </head>
 7 <body>
 8 
 9 <form method="POST" action="/login/">
10     {% csrf_token %}
11     用户名:<input type="text" name="username">{{ obj.errors.username.0 }}<br>
12     密码 &nbsp;&nbsp;:<input type="password" name="password">{{ obj.errors.password.0 }}<br>
13     <input type="submit" value="提交">
14 
15 </form>
16 
17 </body>
18 </html>
19 
20 login.html
View Code

基于Form和Ajax提交实现用户登录案例:两种验证方式

  1 from django.shortcuts import render,redirect,HttpResponse
  2 from django.forms import Form
  3 from django.forms import fields
  4 from django.forms import widgets
  5 
  6 class LoginForm(Form):
  7     user = fields.CharField(required=True)
  8     pwd = fields.CharField(min_length=18)
  9 
 10 
 11 def login(request):
 12     if request.method == 'GET':
 13         return render(request,'login.html')
 14     else:
 15         obj = LoginForm(request.POST)
 16         if obj.is_valid():
 17             print(obj.cleaned_data)
 18             return redirect('http://www.baidu.com')
 19         return render(request,'login.html',{'obj': obj})
 20 
 21 def ajax_login(request):
 22     import json
 23     ret = {'status': True,'msg': None}
 24     obj = LoginForm(request.POST)
 25     if obj.is_valid():
 26         print(obj.cleaned_data)
 27     else:
 28         # print(obj.errors) # obj.errors对象
 29         ret['status'] = False
 30         ret['msg'] = obj.errors
 31     v = json.dumps(ret)
 32     return HttpResponse(v)
 33 
 34 #
 35 # class TestForm(Form):
 36 #     t1 = fields.CharField(
 37 #         required=True,
 38 #         max_length=8,
 39 #         min_length=2,
 40 #         error_messages={
 41 #             'required': '不能为空',
 42 #             'max_length': '太长',
 43 #             'min_length': '太短',
 44 #         }
 45 #     )
 46 #     t2 = fields.IntegerField(
 47 #         min_value=10,
 48 #         max_value=1000,
 49 #         error_messages={
 50 #             'required': 't2不能为空',
 51 #             'invalid': 't2格式错误,必须是数字',
 52 #             'min_value': '必须大于10',
 53 #             'max_value': '必须小于1000',
 54 #         },
 55 #     )
 56 #     t3 = fields.EmailField(
 57 #         error_messages={
 58 #             'required': 't3不能为空',
 59 #             'invalid': 't3格式错误,必须是邮箱格式',
 60 #         }
 61 #     )
 62 
 63 
 64 
 65 
 66 
 67 class TestForm(Form):
 68     t1 = fields.CharField(required=True,max_length=8,min_length=2,
 69         error_messages={
 70             'required': '不能为空',
 71             'max_length': '太长',
 72             'min_length': '太短',
 73         }
 74     )
 75     t2 = fields.EmailField()
 76 
 77 def test(request):
 78     if request.method == "GET":
 79         obj = TestForm()
 80         return render(request,'test.html',{'obj': obj})
 81     else:
 82         obj = TestForm(request.POST)
 83         if obj.is_valid():
 84             print(obj.cleaned_data)
 85         else:
 86             print(obj.errors)
 87         return render(request,'test.html',{'obj':obj})
 88 
 89 
 90 
 91 class RegiterForm(Form):
 92     user = fields.CharField(min_length=8)
 93     email = fields.EmailField()
 94     password = fields.CharField()
 95     phone = fields.RegexField('139\d+')
 96 
 97 
 98 def register(request):
 99     if request.method == 'GET':
100         obj = RegiterForm()
101         return render(request,'register.html',{'obj':obj})
102     else:
103         obj = RegiterForm(request.POST)
104         if obj.is_valid():
105             print(obj.cleaned_data)
106         else:
107             print(obj.errors)
108         return render(request,'register.html',{'obj':obj})
views.py
 1 """s4day77 URL Configuration
 2 
 3 The `urlpatterns` list routes URLs to views. For more information please see:
 4     https://docs.djangoproject.com/en/1.10/topics/http/urls/
 5 Examples:
 6 Function views
 7     1. Add an import:  from my_app import views
 8     2. Add a URL to urlpatterns:  url(r'^$', views.home, name='home')
 9 Class-based views
10     1. Add an import:  from other_app.views import Home
11     2. Add a URL to urlpatterns:  url(r'^$', Home.as_view(), name='home')
12 Including another URLconf
13     1. Import the include() function: from django.conf.urls import url, include
14     2. Add a URL to urlpatterns:  url(r'^blog/', include('blog.urls'))
15 """
16 from django.conf.urls import url
17 from django.contrib import admin
18 from app01 import views
19 urlpatterns = [
20     url(r'^admin/', admin.site.urls),
21     url(r'^login/', views.login),
22     url(r'^ajax_login/', views.ajax_login),
23     url(r'^test/', views.test),
24     url(r'^register/', views.register),
25 ]
urls.py
 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title></title>
 6 </head>
 7 <body>
 8     <h1>用户登录</h1>
 9     <form id="f1" action="/login/" method="POST">
10         {% csrf_token %}
11         <p>
12             <input type="text" name="user" />{{ obj.errors.user.0 }}
13         </p>
14         <p>
15             <input type="password" name="pwd" />{{ obj.errors.pwd.0 }}
16         </p>
17         <input type="submit" value="提交" />
18         <a οnclick="submitForm();">提交</a>
19     </form>
20     <script src="/static/jquery-1.12.4.js"></script>
21     <script>
22         function submitForm(){
23             $('.c1').remove();
24             $.ajax({
25                 url: '/ajax_login/',
26                 type: 'POST',
27                 data: $('#f1').serialize(),// user=alex&pwd=456&csrftoen=dfdf\
28                 dataType:"JSON",
29                 success:function(arg){
30                     console.log(arg);
31                     if(arg.status){
32 
33                     }else{
34                         $.each(arg.msg,function(index,value){
35                             console.log(index,value);
36                             var tag = document.createElement('span');
37                             tag.innerHTML = value[0];
38                             tag.className = 'c1';
39                             $('#f1').find('input[name="'+ index +'"]').after(tag);
40                         })
41                     }
42                 }
43             })
44         }
45     </script>
46 </body>
47 </html>
login.html
 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title></title>
 6 </head>
 7 <body>
 8     <form action="/test/" method="POST" novalidate>
 9         {% csrf_token %}
10         <p>
11             {{ obj.t1 }}{{ obj.errors.t1.0 }}
12         </p>
13         <p>
14             {{ obj.t2 }}{{ obj.errors.t2.0 }}
15         </p>
16         <input type="submit" value="提交" />
17     </form>
18 </body>
19 </html>
test.html
 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title></title>
 6 </head>
 7 <body>
 8 
 9     <form action="/register/" method="POST" novalidate>
10         {% csrf_token %}
11         <p>
12             {{ obj.user }} {{ obj.errors.user.0 }}
13         </p>
14         <p>
15             {{ obj.email }} {{ obj.errors.email.0 }}
16         </p>
17         <p>
18             {{ obj.password }} {{ obj.errors.password.0 }}
19         </p>
20         <p>
21             {{ obj.phone }} {{ obj.errors.phone.0 }}
22         </p>
23         <input type="submit" value="提交"  />
24     </form>
25 </body>
26 </html>
register.html

总结:

1
2
- Ajax,仅用验证功能
- Form,验证功能,生成HTML标签

Form类的字段和插件

创建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
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)            时间间隔: % % 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以及当前时间等创建的不重复的随机字符串

 1 >>> import uuid
 2 
 3     # make a UUID based on the host ID and current time
 4     >>> uuid.uuid1()    # doctest: +SKIP
 5     UUID('a8098c1a-f86e-11da-bd1a-00112444be1e')
 6 
 7     # make a UUID using an MD5 hash of a namespace UUID and a name
 8     >>> uuid.uuid3(uuid.NAMESPACE_DNS, 'python.org')
 9     UUID('6fa459ea-ee8a-3ca4-894e-db77e160355e')
10 
11     # make a random UUID
12     >>> uuid.uuid4()    # doctest: +SKIP
13     UUID('16fd2706-8baf-433b-82eb-8c7fada847da')
14 
15     # make a UUID using a SHA-1 hash of a namespace UUID and a name
16     >>> uuid.uuid5(uuid.NAMESPACE_DNS, 'python.org')
17     UUID('886313e1-3b8a-5372-9b90-0c9aee199e5d')
18 
19     # make a UUID from a string of hex digits (braces and hyphens ignored)
20     >>> x = uuid.UUID('{00010203-0405-0607-0809-0a0b0c0d0e0f}')
21 
22     # convert a UUID to a string of hex digits in standard form
23     >>> str(x)
24     '00010203-0405-0607-0809-0a0b0c0d0e0f'
25 
26     # get the raw 16 bytes of the UUID
27     >>> x.bytes
28     b'\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f'
29 
30     # make a UUID from a 16-byte string
31     >>> uuid.UUID(bytes=x.bytes)
32     UUID('00010203-0405-0607-0809-0a0b0c0d0e0f')
View Code

2、Django内置插件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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

常用选择插件

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
# 单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的选项可以从数据库中获取,但是由于是静态字段 ***获取的值无法实时更新***,那么需要自定义构造方法从而达到此目的。

 方式一:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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字段来实现

1
2
3
4
5
6
7
8
9
10
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())zidi

自定义验证规则

方式一:

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开头' )],
     )

方式二:

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

方法三:自定义方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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

方式四:同时生成多个标签进行验证

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
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.
         =  (
             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 ]

初始化数据

在Web应用程序中开发编写功能时,时常用到获取数据库中的数据并将值初始化在HTML中的标签上。

1、Form

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()
  
    city = fields.ChoiceField(
        choices=((1, '上海'), (2, '北京'),),
        widget=widgets.Select
    )
View Code

2、Views

from django.shortcuts import render, redirect
from .forms import MyForm
  
  
def index(request):
    if request.method == "GET":
        values = {'user': 'root', 'city': 2}
        obj = MyForm(values)
  
        return render(request, 'index.html', {'form': obj})
    elif request.method == "POST":
        return redirect('http://www.google.com')
    else:
        return redirect('http://www.google.com')
View Code

3、HTML

<form method="POST" enctype="multipart/form-data">
    {% csrf_token %}
    <p>{{ form.user }} {{ form.user.errors }}</p>
    <p>{{ form.city }} {{ form.city.errors }}</p>
  
    <input type="submit"/>
</form>
View Code

关于对字段认证[clean,clean_字段]的补充(关于错误信息)

 1 class RegesterForm(Form):
 2     username = fields.CharField(
 3         widget=widgets.TextInput(
 4             attrs={"class": "form-control",
 5                    "placeholder": "用户名",
 6                    }),
 7         error_messages={
 8             "required": "内容不能为空",
 9             "invalid": "格式错误,请重新输入!", })
10  
11     nickname = fields.CharField(
12         widget=widgets.TextInput(
13             attrs={"class": "form-control",
14                    "placeholder": "即昵称",
15                    }),
16         error_messages={
17             "required": "内容不能为空",
18             "invalid": "格式错误,请重新输入!", })
19  
20     email = fields.EmailField(
21         widget=widgets.TextInput(
22           attrs={
23               "class": "form-control",
24               "placeholder": "请输入您查用邮箱",
25           }),
26         error_messages = {
27             "required": "内容不能为空",
28             "invalid": "格式错误,请重新输入!",}
29     )
30  
31     password = fields.CharField(
32         widget=widgets.PasswordInput(
33             attrs={"class": "form-control",
34                    "placeholder": "密码,必须包含数字,字母!",
35                    }),
36         error_messages={
37             "required": "内容不能为空",
38             "invalid": "格式错误,请重新输入!", })
39  
40     passwords = fields.CharField(
41         widget=widgets.PasswordInput(
42             attrs={"class": "form-control",
43                    "placeholder": "请输入确认密码",
44                    }),
45         error_messages={
46             "required": "内容不能为空",
47             "invalid": "格式错误,请重新输入!", })
48  
49     avatar = fields.FileField(
50         widget=widgets.FileInput(
51             attrs={'id':"imgSelect",}),
52     )
53     code = fields.CharField(
54         widget=widgets.TextInput(
55             attrs={
56                 "class": "form-control",
57                 "placeholder": "验证码",
58             },)
59     )
60     def __init__(self,request,*args,**kwargs):
61         super(RegesterForm,self).__init__(*args,**kwargs)
62         self.request = request
63  
64     def clean_code(self):
65         input_code = self.cleaned_data["code"]
66         session_code = self.request.session.get("code")
67         if input_code.upper() == session_code.upper():
68             return input_code
69         raise ValidationError("验证码错误,请重新输入!")
70     #自定义字段验证方法,获取错误信息的方式不变,还是   对象.errors.字段名.0
71  
72     def clean(self):
73         p1 = self.cleaned_data.get("password")
74         p2 = self.cleaned_data.get("passwords")
75         if p1 == p2:
76             return self.cleaned_data
77         else:
78             self.add_error("passwords",ValidationError("输入的密码不一致!"))
View Code
 1 对于Form组件的错误信息:
 2     注意再注意:
 3     默认错误信息方式: raise ValidationError("输入的密码不一致!")
 4     自定义对已拿到所有字段数据进行验证的时候,这种方式在获取错误信息时就发生改变,查看源码发现如果有错误的话,他会执行self.add_error(None, e)
 5     通过方法给字段None添加错误信息,查看add_error的源码以及执行过程,发现None = NON_FIELD_ERRORS。也就是说会默认给__all__字段或
 6     NON_FIELD_ERRORS写上错误信息。原因:内部定义的NON_FIELD_ERRORS="__all__",
 7     获取方式:
 8         前端获取 是通过obj.non_field_errors
 9         后台获取是通过 obj.errors["__all__"]  or   obj.errors[NON_FIELD_ERRORS]
10  
11     我们知道,当报错的时候,内部会自动去添加错误信息,若是我们能否手动指定某个字段呢?答案是肯定的。
12     这样我们自己添加异常的错误信息,就能直接通过{{obj.errors.passwords.0}}获取到与其他的无疑。
13     语法:
14         self.add_error('字段名称', 错误异常对象)
总结

以上代码是我写用户注册时的form组件,由于牵扯到对输入字段的认证问题!如果选择在视图函数中,那代码的重复率可就老了去了!!!所以就使用了Form组件中的字段认证的方法!!!

前面已经介绍过Form组件中两种验证方式的函数,一个对字段的 clean_字段;另一个是等所有字段验证之后,对所有验证过的clean_data进行更高的验证:clean;今天我要说的是关于验证过程中,产生和收集错误信息的问题。详见上面代码!!!

-------------------------------------------------------------------------------------bottom another------------------------------------------------------------------------------------------

一、Form组件:

django框架提供了一个form类,来处理web开发中的表单相关事项。众所周知,form最常做的是对用户输入的内容进行验证,为此django的forms类提供了全面的内容验证和保留用户上次输入数据的支持。

 form组件有2大大功能

对用户提交的内容进行验证(from表单/Ajax)

保留用户上次输入的内容

 

1、对用户提交的数据进行验证

form组件验证的原理

 

1.obj=Form()form组件类实例化时找到类中所有的字段 把这些字段 变成组合成字典;

self.fields={‘user’:正则表达式1,‘pwd’:正则表达式2}

2.循环self.fields字典(自己写的字段)

for  k,v  in self.fields.items():

    K是user,pwd

   v是正则表达式

3.每次循环通过self.fields字典的键, 一个一个的去get前端POST提交的数据 得到用户输入数据;

input_value= request.post.get(‘k’)(所以form字段的名称,要和前端的name属性匹配)

4.每次拿到用户输入的数据 (input_value)和进行正则表达式匹配;

5.匹配成功flag=True 匹配失败flag=falsh,最后 return flag  obj.is_valid=flag。

如果For自带的规则和正则满足不了验证需求,可在Form类中自定义方法,做扩展。

6.每个字段验证通过后,每个字段执执行self.clean_filelds函数(自定义 对Form类中的字段做单独验证,比如去数据库查询判断一下用户提交的数据是否存在?)

7. 执行Form组件的clean_form方法进行整体验证!(既然每个字段都验证了,就可以对用户提交的数据做整体验证了!比如进行联合唯一的验证)

 8.最后执行类似 clean_form的post_clean方法结束验证。(一般不使用post_clean做自定义过滤,clean_form方法完全可以解决)

form表单提交验证(form表单(会发起 get)提交刷新失去上次内容)

 1 from django.shortcuts import render,HttpResponse,redirect
 2 from django.forms import Form
 3 from django.forms import fields
 4 
 5 class Login(Form):
 6                               #from验证规则 用户名 6-10字符  required不能为空
 7     name=fields.CharField(max_length=10,
 8                           min_length=6,
 9                           required=True,
10                            error_messages={
11                                'required':'用户名不能为空',  #error_messages参数 自定义错误信息
12                                'min_length':'太短了',
13                                 'max_length': "太长了",
14                                            }
15 
16                           )
17                                                                     # z注意name 必须和 from表单提交的一致,要么二则怎么对比校验呢
18     pwd= fields.CharField(min_length=3,
19                           required=True,
20                           error_messages={
21                               'required': '密码不能为空',  # error_messages参数 自定义错误信息
22                               'min_length': '太短了',
23                               'max_length': "太长了",
24                           }
25 
26 
27 
28                           )
29 
30 
31 def index(request):
32     if request.method=='GET':
33         return render(request,'login.html')
34     else:
35         obj=Login(request.POST)  #把客户端提交来的form表单和 和匹配规则放在一起
36         res=obj.is_valid()         #自动校验  给出结果 True 或者 False
37         if res:                    #验证成功后obj.cleaned_data获取成功的数据,字典类型正好对应数据 的批量操作
38             print(obj.cleaned_data)
39             return redirect('http://www.baidu.com')                 #obj.errors获取错误信息(对象类型)就可以传到前端显示了!
40         else:
41            return  render(request,'login.html',{'obj':obj})
View Code

Ajax提交验证(不会刷新,上次输入内容自动保留)

Django的form验证功能不仅限于对form表单提交的数据验证,同样适用于ajax提交方式

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>ajx提交</title>
 6 </head>
 7 <body>
 8 <form method="post" action="/aja_login/" id="f1">
 9   {%csrf_token%}
10 <p>用户:<input type="text" name="name"></p>
11 <p>密码:<input type="password" name="pwd"></p>
12 <p><input type="button" οnclick="Ajxform()" value="aja提交"></p>
13 </form>
14 </body>
15 <script src="/static/zhanggen.js"></script>
16 <script> function Ajxform(){
17     $('.c1').remove()
18     $.ajax({
19         url:'/alogin/',
20         type:'POST',
21         dataType:'JSON',
22         data:$('#f1').serialize(),
23         success:function (args) {
24             if (args.status){ }
25             else{
26 {#                {status: false, msg: Object}#}
27 {#                console.log(args);#}
28 {#                Jquery循环服务端 传过来的 错误信息对象#}
29                 $.each(args.msg,function (index,value) {
30                     console.log(index,value);
31 {#                 index----> name ["太短了"]#}
32 {#                 value-----pwd["密码不能为空"]#}
33                     var tag=document.createElement('span');
34                     tag.innerHTML= value[0];
35                     tag.className='c1';
36                     console.log(index);
37 {#                    寻找input下 属性为 name 和pwd的标签(字符串拼接) 在他们后半加 上tag标签也就是错误 信息 #}
38                     $('#f1').find('input[name="'+ index +'"]').after(tag)
39 
40                 })
41             }
42 
43                }})}
44 </script>
45 </html>
View Code

Views

 1 from django.shortcuts import render,HttpResponse,redirect
 2 from django.forms import Form
 3 from django.forms import fields
 4 import json
 5 class Login(Form):
 6                               #from验证规则 用户名 6-10字符  required不能为空
 7     name=fields.CharField(max_length=10,
 8                           min_length=6,
 9                           required=True,
10                          error_messages={
11                                'required':'用户名不能为空',  #error_messages参数 自定义错误信息
12                                'min_length':'太短了',
13                                 'max_length': "太长了",
14                                            }
15 
16                           )
17                                                                     # z注意name 必须和 from表单提交的一致,要么二则怎么对比校验呢
18     pwd= fields.CharField(min_length=3,
19                           required=True,
20                           error_messages={
21                               'required': '密码不能为空',  # error_messages参数 自定义错误信息
22                               'min_length': '太短了',
23                               'max_length': "太长了",})
24 
25 
26 
27 def agx_login(request):
28     ret={'status':True,'msg':None}
29     if request.method=='GET':
30        return render(request,'ajalogin.html')
31     else:
32         obj=Login(request.POST)
33         ret['status']=False
34         ret['msg']=obj.errors
35         return HttpResponse(json.dumps(ret))
View Code

自定义正则表达式验证

密码修改实例

password_complexity='^(?:(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])).+$' #密码复杂性要求:密码必须包含数字、大、写字母
 1 {% extends "arya/layout.html" %}
 2 {% block  out_css %}
 3     <link rel="stylesheet" href="/arya/static/arya/css/form-control.css"/>
 4 {% endblock %}
 5 
 6 {% block content %}
 7     {% csrf_token %}
 8     <div>
 9         <div class="row">
10             <a class="btn btn-default" href="{{ request.META.HTTP_REFERER }}">返回</a>
11             <div class="col-md-5 col-md-offset-3">
12                 <form>
13                     <div class="form-group">
14                         <label for="exampleInputPassword1">请输入原始密码</label>
15                         <input name="old_pwd" type="password" class="form-control" id="exampleInputPassword0"
16                                placeholder="原始密码">
17                     </div>
18                     <div class="form-group">
19                         <label for="exampleInputPassword1">新的密码</label>
20                         <input name="first_new_pwd" type="password" class="form-control" id="exampleInputPassword1"
21                                placeholder="新的密码">
22                     </div>
23                     <div class="form-group">
24                         <label for="exampleInputPassword1">再次输入新密码</label>
25                         <input name="second_new_pwd" type="password" class="form-control" id="exampleInputPassword2"
26                                placeholder="再次输入新密码">
27                     </div>
28 
29                     <button id="submit_pwd" type="button" class="btn btn-default">提交</button>
30 
31                 </form>
32                 <br>
33                 <p style="color: red" id="__all__" class="error_msg"></p>
34                 <br>
35                 <p>设置密码时请符合以下规则:最小长度8、包含大小写英文字母、数字。</p>
36             </div>
37         </div>
38     </div>
39     {#    </section>#}
40     <script>
41         $('#submit_pwd').click(function () {
42             var $csrf = $("[name='csrfmiddlewaretoken']").val();
43             var $old_pwd = $('[name="old_pwd"]').val();
44             var $first_new_pwd = $('[name="first_new_pwd"]').val();
45             var $second_new_pwd = $('[name="second_new_pwd"]').val();
46 
47             var pwd_formdata = new FormData();
48             pwd_formdata.append('csrfmiddlewaretoken', $csrf);
49             pwd_formdata.append('old_pwd', $old_pwd);
50             pwd_formdata.append('first_new_pwd', $first_new_pwd);
51             pwd_formdata.append('second_new_pwd', $second_new_pwd);
52 
53 
54             $.ajax({
55                 type: 'post',
56                 data: pwd_formdata,
57                 processData: false,
58                 contentType: false,
59                 success: function (data) {
60                     var response = JSON.parse(data);
61                     var $error_p = $('<p class="error_msg" style="color:red">'+ '</p>');
62 
63                     if (response.status == 200) {
64                         window.location = "/login/"
65                     }
66 
67                     if (response.status == 404) {
68                         var error_p =$error_p.text(response.msg.old_pwd);
69                         $('[name="old_pwd"]').after(error_p)
70                     }
71                     else {
72                         $.each(response.msg, function (k, v) {
73                             var $input_tag = $("[name=" + k +"]");
74                             var error_p = '<p style="color: red" class="error_msg">'+v[0]+'</p>';
75                             $input_tag.after(error_p);
76                             console.log(response.msg);
77                             if (k == '__all__') {
78                                 $('#__all__').text(v[0])
79                             }
80                         });
81                     }
82                     setTimeout("$('.error_msg').remove()", 3000);
83                 }
84             })
85         })
86     </script>
87 {% endblock %}
前端模板
 1 def changepwd(request):  #修改密码视图
 2     if request.method=='POST':
 3         current_user = request.session.get('username')
 4         response_info = {'status':200,'msg':None}
 5         user_db_obj = models.UserInfo.objects.filter(username=current_user).first()
 6         if not user_db_obj or user_db_obj.password != make_md5(request.POST.get('old_pwd').strip()):
 7             response_info['status'] = 404
 8             response_info['msg'] = {'old_pwd': '原始密码错误.'}
 9         else:
10             obj = FormCheck.Set_password(request.POST)
11             if not obj.is_valid():
12                 response_info['status'] = 403
13                 response_info['msg']=obj.errors
14             else:
15                 user_db_obj.password = make_md5(request.POST.get('second_new_pwd').strip())
16                 user_db_obj.save()
17         return HttpResponse(json.dumps(response_info, ensure_ascii=False))
18     return render(request,'woke_order/changepwd.html')
Django视图
 1 from django.forms import Form
 2 from django.forms import fields
 3 from django.forms import widgets
 4 from cmdb.models import *
 5 import re
 6 from django.core.exceptions import ValidationError
 7 
 8 class Set_password(Form):
 9     password_complexity='^(?:(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])).+$'
10 
11     old_pwd=fields.RegexField(password_complexity,
12         required=True,
13         min_length=8,
14         error_messages={'invalid':'不满足密码复杂性要求','required':'密码不能为空!','min_length':'密码长度少于8位'},
15     )
16 
17     first_new_pwd=fields.RegexField(password_complexity,
18         required=True,
19         min_length=8,
20         error_messages={'invalid':'不满足密码复杂性要求','required':'密码不能为空!','min_length':'密码长度少于8位'},
21     )
22 
23     second_new_pwd =fields.RegexField(password_complexity,
24         required=True,
25         min_length=8,
26         error_messages={'invalid':'不满足密码复杂性要求','required':'密码不能为空!','min_length':'密码长度少于8位'},
27     )
28 
29     def clean(self):
30         first_new_pwd=self.cleaned_data.get('first_new_pwd')
31         second_new_pwd=self.cleaned_data.get('second_new_pwd')
32         if first_new_pwd and second_new_pwd:
33             if first_new_pwd.strip() == second_new_pwd.strip():
34                 return self.cleaned_data
35         raise ValidationError("两次密码不一致")
Django的form验证

IP 和端口

ipaddr_validate="^((?:(2[0-4]\d)|(25[0-5])|([01]?\d\d?))\.){3}(?:(2[0-4]\d)|(255[0-5])|([01]?\d\d?))$"
port_validate='^([0-9]|[1-9]\d|[1-9]\d{2}|[1-9]\d{3}|[1-5]\d{4}|6[0-4]\d{3}|65[0-4]\d{2}|655[0-2]\d|6553[0-5])$' 
 1 from django.forms import Form,fields
 2 from django.forms import widgets,forms
 3 import re
 4 ipaddr_validate="^((?:(2[0-4]\d)|(25[0-5])|([01]?\d\d?))\.){3}(?:(2[0-4]\d)|(255[0-5])|([01]?\d\d?))$"
 5 port_validate='^([0-9]|[1-9]\d|[1-9]\d{2}|[1-9]\d{3}|[1-5]\d{4}|6[0-4]\d{3}|65[0-4]\d{2}|655[0-2]\d|6553[0-5])$'
 6 class dbinfo_create(Form):
 7     data_mode_type=fields.CharField(required=True,error_messages={'required':'数据库模型不能为空.'})
 8     database_type=fields.CharField(required=True,error_messages={'required':'数据库类型不能为空'})
 9     host=fields.RegexField(ipaddr_validate,required=True,error_messages={'required':'IP不能为空','invalid':'不合法的IP地址'})
10     port=fields.RegexField(port_validate,required=True,error_messages={'required':'端口不能为空.','invalid':'端口无效'})
11     # instance_nikename=fields.CharField(max_length=20,error_messages={'required':'端口不能为空.',"max_length":"标题不能超过20个字"})
12     db_business=fields.CharField(required=True,error_messages={'required':'请说明所属业务线'})
13     DBA=fields.CharField(required=True,error_messages={'required':'请说明DBA'})
14     responsible_person=fields.CharField(required=True, error_messages={'required':'请选择相关责任人!'})
验证

2、动态生成HTML标签,保留用户上次输入的内容。

如何保留用户上次输入的内容?

由于form表单submit之后(发送post请求) 数据提交到 后端,不管前端输入的数据是否正确,服务端也要响应,所以页面会刷新;

所以无法保留用户上次输入的内容;如何解决呢?

1、把定义的定义的Form类,实例化(obj=Login() )内部调用一个__str__的方法,如果没有传值 返回<input type="text" name=“字段”>name='字段名空的input标签

2、把这个实例化之后的对象传到前端显示,让用户输入值;用户输入值通过post方法提交到后台。

3、如果后台实例化一个对象 obj=Login(request.POST)传入了值, <input type="text" name=“字段” value='request.post的数据'>然后后端再返回客户端就可以看到用户输入的值了!

保留用户上次输入的内容 是利用了 obj=Login(request.POST)接收了用户输入的值

视图

 1 from django import  forms
 2 
 3 class Myform(forms.Form):            #1、写1个继承forms.Form的类,定制form表单的数据类型;
 4     user=forms.CharField(max_length=32,min_length=3,label='用户名',
 5                          error_messages={'required':'不能为空'},
 6                          widget=forms.TextInput(attrs={'class':'sb','placeholder':'用户名'},)
 7                          )
 8     age=forms.IntegerField(label='年龄',error_messages={'required':'不能为空'},)
 9     email=forms.EmailField(label='邮箱',error_messages={'required':'不能为空'},)
10 
11 def register2(request):
12     if request.method=='GET':
13         forms_obj=Myform()               #2、实例化类,把对象渲染到模板
14         return render(request,'form——register.html',{'forms_obj':forms_obj})
15     else:
16         forms_obj=Myform(request.POST)   #3、把提交的数据封装成form对象
17         if forms_obj.is_valid():         #4、使用 form对象的.is_valid()方法,校验提交过来的数据是否符合验证规则
18             data=forms_obj.cleaned_data  #5、获取验证通过的数据(字典类型,可直接 **dict插入数据库)
19             # User.objects.create_user(**data)
20             return HttpResponse('OK')
21         else:
22             print(forms_obj.cleaned_data) #6、由于用户在form表单提交了值,利用这一点,
23                                             # 把forms_obj=Myform(request.POST)渲染到前端就可以保存用户输入的值
24         return render(request, 'form——register.html', {'forms_obj':forms_obj})
View Code

前台

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Django_form验证</title>
</head>
<body>
<form action="/form/" method="post" novalidate>
    {% csrf_token %}
    <p>用户:{{ forms_obj.user }}{{ forms_obj.errors.user.0 }}</p>
      <p>年龄:{{ forms_obj.age }}{{ forms_obj.errors.age.0}}</p>
    <p>邮箱:{{ forms_obj.email }}{{ forms_obj.errors.email.0}}</p>
    <button>提交</button>
</form>
</body>
</html>
View Code
 1 from django.shortcuts import render,HttpResponse,redirect
 2 from django.forms import Form
 3 from django.forms import fields
 4 import json
 5 class Login(Form):
 6                               #from验证规则 用户名 6-10字符  required不能为空
 7     name=fields.CharField(max_length=10,
 8                           min_length=6,
 9                           required=True,
10                          error_messages={
11                                'required':'用户名不能为空',  #error_messages参数 自定义错误信息
12                                'min_length':'太短了',
13                                 'max_length': "太长了",
14                                            }
15 
16                           )
17                                                                     # z注意name 必须和 from表单提交的一致,要么二则怎么对比校验呢
18     pwd= fields.CharField(min_length=3,
19                           required=True,
20                           error_messages={
21                               'required': '密码不能为空',  # error_messages参数 自定义错误信息
22                               'min_length': '太短了',
23                               'max_length': "太长了",})
24 
25 
26 def index(request):
27     ret={'status':True,'msg':None}
28     if request.method=='GET':
29         obj=Login()                 #自动生成空白的input标签 发送给客户端)
30         return render(request,'login.html',{'obj':obj})
31     else:
32         obj=Login(request.POST)  #把客户端提交来的form表单和 和匹配规则放在一
33         res=obj.is_valid()         #自动生成空白的input标签 发送
34         if res:                    #验证成功后obj.cleaned_data获取成功的数据,字典类型正好对应数据 的批量操作
35             return HttpResponse('OK') #obj.errors获取错误信息(对象类型)就可以传到前端显示了!
36         else:
37            return render(request,'login.html',{'obj':obj})
View Code
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登录页面</title>
</head>
<body>
<form method="post" action="/login/" id="f1" novalidate >
     {%csrf_token%}
       <h1>用户登录</h1>
        <p>用户名 {{obj.name}}{{ obj.name.errors.0}}</p>
        <p>密码:{{ obj.pwd}}{{ obj.pwd.errors.0}}</p>
        <p><input type="submit" value="登录"></p>
</form>
</body>
</html>
View Code

 3、承上启下 form组件的套路(执行流程):

(1)在后端定义类和字段,实例化Form类;

(2)到用户 发送get请求时,服务端渲染到模板(空标签/默认值)发送到客户端显示

(3)客户端填数据,POST提交到后端;

(4)后端验证,返回结果给前端;(切记Form组件是在后端生成,发送给客户端显示,客户端填完数据在发回服务端!)

二、form组件使用:

1、导入Form插件

from django.forms import Form,fields
from django.forms import widgets
 1 class Class_form(Form):
 2     title=fields.RegexField('全栈\d+',
 3                             # initial='全栈', #设置input标签中的默认值
 4                             min_length=2,
 5                             required=True,
 6                             error_messages={'invalid':"必须以全栈开头",
 7                                             'min_length':'太短了',
 8                                             'required':"不能为空",
 9                                             }
10                             )
11 class Students(Form):
12     name=fields.CharField(required=True,
13     widget=widgets.TextInput(attrs={'class':'form-control'}),
14     error_messages={'required':'姓名不能为空'})
15     sex=fields.CharField(required=True,error_messages={'required':'不能为空'},
16     widget = widgets.TextInput(attrs={'class': 'form-control'})
17 
18                          )
19     cls_id=fields.IntegerField(widget=widgets.Select(choices=models.Classes.objects.values_list('id','title'),
20     attrs = {'class': 'form-control'}
21 
22                                                      ),
23 
24                                 )
25 class teacher_form(Form):
26     tname=fields.CharField(required=True,error_messages={'required':"姓名不能为空"} )
27    #  classes=fields.CharField( #多选 不能用这个插件不使用request.post.getlist()取值
28    #      widget=widgets.Select(choices=models.Classes.objects.values_list(),
29    #      attrs={'multiple':'multiple'})
30    #                           )
31    #  classes=fields.CharField(widget=widgets.SelectMultiple(
32    # # 如果在fields.CharField字段该插件,得到会是{'tname': 'ww', 'classes': "['2', '3']"}字符串
33    #   choices= models.Classes.objects.values_list('id','title')) )
34     classes=fields.MultipleChoiceField(
35         choices=models.Classes.objects.values_list('id','title'),
36         widget=widgets.SelectMultiple,error_messages={'required':'选择不能为空'})
37     def __int__(self,*args,**kwargs):  #解决数据不同步的bug,每次form组件实例化时 都重新去数据库拿数据
38         super(teacher_form,self).__init__(*args,**kwargs)
39         self.fields['classes'].widget.choices=models.Classes.objects.values_list('id','title')
40 
41 
42 
43 class Test_form(Form):
44     name=fields.CharField()  #动态生成 text类型的input标签
45     text=fields.CharField(widget=widgets.Textarea,) #动态生成文本框
46     age=fields.CharField(widget=widgets.CheckboxInput) #动态生成单选框
47     holby=fields.MultipleChoiceField(                  #MultipleChoiceField动态生成复选框
48         choices=[(1,'篮球'),(2,"足球"),(3,"高俅")],
49         widget=widgets.CheckboxSelectMultiple)
50     sex=fields.MultipleChoiceField(
51         choices=[(1,''),(2,'')],
52         widget=widgets.RadioSelect
53     )
54 
55     select=fields.ChoiceField(choices=[(2, '北京'), (3, '唐县')]) #通过ChoiceField字段动态生成单选框
56                                                                    # 通过form组件的MultipleChoiceField字段
57     mselect=fields.MultipleChoiceField(choices=[(1,'管家佐'),(2,'万宝利') ],
58                                  widget=widgets.SelectMultiple)
59     file=fields.FileField()  #通过form组件的.FileField动态生成 文件上传input标签,注意在提交到后台是对象
View Code
2、定义类和字段(验证规则) 扩展方法

class Form_login(Form):

                 字段                               参数

  user=fields.RegexField正则表达式,验证规则,error_messages={错误信息},widget=html标签插件attrs = {'标签插件的属性'})

 

三、form的钩子函数

Django的form在obj.is_valid()方法内提供2个钩子函数,以便我们随时调用他自定制一些复杂的验证规则;

 局部钩子函数 

 1 class Class_form(Form):
 2     title=fields.RegexField('全栈\d+',
 3                             # initial='全栈', #设置input标签中的默认值
 4                             min_length=2,
 5                             required=True,
 6                             error_messages={'invalid':"必须以全栈开头",
 7                                             'min_length':'太短了',
 8                                             'required':"不能为空",
 9                                             }
10                             )
11 class Students(Form):
12     name=fields.CharField(required=True,
13     widget=widgets.TextInput(attrs={'class':'form-control'}),
14     error_messages={'required':'姓名不能为空'})
15     sex=fields.CharField(required=True,error_messages={'required':'不能为空'},
16     widget = widgets.TextInput(attrs={'class': 'form-control'})
17 
18                          )
19     cls_id=fields.IntegerField(widget=widgets.Select(choices=models.Classes.objects.values_list('id','title'),
20     attrs = {'class': 'form-control'}
21 
22                                                      ),
23 
24                                 )
25 class teacher_form(Form):
26     tname=fields.CharField(required=True,error_messages={'required':"姓名不能为空"} )
27    #  classes=fields.CharField( #多选 不能用这个插件不使用request.post.getlist()取值
28    #      widget=widgets.Select(choices=models.Classes.objects.values_list(),
29    #      attrs={'multiple':'multiple'})
30    #                           )
31    #  classes=fields.CharField(widget=widgets.SelectMultiple(
32    # # 如果在fields.CharField字段该插件,得到会是{'tname': 'ww', 'classes': "['2', '3']"}字符串
33    #   choices= models.Classes.objects.values_list('id','title')) )
34     classes=fields.MultipleChoiceField(
35         choices=models.Classes.objects.values_list('id','title'),
36         widget=widgets.SelectMultiple,error_messages={'required':'选择不能为空'})
37     def __int__(self,*args,**kwargs):  #解决数据不同步的bug,每次form组件实例化时 都重新去数据库拿数据
38         super(teacher_form,self).__init__(*args,**kwargs)
39         self.fields['classes'].widget.choices=models.Classes.objects.values_list('id','title')
40 
41 
42 
43 class Test_form(Form):
44     name=fields.CharField()  #动态生成 text类型的input标签
45     text=fields.CharField(widget=widgets.Textarea,) #动态生成文本框
46     age=fields.CharField(widget=widgets.CheckboxInput) #动态生成单选框
47     holby=fields.MultipleChoiceField(                  #MultipleChoiceField动态生成复选框
48         choices=[(1,'篮球'),(2,"足球"),(3,"高俅")],
49         widget=widgets.CheckboxSelectMultiple)
50     sex=fields.MultipleChoiceField(
51         choices=[(1,''),(2,'')],
52         widget=widgets.RadioSelect
53     )
54 
55     select=fields.ChoiceField(choices=[(2, '北京'), (3, '唐县')]) #通过ChoiceField字段动态生成单选框
56                                                                    # 通过form组件的MultipleChoiceField字段
57     mselect=fields.MultipleChoiceField(choices=[(1,'管家佐'),(2,'万宝利') ],
58                                  widget=widgets.SelectMultiple)
59     file=fields.FileField()  #通过form组件的.FileField动态生成 文件上传input标签,注意在提交到后台是对象
View Code

 全局钩子函数

如果要想要同时对2个form字段进行验证,就需要全局钩子函数(应用 验证2次输入的密码是否一致),可以调用他们自定制复杂的form验证规则,

问题1:  注册页面输入为空,报错:keyError:找不到password

def clean(self):
        print("---",self.cleaned_data)
        #  if self.cleaned_data["password"]==self.cleaned_data["repeat_password"]:        
        #  报错原因:self.cleaned_data是干净数据,如果页面没有输入内容,则self.cleaned_data没有password。
        改如下:
        if self.cleaned_data.get("password")==self.cleaned_data.get("repeat_password"):
            return self.cleaned_data
        else:
            raise ValidationError("两次密码不一致")
View Code

  

四、渲染到模板

1.简单粗暴型

注意:模板语言{{form_obj.as_p}},一定要在设置lable参数

class UserInfoForm(Form):
    name=fields.CharField(required=True,error_messages={'reqired':'用户名不能为空'},label='姓名') 
    email=fields.EmailField(required=True,error_messages={'reqired':'用户名不能为空'},label='邮箱')
    pary=fields.ChoiceField(choices=[(1,"技术部"),(2,'销售部'),(3,'市场部'),],label='部门')
{{obj.as_p}}以P标签的形式全部显示

<table> 注意加table标签形式全部显示
{{obj.as_table}}
</table>


<ul>注意加ul标签形式全部显示
{{obj.as_table}}
</ul>
View Code

2.灵活定制型

<p>姓名:{{ obj.name }}</p>
<p>性别:{{ obj.sex }}</p>
<p>爱好: {{ obj.holby }}</p>
<p>婚姻状况:{{ obj.age }}</p>
<p>个人简介 {{ obj.text }}</p>
<p>工作地点: {{ obj.select }}</p>
<p>居住地点:{{ obj.mselect }}</p>
<p>资料上传:{{obj.file}}</p>
View Code

 

五、页面显示用户填完数据提交回来后台验证

数据校验

obj=classForm_login(request.POST )

默认校验:obj=classForm_login(data={} ) 含有错误信息: obj=Class_form(initial={'title':class_obj.title})只有html标签

obj.is_valid()  获取校验结果,验证通过返回True,失败则返回False

obj.errors获取错误信息

obj.cleand_data 获取正确的数据

 

六、基于Form组件的学生管理系统(项目)

路由

from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
    url(r'^classes/',views.classes),
    url(r'^classes_add(\d+)/',views.classes_add),
    url(r'^classes_edit(\d+)/',views.classes_edit),
    url(r'^students/',views.students),
    url(r'^students_add(\d+)/',views.students_add),
    url(r'^students.edit(\d+)/',views.students_edit),
    url(r'^teachers/',views.teacher),
    url(r'^teacher_add/',views.teacher_add),
    url(r'^teacher_edit(\d+)/',views.teacher_edit),
    url(r'^test/',views.test),
]
View Code

视图

  1 def classes(request):
  2     if request.method=='GET':
  3         c_list=models.Classes.objects.all()
  4         return render(request,'class_list.html',{'clist':c_list})
  5 
  6 def classes_add(request,args):
  7     if request.method=='GET':
  8         obj=Class_form()
  9         return render(request,'class_add.html',{'obj':obj})
 10     else:
 11         obj=Class_form(request.POST)
 12         if obj.is_valid():
 13             models.Classes.objects.create(**obj.cleaned_data )
 14             return redirect('/classes/')
 15         else:
 16             print('NI')
 17             return render(request,'class_add.html',{'obj':obj})
 18 
 19 def classes_edit(request,args):
 20     if request.method=='GET':
 21         class_obj=models.Classes.objects.filter(id=args).first()
 22         obj=Class_form(initial={'title':class_obj.title})
 23         return render(request,'class_edit.html',{'obj':obj,'nid':args})
 24     else:
 25         obj = Class_form(request.POST)
 26         if obj.is_valid():
 27             models.Classes.objects.filter(id=args).update(**obj.cleaned_data)
 28             return redirect('/classes/')
 29         else:
 30             return render(request, 'class_edit.html', {'obj': obj, 'nid': args})
 31 
 32 
 33 def students(request):
 34     if request.method=='GET':
 35         students=models.Student.objects.all()
 36         return render(request,'students.html',{'student':students})
 37 
 38 def students_add(request,nid):
 39     if request.method=='GET':
 40         obj=Students()
 41         return render(request,'student_add.html',{'obj':obj,'nid':nid})
 42     else:
 43         obj=Students(request.POST)
 44         if obj.is_valid():
 45             models.Student.objects.create(**obj.cleaned_data)
 46             return redirect('/students/')
 47         else:
 48             return render(request,'student_add.html',{'obj':obj,'nid':nid})
 49 
 50 
 51 def students_edit(request,nid):
 52     if request.method=='GET':
 53         # print(models.Student.objects.filter(id=nid).values('name','sex','cls_id').first())
 54         obj=Students(initial=models.Student.objects.filter(id=nid).values('name','sex','cls_id').first())
 55         return render(request,'student_edit.html',{'obj':obj,'nid':nid})
 56     else:
 57         obj1=Students(request.POST)
 58         if obj1.is_valid():
 59             models.Student.objects.filter(id=nid).update(**obj1.cleaned_data)
 60             return redirect('/students/')
 61         else:
 62             return render(request, 'student_edit.html', {'obj': obj1, 'nid': nid})
 63 
 64 def teacher(request):
 65     if request.method=='GET':
 66         teacher_list=models.teacher.objects.all()
 67         return render(request,'teacher_list.html',{'tlist':teacher_list})
 68 
 69 def teacher_add(request):
 70     if request.method=='GET':
 71         print(request.method)
 72         obj=teacher_form()
 73         return render(request,'teacher_add.html',{'obj':obj})
 74     else:
 75         obj=teacher_form(request.POST)
 76         if obj.is_valid():
 77             classe_ids=obj.cleaned_data.pop('classes') #老师任教的班级
 78             tname=obj.cleaned_data   #老师的姓名
 79             create_teacher=models.teacher.objects.create(**tname)
 80             create_teacher.c2t.add(*classe_ids)
 81             return redirect('/teachers/')
 82         else:
 83             return render(request,'teacher_add.html',{'obj':obj})
 84 
 85 
 86 def teacher_edit(request,arg):
 87     if request.method=='GET':
 88         teacher_obj=models.teacher.objects.filter(id=arg).first()
 89         classes_ids=teacher_obj.c2t.values_list('id')
 90         cid_list=list(zip(*classes_ids))[0] if list(zip(*classes_ids)) else[]
 91         # print(cid_list) 元组
 92         obj=teacher_form(initial={'tname':teacher_obj.tname,'classes':cid_list})
 93         return render(request,'teacher_edit.html',{'obj':obj,'nid':arg} )
 94     else:
 95         obj=teacher_form(request.POST)
 96         if obj.is_valid():
 97             teacher_name=obj.cleaned_data.pop('tname')
 98             models.teacher.objects.filter(id=arg).update(tname=teacher_name)
 99             obj1=models.teacher.objects.filter(id=arg).first()
100             classes=obj.cleaned_data.pop('classes')
101             obj1.c2t.set(classes)
102             return redirect('/teachers/')
103         else:
104             return render(request,'teacher_add.html',{'obj':obj})
105 
106 
107 def test(request):
108     if request.method=='GET':
109         obj=Test_form(initial={'holby':[ 1,2],'name':'张根','text':'我来自太行山','sex':1})
110         # # print(models.Student.cls.objects.values_list())
111         # obj=models.Student.objects.filter(id=1).first()
112         # print(obj.cls.title)
113         return render(request,'test.html',{'obj':obj})
View Code

form组件

 1 from django.shortcuts import render,HttpResponse,redirect
 2 from  app01 import models
 3 from django.forms import Form,fields
 4 from django.forms import widgets
 5 
 6 class Class_form(Form):
 7     title=fields.RegexField('全栈\d+',
 8                             # initial='全栈', #设置input标签中的默认值
 9                             min_length=2,
10                             required=True,
11                             error_messages={'invalid':"必须以全栈开头",
12                                             'min_length':'太短了',
13                                             'required':"不能为空",
14                                             }
15                             )
16 class Students(Form):
17     name=fields.CharField(required=True,
18     widget=widgets.TextInput(attrs={'class':'form-control'}),
19     error_messages={'required':'姓名不能为空'})
20     sex=fields.CharField(required=True,error_messages={'required':'不能为空'},
21     widget = widgets.TextInput(attrs={'class': 'form-control'})
22 
23                          )
24     cls_id=fields.IntegerField(widget=widgets.Select(choices=models.Classes.objects.values_list('id','title'),
25     attrs = {'class': 'form-control'}
26 
27                                                      ),
28 
29                                 )
30 class teacher_form(Form):
31     tname=fields.CharField(required=True,error_messages={'required':"姓名不能为空"} )
32    #  classes=fields.CharField( #多选 不能用这个插件不使用request.post.getlist()取值
33    #      widget=widgets.Select(choices=models.Classes.objects.values_list(),
34    #      attrs={'multiple':'multiple'})
35    #                           )
36    #  classes=fields.CharField(widget=widgets.SelectMultiple(
37    # # 如果在fields.CharField字段该插件,得到会是{'tname': 'ww', 'classes': "['2', '3']"}字符串
38    #   choices= models.Classes.objects.values_list('id','title')) )
39     classes=fields.MultipleChoiceField(
40         choices=models.Classes.objects.values_list('id','title'),
41         widget=widgets.SelectMultiple,error_messages={'required':'选择不能为空'})
42     def __int__(self,*args,**kwargs):  #解决数据不同步的bug,每次form组件实例化时 都重新去数据库拿数据
43         super(teacher_form,self).__init__(*args,**kwargs)
44         self.fields['classes'].choices=models.Classes.objects.values_list('id','title')
45 
46 
47 
48 class Test_form(Form):
49     name=fields.CharField()  #动态生成 text类型的input标签
50     text=fields.CharField(widget=widgets.Textarea,) #动态生成文本框
51     age=fields.CharField(widget=widgets.CheckboxInput) #动态生成单选框
52     holby=fields.MultipleChoiceField(                  #MultipleChoiceField动态生成复选框
53         choices=[(1,'篮球'),(2,"足球"),(3,"高俅")],
54         widget=widgets.CheckboxSelectMultiple)
55     sex=fields.MultipleChoiceField(
56         choices=[(1,''),(2,'')],
57         widget=widgets.RadioSelect
58     )
59 
60     select=fields.ChoiceField(choices=[(2, '北京'), (3, '唐县')]) #通过ChoiceField字段动态生成单选框
61                                                                    # 通过form组件的MultipleChoiceField字段
62     mselect=fields.MultipleChoiceField(choices=[(1,'管家佐'),(2,'万宝利') ],
63                                  widget=widgets.SelectMultiple)
64     file=fields.FileField()  #通过form组件的.FileField动态生成 文件上传input标签,注意在提交到后台是对象
View Code

模板

班级管理(1对1)

班级显示

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>班级列表</title>
 6     <link rel="stylesheet" href="/static/bootstrap-3.3.5-dist/css/bootstrap.css">
 7 </head>
 8 <body>
 9 <div style="width: 500px;margin: 0 auto">
10 <h1>班级列表</h1>
11 <ul>
12     {% for obj in clist %}
13         <li>{{ obj.title }}
14             <a href="/classes_add{{ obj.id }}/">添加</a>
15             <a href="/classes_edit{{ obj.id }}/">编辑</a>
16         </li>
17     {% endfor %}
18 </ul>
19 </div>
20 </body>
21 </html>
View Code

添加班级

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>添加班级</title>
</head>
<body>
<h1>添加班级</h1>
<form action='/classes_add{{2}}/' method="post" novalidate>
    {% csrf_token %}
  <p>班级添加:{{ obj.title}} {{ obj.errors.title.0}}</p>
   <p><input type="submit" value="提交"></p>
</form>

</body>
</html>
View Code

编辑班级

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>编辑班级</title>
</head>
<body>
<form action="/classes_edit{{nid}}/" method="post">
    {% csrf_token %}
   <p>编辑班级:{{ obj.title }}{{obj.title.errors.0}} </p>
    <input type="submit" value="提交">
</form>
</body>
</html>
View Code

 

学生管理1对多

学生显示

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>学生管理</title>
</head>
<body>
<h1>学生管理</h1>
<ul>
    {% for row in student %}
        <li>{{row.name}}
            {{row.sex}}
            <a href="/students_add{{row.id}}/">添加</a>
            <a href="/students.edit{{row.id}}/">编辑</a>
        </li>
    {% endfor %}
</ul>
</body>
</html>
View Code

学生添加

<!DOCTYPE html>
<html lang="en">
<head>
    <h1>添加学生</h1>
    <meta charset="UTF-8">
    <title>添加学生</title>
</head>
<body>
<form action="/students_add{{ nid}}/" method="post" novalidate>
     {% csrf_token%}
<p>姓名:{{ obj.name}}{{obj.name.errors.0}}</p>
<p>性别:{{ obj.sex}}{{obj.sex.errors.0}} </p>
<p>班级:{{ obj.cls_id }}{{ obj.errors.0}}  </p>
<p><input type="submit" value="提交"></p>
 </form>
</body>
</html>
View Code

学生编辑

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>老师编辑</title>
</head>
<body>
<form action="/teacher_edit{{ nid }}/" method="post">
    {% csrf_token %}
<p>老师姓名:{{obj.tname }}</p>
<p>班级:{{ obj.classes }}</p>
<input type="submit" value="提交">
</form>
</body>
</html>
View Code

 

 老师管理多对多

老师显示

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>老师列表</title>
 6 </head>
 7 <body>
 8 <table border="1">
 9 <thead>
10 <tr><td>ID</td><td>老师</td><td>任教班级</td><td colspan="3">操作</td></tr>
11 </thead>
12 <tbody>
13      {% for teacher in tlist %}
14     <tr>
15         <td>{{ teacher.id }}</td>
16         <td>{{teacher.tname}}</td>
17         <td>
18             {% for row in teacher.c2t.values %}
19             {{ row.title }}
20             {% endfor %}
21          </td>
22         <td><a href="/teacher_add/">添加</a></td>
23         <td><a href="/teacher_edit{{ teacher.id}}/">编辑</a></td>
24     </tr>
25     {% endfor %}
26 </tbody>
27 </table>
28 </body>
29 </html>
View Code

老师添加

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>添加老师</title>
</head>
<body>
<form action="/teacher_add/" method="post" novalidate>
{% csrf_token %}
<p>老师姓名:{{ obj.tname }}{{obj.tname.errors.0}}</p>
<p>任教班级:{{ obj.classes }}{{obj.classes.errors.0}}</p>
<p><input type="submit" value="提交"></p>
 </form>
</body>
</html>
View Code

老师编辑

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>老师编辑</title>
</head>
<body>
<form action="/teacher_edit{{ nid }}/" method="post">
    {% csrf_token %}
<p>老师姓名:{{obj.tname }}</p>
<p>班级:{{ obj.classes }}</p>
<input type="submit" value="提交">
</form>
</body>
</html>
View Code

 PS:Form验证组件验证ajax提交的json

Django的form组件,不仅可以对 浏览器端 提交过来的form表单数据做验证,还可以对ajax提交的 json数据 做验证,但是需要在发送之前获取CSRF-tocken设置在请求头中;

 1 $.ajax({
 2                 type: 'POST',
 3                 async: false,
 4                 cache: false,
 5                 url: '{% url "instance_add" %}',
 6                  headers:{"X-CSRFToken":$.cookie('csrftoken')},
 7                 contentType: "application/json; charset=utf-8",
 8                 dataType: "json",
 9                 traditional:true,
10                 data:JSON.stringify({
11                     "data_mode_type": $data_mode_type,
12                     'database_type': $database_type,
13                     'host': $host,
14                     'port': $port,
15                     'instance_nikename': $instance_nikename,
16                     'db_business': $db_business,
17                     'DBA': $DBA,
18                     'responsible_person': $responsible_person
19                 }),
20                 success: function (data) {
21                    alert(1)
22                 }
23             });
24         })
前端
from django.shortcuts import render,HttpResponse,redirect
from DB_auto.form_validate.add_dbinfo import dbinfo_create
import json

def instance_add(request):
    if request.method=='POST':
        json_data=json.loads(request.body.decode('utf-8'))
        obj=dbinfo_create(json_data)
        if obj.is_valid():
            print(obj.cleaned_data)
        else:
            print(obj.errors)
    return render(request,'add_dbinfo.html')
django后台

 

 七、ModelForm

使用Django开发web程序阶段回顾:

1.手动对单表进行增、删、该、查,手动把ORM操作获取的数据渲染到模板;(阶段1)

2.Form组件(类),自动生成标签(input、select),并对用户输入的数据做规则验证;(阶段2)

3.ModelForm顾名思义就Form和Django的Model数据库模型结合体,可以简单、方便得对数据库进行增加、编辑操作和验证标签的生成;

Form组件和ModelForm的区别

ModelForm是Django Model.py和Form组件的结合体,可以简单/快速使用 Form验证和数据库操作功能,但不如Form组件灵活,如果在使用Django做web开发过程中验证的数据和数据库字段相关(可以对表进行增、删、改操,注意 Many to many字段,也可以级联操作第3张关系表;),建议优先使用ModelForm,用起来更方便些,但是在使用ModelForm的时候慎用fields='__all__',获取数据库所有字段势必造成性能损耗;

 1 ModelForm
 2     a.  class Meta:
 3             model,                           # 对应Model的
 4             fields=None,                     # 字段
 5             exclude=None,                    # 排除字段
 6             labels=None,                     # 提示信息
 7             help_texts=None,                 # 帮助提示信息
 8             widgets=None,                    # 自定义插件
 9             error_messages=None,             # 自定义错误信息(整体错误信息from django.core.exceptions import NON_FIELD_ERRORS)
10             field_classes=None               # 自定义字段类 (也可以自定义字段)
11             localized_fields=('birth_date',) # 本地化,如:根据不同时区显示数据
12             如:
13                 数据库中
14                     2016-12-27 04:10:57
15                 setting中的配置
16                     TIME_ZONE = 'Asia/Shanghai'
17                     USE_TZ = True
18                 则显示:
19                     2016-12-27 12:10:57
20     b. 验证执行过程
21         is_valid -> full_clean -> 钩子 -> 整体错误
22  
23     c. 字典字段验证
24         def clean_字段名(self):
25             # 可以抛出异常
26             # from django.core.exceptions import ValidationError
27             return "新值"
28     d. 用于验证
29         model_form_obj = XXOOModelForm()
30         model_form_obj.is_valid()
31         model_form_obj.errors.as_json()
32         model_form_obj.clean()
33         model_form_obj.cleaned_data
34     e. 用于创建
35         model_form_obj = XXOOModelForm(request.POST)
36         #### 页面显示,并提交 #####
37         # 默认保存多对多
38             obj = form.save(commit=True)
39         # 不做任何操作,内部定义 save_m2m(用于保存多对多)
40             obj = form.save(commit=False)
41             obj.save()      # 保存单表信息
42             obj.save_m2m()  # 保存关联多对多信息
43  
44     f. 用于更新和初始化
45         obj = model.tb.objects.get(id=1)
46         model_form_obj = XXOOModelForm(request.POST,instance=obj)
47         ...
48  
49         PS: 单纯初始化
50             model_form_obj = XXOOModelForm(initial={...})
Django之ModelForm组件(wupeiqi)

使用ModelForm

前端:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
{{ form_obj.as_p }}
{#<p>姓名:{{form_obj.name  }}</p>#}
</body>
</html>
View Code

后端视图:

 1 from app02 import models
 2 from django.forms import ModelForm
 3 class UserModalForm(ModelForm):
 4     class Meta:
 5         model=models.UserInfo #(该字段必须为 model  数据库中表)
 6         fields= '__all__'   #(该字段必须为 fields 数据库中表)
 7 
 8 def add(request):
 9      # 实例化models_form
10     if request.method=='GET':
11         obj = UserModalForm()
12         return render(request,'rbac/user_add.html',locals())
13     else:
14         obj=UserModalForm(request.POST)
15         if obj.is_valid():
16             data=obj.cleaned_data
17             obj.save()  #form验证通过直接 添加用户信息到数据库
18         return render(request, 'rbac/user_add.html', locals())
View Code

 model.py:

使用使用Form组件和ModelForm注意事项:

1、model.py一点要写verbose_name='名称'参数,才会在前端显示P标签的标题;

from django.db import models

class Department(models.Model):
    title=models.CharField(max_length=32,verbose_name='部门名称')
    def __str__(self):
        return self.title

class UserInfo(models.Model):
    name=models.CharField(max_length=32,verbose_name='姓名')
    emai=models.EmailField(max_length=32,verbose_name='邮箱')
    pary=models.ForeignKey(Department,verbose_name='部门')
View Code

如果使用Form组件在前端显示标题,可以设置Form类中的lable参数

class UserInfoForm(Form):
    name=fields.CharField(required=True,error_messages={'reqired':'用户名不能为空'},label='姓名')
    email=fields.EmailField(required=True,error_messages={'reqired':'用户名不能为空'},label='邮箱')
    pary=fields.ChoiceField(choices=[(1,"技术部"),(2,'销售部'),(3,'市场部'),],label='部门')
View Code

2、pary=fields.ChoiceField(choices=models.Department.objects.values_list('pk','title'),label='部门'),前端select标签不能随数据库操作实时更新;

在Department表添加一条数据之后,前端select标签中的数据不能随数据库实时更新;

原因:

不管是ModelForm还是Form组件本质就是个类,fields(字段)本质就是类中的1个静态属性,在类第一次加载时赋值,永远不会更新;

 

解决方案1(手动档):

重写__init__方法,每次实例化对象,就去获取一次数据库内容,重新赋值;

class UserInfoForm(Form):
    name=fields.CharField(required=True,error_messages={'reqired':'用户名不能为空'},label='姓名')
    email=fields.EmailField(required=True,error_messages={'reqired':'用户名不能为空'},label='邮箱')
    pary=fields.ChoiceField(label='部门')
    # pary=fields.ChoiceField(choices=models.Department.objects.values_list('pk','title'),label='部门')
    def __init__(self,*args,**kwargs):
        super(UserInfoForm,self).__init__(*args,**kwargs)
        self.fields['pary'].choices=models.Department.objects.values_list('pk','title')
View Code

解决方案2(自动档)

导入ModelChoiceField 模块  from django.forms.models import ModelChoiceField 

使用ModelChoiceField 字段

from django.forms import fields
from django.forms import widgets
from django.forms import ModelForm
from django.forms.models import ModelChoiceField

class UserInfoForm(Form):
    name=fields.CharField(required=True,error_messages={'reqired':'用户名不能为空'},label='姓名')
    email=fields.EmailField(required=True,error_messages={'reqired':'用户名不能为空'},label='邮箱')
    #方案1
    pary=ModelChoiceField(queryset=models.Department.objects.all(),label='部门')
View Code

自动挡虽好,但是也有缺陷;前端option标签的内容,需要借助model.py中的__str__方法,生成;

八、扩展 widgets之富文本编辑框

 如果你的web应用涉及到了发表文章、表情评论就必须使用富文本编辑框,小编调研了两款 Kindeditor、CKeditor;

Kindeditor

1.Kindeditor简介

http://kindeditor.net/docs/usage.html

2.下载Kindeditor编辑器

http://www.kindsoft.net/down.php

3.引入Kindeditor编辑器

<script src="/static/kindeditor-4.1.10/kindeditor-all.js"></script>

4.使用Kindeditor编辑器

a.创建textarea 标签

<textarea name="content" id="a" cols="30" rows="10"></textarea>

b.初始化Kindeditor

复制代码
<script>
  var edit=KindEditor.create('#a',{
        width:'700px',
        height:'500px',
        uploadJson:'/upload_file/',
        extraFileUploadParams:{
            'csrfmiddlewaretoken':'{{ csrf_token }}',}})
</script>
复制代码

c. Kindeditor功能定制

复制代码
<script>
        var edit = KindEditor.create('#a', {
            items: [ //填写自己想要的功能
                'fontname', 'fontsize', '|', 'forecolor', 'hilitecolor', 'bold', 'italic', 'underline',
                'removeformat', '|', 'justifyleft', 'justifycenter', 'justifyright', 'insertorderedlist',
                'insertunorderedlist', '|', 'emoticons', 'image', 'link'],
            width: '700px',
            height: '500px',
            uploadJson: '/upload_file/',
            extraFileUploadParams: {
                'csrfmiddlewaretoken': '{{ csrf_token }}',
            }
        })
    </script>
复制代码

d.kindeditor的API

复制代码
// 取得HTML内容
html = editor.html();

// 同步数据后可以直接取得textarea的value
editor.sync();
html = document.getElementById('editor_id').value; // 原生API
html = K('#editor_id').val(); // KindEditor Node API
html = $('#editor_id').val(); // jQuery

// 设置HTML内容
editor.html('HTML内容');
复制代码

 

CKeditor结合Django Form

1.下载  django-ckeditor 和pillow

pip install django-ckeditor 
pip install pillow

2.setings

复制代码
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rbac.apps.RbacConfig',
    'arya.apps.AryaConfig',
    'cmdb.apps.CmdbConfig',
    'rest_framework',
    'ckeditor',
    # 'ckeditor_uploader'
]
复制代码
CKEDITOR_CONFIGS = {
    'default': {
        'toolbar': (
            # ['div','Source','-','Save','NewPage','Preview','-','Templates'],
            # ['Cut','Copy','Paste','PasteText','PasteFromWord','-','Print','SpellChecker','Scayt'],
            # ['Undo','Redo','-','Find','Replace','-','SelectAll','RemoveFormat'],
            # ['Form','Checkbox','Radio','TextField','Textarea','Select','Button', 'ImageButton','HiddenField'],
            # ['Bold','Italic','Underline','Strike','-','Subscript','Superscript'],
            # ['NumberedList','BulletedList','-','Outdent','Indent','Blockquote'],
            # ['JustifyLeft','JustifyCenter','JustifyRight','JustifyBlock'],
            # ['Link','Unlink','Anchor'],
            ['Smiley',],

            # ['Styles','Format','Font','FontSize'],
            # ['TextColor','BGColor'],
            # ['Maximize','ShowBlocks','-','About', 'pbckcode'],

        ),
    }
}
功能定制

3. 收集Django 项目所有 静态文件  到的目录static目录   /   直接下载ckeditor到项目static

  设置media路径+static路径

注意:此步骤如果提示 需要你设置MEDIA_URL目录 和STATIC_ROOT 就先暂且设置一下,最终目的是把CKeditor的js插件copy到你的静态文件存放目录下;

4.后端生成 textarea +加前端 ckedit 插件生成 富文本编辑

from ckeditor.widgets import CKEditorWidget
class comment(Form): #评论框
    content =fields.CharField(widget=CKEditorWidget)
{{ obj.content|safe }}

<script src="/static/pligin/ckeditor/ckeditor-init.js"></script>
<script src="/static/pligin/ckeditor/ckeditor/ckeditor.js"></script>
View Code

5.CKEditorWidget API

复制代码
  <script>
        $('.root_reply_btn').click(function () {
            var $reply_user = $(this).attr('name');
            var $pid = $(this).attr('pid');
            $('#comment_submit').attr('pid', $pid);
            CKEDITOR.instances.id_content.insertText('回复' + $reply_user + ':');
            CKEDITOR.instances.id_content.insertHtml('<br>');
            CKEDITOR.instances.id_content.focus(); #使CKEditorWidget进入编辑状态 (MD在后台测试了半天!!)


        });
CKEDITOR.instances.id_content.document.$.body.firstChild.textContent 获取p标签的文本内容 </script>
复制代码

6.完成效果

博客链接:http://www.cnblogs.com/wupeiqi/articles/6144178.html

                  https://www.cnblogs.com/SHENGXIN/p/7643554.html

                  http://www.cnblogs.com/yuanchenqi/articles/7439088.html#3770465

                  DjangoForm补充:http://www.cnblogs.com/yuanchenqi/articles/7487059.html

转载于:https://www.cnblogs.com/lbzbky/articles/10975632.html

表情包
插入表情
评论将由博主筛选后显示,对所有人可见 | 还能输入1000个字符
相关推荐
SystemVerilog的听课学习笔记,包括讲义截取知识点记录注意事项等细节的标注。 目录如下: 第一章 SV环境构建常识 1 1.1 数据类型 1 四二值逻辑 4 定宽数组 9 foreach 13 动态数组 16 队列 19 关联数组 21 枚举类型 23 字符串 25 1.2 过程块和方法 27 initial和always 30 function逻辑电路 33 task时序电路 35 动态 静态变量 39 1.3 设计例化和连接 45 第二章 验证的方法 393 动态仿真 395 静态检查 397 虚拟模型 403 硬件加速 405 效能验证 408 性能验证 410 第三章 SV组件实现 99 3.1 接口 100 什么是interface 101 接口的优势 108 3.2 采样和数据驱动 112 竞争问题 113 接口中的时序块clocking 123 利于clocking的驱动 133 3.3 测试的开始和结束 136 仿真开始 139 program隐式结束 143 program显式结束 145 软件域program 147 3.4 调试方法 150 第四章 验证的计划 166 4.1 计划概述 166 4.2 计划的内容 173 4.3 计划的实现 185 4.4 计划的进程评估 194 第五章 验证的管理 277 6.1 验证的周期检查 277 6.2 管理三要素 291 6.3 验证的收敛 303 6.4 问题追踪 314 6.5 团队建设 321 6.6 验证的专业化 330 第六章 验证平台的结构 48 2.1 测试平台 49 2.2 硬件设计描述 55 MCDF接口描述 58 MCDF接口时序 62 MCDF寄存器描述 65 2.3 激励发生器 67 channel initiator 72 register initiator 73 2.4 监测器 74 2.5 比较器 81 2.6 验证结构 95 第七章 激励发生封装:类 209 5.1 概述 209 5.2 类的成员 233 5.3 类的继承 245 三种类型权限 protected/local/public 247 this super 253 成员覆盖 257 5.4 句柄的使用 263 5.5 包的使用 269 第八章 激励发生的随机化 340 7.1 随机约束和分布 340 权重分布 353 条件约束 355 7.2 约束块控制 358 7.3 随机函数 366 7.4 数组约束 373 7.5 随机控制 388 第九章 线程与通信 432 9.1 线程的使用 432 9.2 线程的控制 441 三个fork...join 443 等待衍生线程 451 停止线程disable 451 9.3 线程的通信 458 第十章 进程评估:覆盖率 495 10.1 覆盖率类型 495 10.2 功能覆盖策略 510 10.3 覆盖组 516 10.4 数据采样 524 10.5 覆盖选项 544 10.6 数据分析 550 第十一章 SV语言核心进阶 552 11.1 类型转换 552 11.2 虚方法 564 11.3 对象拷贝 575 11.4 回调函数 584 11.5 参数化的类 590 第十二章 UVM简介 392 8.2 UVM简介 414 8.3 UVM组件 420 8.4 UVM环境 425
<p> 课程演示环境:<span>Ubuntu</span> </p> <p> <span> </span> </p> <p> 需要学习<span>Windows</span>系统<span>YOLOv4-tiny</span>的同学请前往《<span>Windows</span>版<span>YOLOv4-tiny</span>目标检测实战:训练自己的数据集》 <span></span> </p> <p> <span> </span> </p> <p> <span style="color:#E53333;">YOLOv4-tiny</span><span style="color:#E53333;">来了!速度大幅提升!</span><span></span> </p> <p> <span> </span> </p> <p> <span>YOLOv4-tiny</span>在<span>COCO</span>上的性能可达到:<span>40.2% AP50, 371 FPS (GTX 1080 Ti)</span>。相较于<span>YOLOv3-tiny</span>,<span>AP</span>和<span>FPS</span>的性能有巨大提升。并且,<span>YOLOv4-tiny</span>的权重文件只有<span>23MB</span>,适合在移动端嵌入式设备边缘计算等设备上部署。<span></span> </p> <p> <span> </span> </p> <p> 本课程将手把手地教大家使用<span>labelImg</span>标注和使用<span>YOLOv4-tiny</span>训练自己的数据集。课程实战分为两个项目:单目标检测(足球目标检测)和多目标检测(足球和梅西同时检测)。<span></span> </p> <p> <span> </span> </p> <p> 本课程的<span>YOLOv4-tiny</span>使用<span>AlexAB/darknet</span>,在<span>Ubuntu</span>系统上做项目演示。包括:<span>YOLOv4-tiny</span>的网络结构安装<span>YOLOv4-tiny</span>标注自己的数据集整理自己的数据集修改配置文件训练自己的数据集测试训练出的网络模型性能统计<span>(mAP</span>计算和画出<span>PR</span>曲线<span>)</span>和先验框聚类分析。 <span> </span> </p> <p> <span> </span> </p> <p> 除本课程《<span>YOLOv4-tiny</span>目标检测实战:训练自己的数据集》外,本人推出了有关<span>YOLOv4</span>目标检测的系列课程。请持续关注该系列的其它视频课程,包括:<span></span> </p> <p> 《<span>YOLOv4</span>目标检测实战:训练自己的数据集》<span></span> </p> <p> 《<span>YOLOv4</span>目标检测实战:人脸口罩佩戴识别》<span></span> </p> <p> 《<span>YOLOv4</span>目标检测实战:中国交通标志识别》<span></span> </p> <p> 《<span>YOLOv4</span>目标检测:原理与源码解析》<span></span> </p> <p> <br /> </p> <p> <br /> </p> <p> <img alt="" src="https://img-bss.csdnimg.cn/202007061437441198.jpg" /> </p> <img alt="" src="https://img-bss.csdnimg.cn/202007061438066851.jpg" />
<p> <b><span style="background-color:#FFE500;">【超实用课程内容】</span></b> </p> <p> <br /> </p> <p> <br /> </p> <p> 本课程内容包含讲解<span>解读Nginx的基础知识,</span><span>解读Nginx的核心知识带领学员进行</span>高并发环境下的Nginx性能优化实战,让学生能够快速将所学融合到企业应用中。 </p> <p> <br /> </p> <p style="font-family:Helvetica;color:#3A4151;font-size:14px;background-color:#FFFFFF;"> <b><br /> </b> </p> <p style="font-family:Helvetica;color:#3A4151;font-size:14px;background-color:#FFFFFF;"> <b><span style="background-color:#FFE500;">【课程如何观看?】</span></b> </p> <p style="font-family:Helvetica;color:#3A4151;font-size:14px;background-color:#FFFFFF;"> PC端:<a href="https://edu.csdn.net/course/detail/26277"><span id="__kindeditor_bookmark_start_21__"></span></a><a href="https://edu.csdn.net/course/detail/27216">https://edu.csdn.net/course/detail/27216</a> </p> <p style="font-family:Helvetica;color:#3A4151;font-size:14px;background-color:#FFFFFF;"> 移动端:CSDN 学院APP(注意不是CSDN APP哦) </p> <p style="font-family:Helvetica;color:#3A4151;font-size:14px;background-color:#FFFFFF;"> 本课程为录播课,课程永久有效观看时长,大家可以抓紧时间学习后一起讨论哦~ </p> <p style="font-family:"color:#3A4151;font-size:14px;background-color:#FFFFFF;"> <br /> </p> <p class="ql-long-24357476" style="font-family:"color:#3A4151;font-size:14px;background-color:#FFFFFF;"> <strong><span style="background-color:#FFE500;">【学员专享增值服务】</span></strong> </p> <p class="ql-long-24357476" style="font-family:"color:#3A4151;font-size:14px;background-color:#FFFFFF;"> <b>源码开放</b> </p> <p class="ql-long-24357476" style="font-family:"color:#3A4151;font-size:14px;background-color:#FFFFFF;"> 课件课程案例代码完全开放给你,你可以根据所学知识,自行修改优化 </p> <p class="ql-long-24357476" style="font-family:"color:#3A4151;font-size:14px;background-color:#FFFFFF;"> 下载方式:电脑登录<a href="https://edu.csdn.net/course/detail/26277"></a><a href="https://edu.csdn.net/course/detail/27216">https://edu.csdn.net/course/detail/27216</a>,播放页面右侧点击课件进行资料打包下载 </p> <p> <br /> </p> <p> <br /> </p> <p> <br /> </p>
<p> <span style="color:#0000ff;">需要学习ubuntu系统上YOLOv4的同学请前往:《YOLOv4目标检测实战:原理与源码解析》</span> </p> <h3> <span style="color:#3598db;">【为什么要学习这门课】</span> </h3> <p> Linux创始人Linus Torvalds有一句名言:Talk is cheap. Show me the code. <strong><span style="color:#ba372a;">冗谈不够,放码过来!</span></strong> </p> <p> 代码阅读是从基础到提高的必由路。尤其对深度学习,许多框架隐藏了神经网络底层的实现,只能在上层调包使用,对其内部原理很难认识清晰,不利于进一步优化和创新。 </p> <p> YOLOv4是最近推出的基于深度学习的端到端实时目标检测方法。 </p> <p> YOLOv4的实现darknet是使用C语言开发的轻型开源深度学习框架,依赖少,可移植性好,可以作为很好的代码阅读案例,让我们深入探究其实现原理。 </p> <h3> <span style="color:#3598db;">【课程内容与收获】</span> </h3> <p> 本课程将解析YOLOv4的实现原理和源码,具体内容包括: </p> <p> - YOLOv4目标检测原理 </p> <p> - 神经网络及darknet的C语言实现,尤其是反向传播的梯度求解和误差计算 </p> <p> - 代码阅读工具及方法 </p> <p> - 深度学习计算的利器:BLAS和GEMM </p> <p> - GPU的CUDA编程方法及在darknet的应用 </p> <p> - YOLOv4的程序流程 </p> <p> - YOLOv4各层及关键技术的源码解析 </p> <p> 本课程将提供注释后的darknet的源码程序文件。 </p> <h3> <span style="color:#3598db;">【相关课程】</span> </h3> <p> 除本课程《Windows版YOLOv4目标检测:原理与源码解析》外,本人推出了有关YOLOv4目标检测的系列课程,包括: </p> <p> 《Windows版YOLOv4目标检测实战:训练自己的数据集》 </p> <p> 《Windows版YOLOv4-Tiny目标检测实战:训练自己的数据集》 </p> <p> 《Windows版YOLOv4目标检测实战:人脸口罩佩戴检测》<br /> 《Windows版YOLOv4目标检测实战:中国交通标志识别》 </p> <p> 建议先学习一门YOLOv4实战课程,对YOLOv4的使用方法了解以后再学习本课程。 </p> <h3> <span style="color:#3598db;">【YOLOv4网络模型架构图】</span> </h3> <p> 下图由白勇老师绘制<img alt="" src="https://img-bss.csdnimg.cn/202006291533009066.jpg" /> </p> <p>   </p>
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页