1. form组件的特点
以注册为例:
  a. 要有一个注册的页面,页面里面要有form表单  -->自动生成HTML代码
  b. form表单要能提交数据到后端,后端要做有效性的校验   -->数据有效性校验
  c. 要把校验提示信息显示到页面上    -->校验信息返回并展示,并保存原来填写的内容

2. form组件简单使用
2.1 自己生成简单form表单
2.1.1. url

url(r'^reg.html', views.reg),

 

2.1.2. views视图

from django import forms # 导入forms组件
class RegForm(forms.Form):	# 定义一个生成form表单的类,这个类和在app的models中创建表特别类似
    name = forms.CharField(max_length=32,label='用户名')	# 生成输入用户名的input框,max_length最大值,label设置中文 
    pwd = forms.CharField(label='密码') # 生成输入密码的input框

def reg(request):	# 展示网站函数
    form_obj = RegForm() # 实例化上面定义的类,将实例化的对象传到html中去
    return render(request,'reg.html',{'form_obj':form_obj})

  

2.1.3. html代码

<form action="/reg.html" method="post" novalidate> # novalidate取消浏览器做的校验
    {% csrf_token %} 
    {{ form_obj.as_p }} # 这句代码自动生成两个input框
    <input type="submit"> # 自己补一个提交按钮
</form>

 

2.2  数据有效性校验
2.2.1. views视图代码

from django import forms
class RegForm(forms.Form):
    name = forms.CharField(
        max_length=32,
        label='用户名',
        error_messages={
            'required': '该字段不能为空',
        },
    )

    pwd = forms.CharField(
        min_length=6,
        max_length=16,
        label='密码',
        error_messages={ # 自定义错误信息,如果验证不通过则提示
            'min_length':'密码最小不能少于6位',
            'max_length':'密码最长不能大于16位',
            'required': '该字段不能为空',
            },
      )

def reg(request):
    form_obj = RegForm()
    if request.method == 'POST': 
        form_obj = RegForm(request.POST)	# 如果post请求提交后,则对RegForm重新实例化,并传值进去

        if form_obj.is_valid(): # 对验证结果做判断,如果验证成功则继续往下走,如果不成功则直接执行下面return代码
            pass

    return render(request,'reg.html',{'form_obj':form_obj})

 

2.2.2. html代码

<form action="/reg.html" method="post" novalidate>
    {% csrf_token %}
    {{ form_obj.as_p }}
    {{ form_obj.errors.pwd }} # 提示自定义的错误信息,并指定提示的位置
    <input type="submit">
</form>

 

3. form组件的详细用法
3.1 导入forms模块

from django import forms


3.2 定义一个form类

class RegForm(forms.Form)
    username = forms.CharField()	# 用户名对应的input框
    password = forms.CharField()	# 密码对应的input框
    email = forms.EmailField()	# 邮箱对应的input框

    每个input框所能设置的参数
        max_length # 最长
        min_length	# 最短
        label	# 设置中文
        error_messages	# 错误信息
        validators	# 自定义校验信息

 

3.3 生成HTML代码

form_obj = RegForm() # 实例化RegForm类,并把form_obj这个对象传到模板中

 

3.3.1 第一种写法

{{form_obj.as_p}}	# 生成input框,缺点:都是用p标签包裹

 

3.3.2 第二种写法
用户名

{{ form_obj.name.label }}
{{ form_obj.name }}
<span class="help-block">{{ form_obj.name.errors.0 }}</span>

 

密码

{{ form_obj.pwd.label }} # 取类中的lable参数
{{ form_obj.pwd }}	# 取类中pwd字段
<span class="help-block">{{ form_obj.pwd.errors.0 }}</span>

 

3.4 校验
views视图函数中

form_obj = RegForm(request.POST)
form_obj.is_valid()

 

3.5 常用字段和字段参数

 1 from django.forms import widgets
 2 
 3 # 用户名(TextInput 文本相关)
 4 name = forms.CharField(
 5         max_length=32,
 6         label='用户名',
 7         error_messages={
 8             'required': '该字段不能为空',
 9         },
10         widget=widgets.TextInput(attrs={'class':'form-control'}),
11     )
12 
13 # 密码(PasswordInput)
14 pwd = forms.CharField(
15         min_length=6,
16         max_length=16,
17         label='密码',
18         error_messages={ # 自定义错误信息,如果验证不通过则提示
19             'min_length':'密码最小不能少于6位',
20             'max_length':'密码最长不能大于16位',
21             'required': '该字段不能为空',
22         },
23         widget=widgets.PasswordInput(attrs={'class':'form-control'},render_value=True), # render_value=True表示如果密码错误不清空,还保留
24     )
25 
26 # 弹出下拉框并单选(Select)
27 hobby = forms.ChoiceField(
28         choices=((1,'篮球'),(2,'足球'),(3,'乒乓球'),(4,'双色球')),
29         label='爱好',
30         initial=1,
31         widget=widgets.Select(attrs={'class':'h1'})
32     )
33 
34 # 弹出下拉框并多选(SelectMultiple)
35 hobby2 = forms.MultipleChoiceField(
36         choices=((1,'篮球'),(2,'足球'),(3,'乒乓球'),(3,'双色球')),
37         label='爱好',
38         initial=[1,3],
39         widget=widgets.SelectMultiple(attrs={'class':'h2'})
40     )
41 
42 # 单选checkbox(CheckboxInput)
43 keep = forms.ChoiceField(
44         label='是否记住密码',
45         initial='checked',
46         widget=widgets.CheckboxInput(attrs={'class':'k1'})
47     )
48 
49 # 多选checkbox(CheckboxSelectMultiple)
50 hobby3 = forms.MultipleChoiceField(
51         choices=((1, '篮球'), (2, '足球'), (3, '乒乓球'), (3, '双色球')),
52         label='爱好',
53         initial=[1, 3],
54         widget=widgets.CheckboxSelectMultiple(attrs={'class':'h3'})
55     )
View Code

 

3.6 使用bootstrap样式

 1 <head>
 2     <meta charset="UTF-8">
 3     <title>Title</title>
 4     <link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.min.css">
 5 </head>
 6 <body>
 7     <div class="container">
 8         <div class="row">
 9             <div class="col-md-6 col-md-offset-3">
10                 <form action="/reg.html" method="post" novalidate>
11                     {% csrf_token %}
12 
13                     <div class="from-group">
14                         {{ form_obj.name.label }}
15                         {{ form_obj.name }}
16                         <span class="help-block">{{ form_obj.name.errors.0 }}</span>
17                     </div>
18                     <div class="from-group">
19                         {{ form_obj.pwd.label }}
20                         {{ form_obj.pwd }}
21                         <span class="help-block">{{ form_obj.pwd.errors.0 }}</span>
22                     </div>
23                     <div class="from-group">
24                         <input type="submit" class="btn btn-success" value="注册">
25                     </div>
26                 </form>
27             </div>
28         </div>
29     </div>
30 </body>
View Code

 

 

3.7 在模板中form_obj对象的用法

{{ form_obj.as_p }} —— 》 生成P标签 (label 和 input)

{{ form_obj.user }} —— 》 生成input框
{{ form_obj.pwd }}

{{ form_obj.pwd.label }} ——》 对应的中文
{{ form_obj.pwd.id_for_label }} ——》 input的ID
{{ form_obj.errors }} —— 》 所有错误提示
{{ form_obj.pwd.errors }} —— 》 某个字段的所有错误提示
{{ form_obj.pwd.errors.0 }} —— 》 某个字段的第一错误提示

 

3.8 校验通过后

form_obj.cleaned_data  # 默认提交的参数都在这个里面{'name': 'eric', 'pwd': 'pwd123', 're_pwd': 'pwd123'}

 

# 注册跳转函数

def reg(request):
    form_obj = RegForm()
    if request.method == 'POST':
        form_obj = RegForm(request.POST)
        if form_obj.is_valid(): # 返回布尔值,True或False
            dic = form_obj.cleaned_data
            models.User.objects.create(**dic)
            return HttpResponse('注册成功')
    return render(request,'reg.html',{'form_obj':form_obj})

 

3.9 自定义校验
3.9.1 正则校验手机号

from django.core.validators import RegexValidator # 导入正则校验模块
phone = forms.CharField(
    label='手机号',
    max_length=11,
    validators=[
        RegexValidator(r'^[0-9]+$','手机号必须是数字'), # 校验是不是数字
        RegexValidator(r'^1[3-9][0-9]{9}$','格式错误'), # 校验格式
    ],
    widget=widgets.TextInput(attrs={'class':'form-control'}),
    error_messages={
        'required':'该字段不能为空'
    }


3.9.2 局部钩子校验用户名

from django.core.exceptions import ValidationError

class RegForm(forms.Form): # 在定义的forms类中去校验某个字段
...

    # 校验用户名的可用性
    def clean_name(self):
        value = self.cleaned_data.get('name')
        if '大傻逼' in value:
            raise ValidationError('用户名不符合规定')
        return value

 

3.9.3 全局钩子校验密码

from django.core.exceptions import ValidationError
class RegForm(forms.Form): # 在定义的forms类中去重写clean方法
...

    # 校验两次密码的一致性
    def clean(self):
        pwd = self.cleaned_data.get('pwd')
        re_pwd = self.cleaned_data.get('re_pwd')
        if pwd != re_pwd:
            self.add_errors('re_pwd','两次密码不一致')
            raise ValidationError('两次密码不一致')
        return self.cleaned_data

 

4. 解决forms.ChoiceField不更新问题

 1 hobby = forms.ChoiceField(
 2     choices=((1,'篮球'),(2,'足球'),(3,'乒乓球'),(4,'双色球')),
 3     label='爱好',
 4     initial=1,
 5     widget=forms.widgets.Select(attrs={'class':'h1'})
 6     )
 7 如果choices=((1,'篮球'),(2,'足球'),(3,'乒乓球'),(4,'双色球'))里面的内容是通过数据库动态获取到的数据,例如:
 8 
 9 choices=models.Hobby.objects.all().values_list('id','name'),那么在页面展示的时候,新添加的数据不会被显示出来,那么解决这个问题的办法如下:
10 
11 # 重写父类的__init__方法
12 def __init__(self,*args,**kwargs):
13     super().__init__(*args,**kwargs)                 
14     self.fields['hobby'].widget.choices=models.Hobby.objects.all().values_list('id','name') # 每添加一个数据就动态刷新一次
View Code

 

5. 完整的注册代码
5.1 views中的代码

 1 from django import forms
 2 from django.forms import widgets
 3 class RegForm(forms.Form):
 4     # 用户名
 5     name = forms.CharField(
 6         max_length=6,
 7         label='用户名',
 8         widget=widgets.TextInput(attrs={'class':'form-control'}),
 9         error_messages={
10             'required': '该字段不能为空',
11         },
12     )
13     
14     # 密码
15     pwd = forms.CharField(
16         min_length=6,
17         max_length=16,
18         label='密码',
19         widget=widgets.PasswordInput(attrs={'class':'form-control'},render_value=True),
20         error_messages={
21             'min_length':'密码最小不能少于6位',
22             'max_length':'密码最长不能大于16位',
23             'required': '该字段不能为空',
24         },
25     )
26     
27     # 确认密码
28     re_pwd = forms.CharField(
29         min_length=6,
30         max_length=16,
31         label='确认密码',
32         widget=widgets.PasswordInput(attrs={'class':'form-control'},render_value=True),
33         error_messages={
34             'min_length':'密码最小不能少于6位',
35             'max_length':'密码最长不能大于16位',
36             'required': '该字段不能为空',
37         },
38     )
39 
40     # 邮箱
41     email = forms.EmailField(
42         label='邮箱',
43         widget=widgets.EmailInput(attrs={'class':'form-control'}),
44         error_messages={
45             'required': '该字段不能为空',
46 
47         }
48     )
49 
50     # 手机号
51     phone = forms.CharField(
52         label='手机号',
53         max_length=11,
54         validators=[
55             RegexValidator(r'^[0-9]+$','手机号必须是数字'),
56             RegexValidator(r'^1[3-9][0-9]{9}$','格式错误'),
57         ],
58         widget=widgets.TextInput(attrs={'class':'form-control'}),
59         error_messages={
60             'required':'该字段不能为空'
61         }
62 
63     )    
64     
65     # 验证用户名是否可用
66         def clean_name(self):
67         value = self.cleaned_data.get('name')
68         if '大傻逼' in value:
69             raise ValidationError('用户名不符合规定')
70         return value
71 
72     # 验证两次密码是否一致
73     def clean(self):
74         pwd = self.cleaned_data.get('pwd')
75         re_pwd = self.cleaned_data.get('re_pwd')
76         if pwd != re_pwd:
77             self.add_error('re_pwd','两次密码不一致')
78             raise ValidationError('两次密码不一致')
79         return self.cleaned_data    
View Code

5.2 注册函数

1 def reg(request):
2     form_obj = RegForm()
3     if request.method == 'POST':
4         form_obj = RegForm(request.POST)
5         if form_obj.is_valid():
6             dic = form_obj.cleaned_data
7             models.User.objects.create(**dic)
8             return HttpResponse('注册成功')
9     return render(request,'reg.html',{'form_obj':form_obj})
View Code

5.3 模板中的代码

 1 <link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.min.css">  # 导入bootstrap样式
 2 <div class="container">
 3     <div class="row">
 4         <div class="col-md-6 col-md-offset-3">
 5             <form action="/reg.html" method="post" novalidate>
 6                 {% csrf_token %}
 7 
 8                 <div class="from-group {% if form_obj.name.errors.0 %}has-error{% endif %}">
 9                     {{ form_obj.name.label }}
10                     {{ form_obj.name }}
11                     <span class="help-block">{{ form_obj.name.errors.0 }}</span>
12                 </div>
13                 <div class="from-group {% if form_obj.pwd.errors.0 %}has-error{% endif %}">
14                     {{ form_obj.pwd.label }}
15                     {{ form_obj.pwd }}
16                     <span class="help-block">{{ form_obj.pwd.errors.0 }}</span>
17                 </div>
18 
19                 <div class="from-group {% if form_obj.re_pwd.errors.0 %}has-error{% endif %}">
20                     {{ form_obj.re_pwd.label }}
21                     {{ form_obj.re_pwd }}
22                     <span class="help-block">{{ form_obj.re_pwd.errors.0 }}</span>
23                 </div>
24                 <div class="from-group {% if form_obj.email.errors.0 %}has-error{% endif %}">
25                     {{ form_obj.email.label }}
26                     {{ form_obj.email }}
27                     <span class="help-block">{{ form_obj.email.errors.0 }}</span>
28                 </div>
29                 <div class="from-group {% if form_obj.phone.errors.0 %}has-error{% endif %}">
30                     {{ form_obj.phone.label }}
31                     {{ form_obj.phone }}
32                     <span class="help-block">{{ form_obj.phone.errors.0 }}</span>
33                 </div>
34                 <div class="from-group">
35                     <input type="submit" class="btn btn-success" value="注册">
36                 </div>
37             </form>
38         </div>
39     </div>
40 </div>
View Code
posted on 2019-02-28 12:39  花豆豆  阅读(104)  评论(0)    收藏  举报