首页 > 代码库 > Django之Form

Django之Form

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

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

一、基本结构

1.views.py中创建Form类

1 from django.forms import Form
2 
3 # Create your views here.
4 class ClassForm(Form):
5     title= fields.RegexField(全栈\d+)

2.views.py中函数处理

 1 def add_class(request):
 2     if request.method==GET:
 3         obj=ClassForm()
 4         return render(request,add_class.html,{obj:obj})
 5     else:
 6         obj=ClassForm(request.POST)
 7         if obj.is_valid():
 8             models.Classes.objects.create(**obj.cleaned_data)
 9             return redirect(/classes/)
10         return render(request,add_class.html,{obj:obj})

3.生成HTML

1 <body>
2     <h1>添加班级</h1>
3     <form action="/add_class/" method="POST" novalidate>
4          {% csrf_token %}
5         {{ obj.title }}{{ obj.errors.title.0 }}
6         <input type="submit" value=http://www.mamicode.com/"提交">
7     </form>
8 </body>

二、Form类相关参数

创建Form类时,主要涉及到 【字段】 和 【插件】,字段用于对用户请求数据的验证,插件用于自动生成HTML;

1、Django内置字段如下:

技术分享
  1 Field
  2     required=True,               是否允许为空
  3     widget=None,                 HTML插件
  4     label=None,                  用于生成Label标签或显示内容
  5     initial=None,                初始值
  6     help_text=‘‘,                帮助信息(在标签旁边显示)
  7     error_messages=None,         错误信息 {required: 不能为空, invalid: 格式错误}
  8     show_hidden_initial=False,   是否在当前插件后面再加一个隐藏的且具有默认值的插件(可用于检验两次输入是否一直)
  9     validators=[],               自定义验证规则
 10     localize=False,              是否支持本地化
 11     disabled=False,              是否可以编辑
 12     label_suffix=None            Label内容后缀
 13  
 14  
 15 CharField(Field)
 16     max_length=None,             最大长度
 17     min_length=None,             最小长度
 18     strip=True                   是否移除用户输入空白
 19  
 20 IntegerField(Field)
 21     max_value=http://www.mamicode.com/None,              最大值
 22     min_value=http://www.mamicode.com/None,              最小值
 23  
 24 FloatField(IntegerField)
 25     ...
 26  
 27 DecimalField(IntegerField)
 28     max_value=http://www.mamicode.com/None,              最大值
 29     min_value=http://www.mamicode.com/None,              最小值
 30     max_digits=None,             总长度
 31     decimal_places=None,         小数位长度
 32  
 33 BaseTemporalField(Field)
 34     input_formats=None          时间格式化   
 35  
 36 DateField(BaseTemporalField)    格式:2015-09-01
 37 TimeField(BaseTemporalField)    格式:11:12
 38 DateTimeField(BaseTemporalField)格式:2015-09-01 11:12
 39  
 40 DurationField(Field)            时间间隔:%d %H:%M:%S.%f
 41     ...
 42  
 43 RegexField(CharField)
 44     regex,                      自定制正则表达式
 45     max_length=None,            最大长度
 46     min_length=None,            最小长度
 47     error_message=None,         忽略,错误信息使用 error_messages={invalid: ...}
 48  
 49 EmailField(CharField)      
 50     ...
 51  
 52 FileField(Field)
 53     allow_empty_file=False     是否允许空文件
 54  
 55 ImageField(FileField)      
 56     ...
 57     注:需要PIL模块,pip3 install Pillow
 58     以上两个字典使用时,需要注意两点:
 59         - form表单中 enctype="multipart/form-data"
 60         - view函数中 obj = MyForm(request.POST, request.FILES)
 61  
 62 URLField(Field)
 63     ...
 64  
 65  
 66 BooleanField(Field)  
 67     ...
 68  
 69 NullBooleanField(BooleanField)
 70     ...
 71  
 72 ChoiceField(Field)
 73     ...
 74     choices=(),                选项,如:choices = ((0,上海),(1,北京),)
 75     required=True,             是否必填
 76     widget=None,               插件,默认select插件
 77     label=None,                Label内容
 78     initial=None,              初始值
 79     help_text=‘‘,              帮助提示
 80  
 81  
 82 ModelChoiceField(ChoiceField)
 83     ...                        django.forms.models.ModelChoiceField
 84     queryset,                  # 查询数据库中的数据
 85     empty_label="---------",   # 默认空显示内容
 86     to_field_name=None,        # HTML中value的值对应的字段
 87     limit_choices_to=None      # ModelForm中对queryset二次筛选
 88      
 89 ModelMultipleChoiceField(ModelChoiceField)
 90     ...                        django.forms.models.ModelMultipleChoiceField
 91  
 92  
 93      
 94 TypedChoiceField(ChoiceField)
 95     coerce = lambda val: val   对选中的值进行一次转换
 96     empty_value= http://www.mamicode.com/‘‘            空值的默认值
 97  
 98 MultipleChoiceField(ChoiceField)
 99     ...
100  
101 TypedMultipleChoiceField(MultipleChoiceField)
102     coerce = lambda val: val   对选中的每一个值进行一次转换
103     empty_value= http://www.mamicode.com/‘‘            空值的默认值
104  
105 ComboField(Field)
106     fields=()                  使用多个验证,如下:即验证最大长度20,又验证邮箱格式
107                                fields.ComboField(fields=[fields.CharField(max_length=20), fields.EmailField(),])
108  
109 MultiValueField(Field)
110     PS: 抽象类,子类中可以实现聚合多个字典去匹配一个值,要配合MultiWidget使用
111  
112 SplitDateTimeField(MultiValueField)
113     input_date_formats=None,   格式列表:[%Y--%m--%d, %m%d/%Y, %m/%d/%y]
114     input_time_formats=None    格式列表:[%H:%M:%S, %H:%M:%S.%f, %H:%M]
115  
116 FilePathField(ChoiceField)     文件选项,目录下文件显示在页面中
117     path,                      文件夹路径
118     match=None,                正则匹配
119     recursive=False,           递归下面的文件夹
120     allow_files=True,          允许文件
121     allow_folders=False,       允许文件夹
122     required=True,
123     widget=None,
124     label=None,
125     initial=None,
126     help_text=‘‘
127  
128 GenericIPAddressField
129     protocol=both,           both,ipv4,ipv6支持的IP格式
130     unpack_ipv4=False          解析ipv4地址,如果是::ffff:192.0.2.1时候,可解析为192.0.2.1, PS:protocol必须为both才能启用
131  
132 SlugField(CharField)           数字,字母,下划线,减号(连字符)
133     ...
134  
135 UUIDField(CharField)           uuid类型
136     ...
View Code

2、Django内置插件:

技术分享
 1 TextInput(Input)
 2 NumberInput(TextInput)
 3 EmailInput(TextInput)
 4 URLInput(TextInput)
 5 PasswordInput(TextInput)
 6 HiddenInput(TextInput)
 7 Textarea(Widget)
 8 DateInput(DateTimeBaseInput)
 9 DateTimeInput(DateTimeBaseInput)
10 TimeInput(DateTimeBaseInput)
11 CheckboxInput
12 Select
13 NullBooleanSelect
14 SelectMultiple
15 RadioSelect
16 CheckboxSelectMultiple
17 FileInput
18 ClearableFileInput
19 MultipleHiddenInput
20 SplitDateTimeWidget
21 SplitHiddenDateTimeWidget
22 SelectDateWidget
View Code

三、常用插件选择

 

 1 # 单radio,值为字符串
 2 # user = fields.CharField(
 3 #     initial=2,
 4 #     widget=widgets.RadioSelect(choices=((1,上海),(2,北京),))
 5 # )
 6  
 7 # 单radio,值为字符串
 8 # user = fields.ChoiceField(
 9 #     choices=((1, 上海), (2, 北京),),
10 #     initial=2,
11 #     widget=widgets.RadioSelect
12 # )
13  
14 # 单select,值为字符串
15 # user = fields.CharField(
16 #     initial=2,
17 #     widget=widgets.Select(choices=((1,上海),(2,北京),))
18 # )
19  
20 # 单select,值为字符串
21 # user = fields.ChoiceField(
22 #     choices=((1, 上海), (2, 北京),),
23 #     initial=2,
24 #     widget=widgets.Select
25 # )
26  
27 # 多选select,值为列表
28 # user = fields.MultipleChoiceField(
29 #     choices=((1,上海),(2,北京),),
30 #     initial=[1,],
31 #     widget=widgets.SelectMultiple
32 # )
33  
34  
35 # 单checkbox
36 # user = fields.CharField(
37 #     widget=widgets.CheckboxInput()
38 # )
39  
40  
41 # 多选checkbox,值为列表
42 # user = fields.MultipleChoiceField(
43 #     initial=[2, ],
44 #     choices=((1, 上海), (2, 北京),),
45 #     widget=widgets.CheckboxSelectMultiple
46 # )

在使用选择标签时,需要注意choices的选项可以从数据库中获取,但是由于是静态字段 ***获取的值无法实时更新***,那么需要自定义构造方法从而达到此目的。

方式一:

 1 from django.forms import Form
 2 from django.forms import widgets
 3 from django.forms import fields
 4 from django.core.validators import RegexValidator
 5  
 6 class MyForm(Form):
 7  
 8     user = fields.ChoiceField(
 9         # choices=((1, 上海), (2, 北京),),
10         initial=2,
11         widget=widgets.Select
12     )
13  
14     def __init__(self, *args, **kwargs):
15         super(MyForm,self).__init__(*args, **kwargs)
16         # self.fields[user].widget.choices = ((1, 上海), (2, 北京),)
17         # 或
18         self.fields[user].widget.choices = models.Classes.objects.all().value_list(id,caption)

方式二:

使用django提供的ModelChoiceField和ModelMultipleChoiceField字段来实现

 1 from django import forms
 2 from django.forms import fields
 3 from django.forms import widgets
 4 from django.forms import models as form_model
 5 from django.core.exceptions import ValidationError
 6 from django.core.validators import RegexValidator
 7  
 8 class FInfo(forms.Form):
 9     authors = form_model.ModelMultipleChoiceField(queryset=models.NNewType.objects.all())
10     # authors = form_model.ModelChoiceField(queryset=models.NNewType.objects.all())
11 自定义验证规则

四、个别Form方法实例

1.由于利用form提交会刷新页面,故提交信息无法保留。如用户提交信息错误时,提交信息想在原表中保留,可用以下两种方法:

方法一:

a、views.py

 1 from django.shortcuts import render,HttpResponse,redirect
 2 from django.forms import Form,fields
 3 
 4 # Create your views here.
 5 class LoginForm(Form):
 6     user = fields.CharField(min_length=8,max_length=15)
 7     pwd = fields.CharField(min_length=6)
 8     email=fields.EmailField()
 9 
10 def login(request):
11     if request.method == GET:
12         obj=LoginForm()  #利用obj对象生成input标签
13         return render(request,login.html,{obj:obj})
14     else:
15         obj = LoginForm(request.POST)
16         if obj.is_valid():
17             return HttpResponse(ok)
18         return render(request,login.html,{obj: obj})

b.login.html

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>Title</title>
 6 </head>
 7 <body>
 8     <form id="f1" action="/login/" method="POST" novalidate>
 9         {% csrf_token %}
10         <p>
11             {{ obj.user }}{{ obj.errors.user.0 }}{# 重点是这里 #}
12         </p>
13         <p>
14             {{ obj.pwd }}{{ obj.errors.pwd.0 }}
15         </p>
16         <p>
17             {{ obj.email }}{{ obj.errors.email.0 }}
18         </p>
19         <input type="submit" value=http://www.mamicode.com/"提交" />
20     </form>
21 </body>
22 </html>

本方法主要是在用户提交信息错误时,重新向html提交obj,重新渲染html,达到保存原来输入信息的功能

方法二:

a.view.py

 1 from django.shortcuts import render,HttpResponse,redirect
 2 from django.forms import Form,fields
 3 import json
 4 
 5 # Create your views here.
 6 class LoginForm(Form):
 7     user = fields.CharField(min_length=8,max_length=15)
 8     pwd = fields.CharField(min_length=6)
 9     email=fields.EmailField()
10 
11 def login(request):
12     return render(request,login.html)
13 
14 def ajax_login(request):
15     ret = {status: True,msg: None}
16     obj = LoginForm(request.POST)
17     if obj.is_valid():
18         v = json.dumps(ret)
19         return HttpResponse(v)
20     else:
21         ret[status] = False
22         ret[msg] = obj.errors
23         v = json.dumps(ret)
24         return HttpResponse(v)

b.html

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>Title</title>
 6 </head>
 7 <body>
 8     <form id="f1">
 9         {% csrf_token %}
10         <p>
11             <input type="text" name="user">
12         </p>
13         <p>
14             <input type="password" name="pwd">
15         </p>
16         <p>
17             <input type="email" name="email">
18         </p>
19     </form>
20     <input type="button" onclick="submitForm();" value=http://www.mamicode.com/"提交">
21     <script src=http://www.mamicode.com/"/static/jquery-3.2.1.js"></script>
22     <script>
23         function submitForm(){
24             $(.c1).remove();
25             $.ajax({
26                 url: /ajax_login/,
27                 type: POST,
28                 data: $(#f1).serialize(),//取得序列化表单值的结果
29                 dataType:"JSON",
30                 success:function(arg){
31                     console.log(arg);
32                     if(arg.status){
33                         location.href=http://www.mamicode.com/"http://www.baidu.com";
34                     }else{
35                         $.each(arg.msg,function(index,value){
36                             console.log(index,value);
37                             var tag = document.createElement(span);
38                             tag.innerHTML = value[0];
39                             tag.className = c1;
40                             $(#f1).find(input[name="+ index +"]).after(tag);
41                         })
42                     }
43                 }
44             })
45         }
46     </script>
47 
48 </body>
49 </html>

ajax提交数据不刷新页面的特性来完成该功能,同时也借用Form的验证功能

2.数据库数据变更时,解决页面无法动态刷新数据的方法

方法一:

 1 #教师表单验证规则
 2 class TchForm(Form):
 3     name = fields.CharField(max_length=16, min_length=2, widget=widgets.TextInput(attrs={class: form-control}))
 4     t2c = fields.MultipleChoiceField(
 5         # choices=models.Classes.objects.values_list(id, title),
 6         widget=widgets.SelectMultiple(attrs={class: form-control})
 7     )
 8 
 9     def __init__(self, *args, **kwargs):    # 自定义__init__
10         super(TchForm, self).__init__(*args, **kwargs)  # 调用父类的__init__
11         self.fields[t2c].choices = models.Classes.objects.values_list(id, title)   # 为字段t2c的choices赋值

方法二:

 1 #教师表单验证规则
 2 from django.forms import models as form_models  # 导入django.forms.models
 3 class TchForm(Form):
 4     name = fields.CharField(max_length=16, min_length=2, widget=widgets.TextInput(attrs={class: form-control}))
 5     #重新定义字段
 6     t2c = form_models.ModelMultipleChoiceField(
 7         # choices=models.Classes.objects.values_list(id, title),
 8         queryset=models.Classes.objects.all(),  # 利用queryset连接数据库,只能连接object类型
 9         widget=widgets.SelectMultiple(attrs={class: form-control})
10     )

 3.上传文件

方法一:

a.views.py

 1 def f1(request):
 2     if request.method==GET:
 3         return render(request,f1.html)
 4     else:
 5         file_obj=request.FILES.get(fafafa)
 6         f=open(os.path.join(static,file_obj.name),wb)
 7         for chunk in file_obj.chunks():
 8             f.write(chunk)
 9         f.close()
10         return render(request,f1.html)

b.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form action="/f1/" method="POST" enctype="multipart/form-data">
        {% csrf_token %}
        <input type="text" name="user">
        <input type="file" name="fafafa">
        <input type="submit" value=http://www.mamicode.com/"提交">
    </form>
</body>
</html>

方法二:

a.views.py

 1 class F2Form(Form):
 2     user=fields.CharField()
 3     fafafa=fields.FileField()
 4 
 5 def handle_uploaded_file(f):
 6     with open(os.path.join(static,f.name), wb+) as destination:
 7         for chunk in f.chunks():
 8             destination.write(chunk)
 9 
10 def f2(request):
11     if request.method==GET:
12         obj=F2Form()
13         return render(request,f2.html,{obj:obj})
14     else:
15         obj=F2Form(data=http://www.mamicode.com/request.POST,files=request.FILES)
16         if obj.is_valid():
17             print(obj.cleaned_data.get(fafafa).name)
18             print(obj.cleaned_data.get(fafafa).size)
19             handle_uploaded_file(request.FILES[fafafa])
20         return render(request, f2.html, {obj: obj})

b.html

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>Title</title>
 6 </head>
 7 <body>
 8     <form action="/f2/" method="POST" enctype="multipart/form-data">
 9         {% csrf_token %}
10         {{ obj.user }}
11         {{ obj.fafafa }}
12         <input type="submit" value=http://www.mamicode.com/"提交">
13     </form>
14 </body>
15 </html>

 

Django之Form