一、初始forms组件
小需求:
我们写一个注册页面 获取用户输入的用户名与密码,用户点击注册发送到后端做用户名密码的校验
用户名中不能包含金瓶mei 如果包含报错提示不符合社会主义核心价值观
密码可不能为空 如果为空报错提示密码不能为空 你个DSB
- 代码演示
"""day56 URL Configuration The `urlpatterns` list routes URLs to views. For more information please see: https://docs.djangoproject.com/en/1.11/topics/http/urls/ Examples: Function views 1. Add an import: from my_app import views 2. Add a URL to urlpatterns: url(r'^$', views.home, name='home') Class-based views 1. Add an import: from other_app.views import Home 2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home') Including another URLconf 1. Import the include() function: from django.conf.urls import url, include 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls')) """ from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^register/', views.register), ]
from django.shortcuts import render, HttpResponse, redirect, reverse # Create your views here. def register(request): error_dict = {'username': '', 'password': ''} if request.method == 'POST': username = request.POST.get('username') password = request.POST.get('password') if '金瓶mei' in username: # 提示报错信息 error_dict['username'] = '不符合社会主义核心价值观' if not password: # 提示报错信息 error_dict['password'] = '密码不能为空, 你个DSB' return render(request, 'register.html', locals())
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script> <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet"> <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script> </head> <body> <form action="" method="post"> <p>username: <input type="text" name="username"> <span style="color: red">{{ error_dict.username }}</span> </p> <p>password: <input type="text" name="password"> <span style="color: red">{{ error_dict.password }}</span> </p> <input type="submit"> </form> </body> </html>
- 效果图
其实在这整个过程中 我们自己做了这么几件事
1、手写获取用户输入的前端页面代码 (渲染标签)
2、后端获取用户数据并做合法性校验 (校验数据)
3、将校验之后的结果渲染到前端页面 (渲染信息)
那么有没有这么一种能够帮我们完成上面是三件事,其实forms组件就可以帮我们完成这三件事
forms组件可以:
1、渲染标签
2、校验数据
3、渲染信息
二、forms组件之校验数据
1、测试环境
注意:我们在使用forms组件去校验数据的前提(准备工作),需要我们先写一个类之后才可以去校验数据,这里需要先导入一个模块form django import forms
from django import forms # 写之前需要先导入一个模块 class MyRegForm(forms.Form): username = forms.CharField(max_length=8, min_length=3) # 限制你的用户名最大为8位数,最小为3位数 password = forms.CharField(max_length=8, min_length=3) email = forms.EmailField() # 限制必须为符合邮箱类型的数据
之前我们已经介绍过了如何去单独的去测试某一个数据或文件,是需要我们去配置一个测试环境的,接下来再来介绍一下一个pycharm自带的测试环境,更为简洁
2、如何校验数据
# 1.传入待校验的数据 用自己写的类 传入字典格式的待校验的数据 form_obj = views.MyRegForm({'username':'yafeng','password':'12','email':'123456'}) # 2.判断数据是否符合校验规则 form_obj.is_valid() # 该方法只有在所有的数据全部符合校验规则才会返回True False # 3.如何获取校验之后通过的数据 form_obj.cleaned_data {'username': 'yafeng'} # 4.如何获取校验失败及失败的原因 form_obj.errors { 'password': ['Ensure this value has at least 3 characters (it has 2).'], 'email': ['Enter a valid email address.'] } # 5.注意 forms组件默认所有的字段都必须传值 也就意味着传少了是不行的 而传多了则没有任何关系 只校验类里面写的字段 多传的直接忽略了 form_obj = views.MyRegForm({'username':'yafeng','password':'123456'}) form_obj.is_valid() Out[12]: False form_obj.errors Out[18]: {'email': ['This field is required.']} form_obj = views.MyRegForm({'username':'yafeng','password':'123456',"email":'123@qq.com',"hobby":'hahahaha'}) form_obj.is_valid() Out[14]: True form_obj.cleaned_data Out[15]: {'username': 'yafeng', 'password': '123456', 'email': '123@qq.com'} form_obj.errors Out[16]: {}
三、forms组件之渲染标签
首先我们还是需要先写一个类
注意:forms组件只帮你渲染获取用户输入(输入 选择 下拉 文件)的标签不会渲染按钮以及form表单标签,渲染出来的每一个input提示信息都是类中的字段首字母大写。
# forms渲染页面 def reg(request): # 1、先生成一个空的类的对象 form_obj = MyRegForm() # 2、直接将该对象传给前端页面 return render(request, 'reg.html', locals())
1、第一种渲染方式
便于本地测试,但封装程度太高了,不利于扩展
{{as_p}}
<head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script> <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet"> <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script> </head> <body> <p>第一种渲染方式 多个p标签 优点:本地测试方便 不足之处:封装程度太高了 不便于扩展</p> {{ form_obj.as_p }}
#{{ form_obj.as_ul }} # 其他类型
#{{ form_obj.as_table }} # 其他类型
</body> </html>
2、第二种渲染方式
自己手动去书写比如
{{ form_obj.username.label }}{{ form_obj.username }}
<p>第二种渲染方式:优点:扩展性高, 缺点:有几个字段就得自己手写多少个,所以书写麻烦</p>
<label for="{{ form_obj.username.id_for_label }}"></label> <--for是用来放对应的input框的id地址--!>
{{ form_obj.username.label }}{{ form_obj.username }} # 点label是获取注释,不加只会是一个空白的框 {{ form_obj.password.label }}{{ form_obj.password }} {{ form_obj.email.label }}{{ form_obj.email }} </body> </html>
3、第三种渲染方式
for循环(推荐使用)
<p>第三种渲染方式:推荐使用</p> {% for form in form_obj %} <p>{{ form.label }}{{ form }}</p>
<span>{{form.errors.0}}</span>
{% endfor %}
四、forms组件之渲染信息
注意:数据校验你得前后端都得有 但是前端的校验弱不禁风,可有可无,而后端的校验则必须非常全面。
那么我们应该如何取消浏览器自动帮我们校验的功能?
针对form表单取消前端浏览器自动校验功能, 你只需要加一个参数novalidate
<form action="" method="post" novalidate> # 取消前端的校验
前端:
<form action="" method="post" novalidate> # 取消前端的校验 {% for form in form_obj %} <p> {{ form.label }}{{ form }} <span>{{ form.errors.0 }}</span> <--直接点索引0,拿到的就是列表的提示信息--!> </p> {% endfor %} <input type="submit"> </form>
后端:
# forms渲染页面 def reg(request): # 1、先生成一个空的类的对象 form_obj = MyRegForm() if request.method == 'POST': # 3、获取用户数据并交给forms组件检验 request.POST form_obj = MyRegForm(request.POST) # 4、获取检验结果 if form_obj.is_valid(): return HttpResponse('数据没问题') else: # 获取检验失败的字段和提示信息 print(form_obj.errors) # 2、直接将该对象传给前端页面 return render(request, 'reg.html', locals())
五、forms组件常用参数
1、label input的提示信息
2、error_message 自定义报错信息的提示信息
3、required 设置字段是否可以允许为空
4、initial 给字段设置默认值
5、widget 控制标签的type类型及属性
6、validator 正则校验 可写多个正则
widget=forms.widgets.TextInput(attrs={'class':'form-control c1 c2'})
widget=forms.widgets.PasswordInput(attrs={'class':'form-control'})
2、给input框修改样式
widget用来控制字段的type类型
from django import forms # 写之前需要先导入一个模块 from django.forms import widgets # forms之校验数据 class MyRegForm(forms.Form): username = forms.CharField(max_length=8, min_length=3, label='用户名', error_messages={ 'max_length': '用户名最长8位', 'min_length': '用户名最短三位', 'required': '用户名不能为空' }, required=False, initial='reba', widget= forms.widgets.TextInput(attrs={'class': 'form-control c1 c2'}) ) # 限制你的用户名最大为8位数,最小为3位数 password = forms.CharField(max_length=8, min_length=3, label='密码', widget=forms.widgets.PasswordInput) email = forms.EmailField(label='邮箱',error_messages={ 'required': '邮箱必填', 'invalid': '邮箱格式不正确', }) # 限制必须为符合邮箱类型的数据
接下来我想用widget是input框具有bootstrap样式以及使密码变成密文就得使用widget方法
六、钩子函数
1、两种类型
全局钩子(针对多个字段)
比如:校验两次密码是否一致
from django import forms # 写之前需要先导入一个模块 from django.forms import widgets # forms之校验数据 class MyRegForm(forms.Form): username = forms.CharField(max_length=8, min_length=3, label='用户名', error_messages={ 'max_length': '用户名最长8位', 'min_length': '用户名最短三位', 'required': '用户名不能为空' }, required=False, initial='reba', #widget= # forms.widgets.TextInput(attrs={'class': 'form-control c1 c2'}) ) # 限制你的用户名最大为8位数,最小为3位数 password = forms.CharField(max_length=8, min_length=3, label='密码', # widget=forms.widgets.PasswordInput ) confirm_password = forms.CharField(max_length=8, min_length=3, label='确认密码') email = forms.EmailField(label='邮箱',error_messages={ 'required': '邮箱必填', 'invalid': '邮箱格式不正确', }) # 限制必须为符合邮箱类型的数据 # 全局钩子 def clean(self): # 全局钩子固定叫clean # 校验密码和确认密码是否一致 password = self.cleaned_data.get('password') # self 指代的是当前类产生的对象 confirm_password = self.cleaned_data.get('confirm_password') if not password == confirm_password: # 展示提示信息 self.add_error('confirm_password', '两次密码不一致') # 你想展示到那个字段后面就放那个字段就可以啦 return self.cleaned_data
局部钩子(针对某一个字段)
例如:校验用户名中不能包含666
# 局部钩子 def clean_username(self): username = self.cleaned_data.get('username') if '666' in username: self.add_error('username', '光喊666 是不行的') return username # 注意:你把什么勾出来了你就得把什么还回去
总结:如果你想同时操作多个字段的数据你就用全局钩子,如果你想操作单个字段的数据 你就用局部钩子
七、forms补充
1、正则校验(除了钩子函数之外还可以使用正则校验)
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开头')], )
2、radioselect(多选一)
class LoginForm(forms.Form): username = forms.CharField( min_length=8, label="用户名", initial="张三", error_messages={ "required": "不能为空", "invalid": "格式错误", "min_length": "用户名最短8位" } ) pwd = forms.CharField(min_length=6, label="密码") gender = forms.fields.ChoiceField( choices=((1, "男"), (2, "女"), (3, "保密")), label="性别", initial=3, widget=forms.widgets.RadioSelect() # 这个是来确定到底是什么类型 )
3、单选下拉select
class LoginForm(forms.Form): ... hobby = forms.ChoiceField( choices=((1, "篮球"), (2, "足球"), (3, "双色球"), ), label="爱好", initial=3, widget=forms.widgets.Select() )
4、多选select
class LoginForm(forms.Form): ... hobby = forms.MultipleChoiceField( choices=((1, "篮球"), (2, "足球"), (3, "双色球"), ), label="爱好", initial=[1, 3], widget=forms.widgets.SelectMultiple() )
5、单选CheckBox
class LoginForm(forms.Form): ... keep = forms.ChoiceField( label="是否记住密码", initial="checked", widget=forms.widgets.CheckboxInput() )
6、多选CheckBox
class LoginForm(forms.Form): ... hobby = forms.MultipleChoiceField( choices=((1, "篮球"), (2, "足球"), (3, "双色球"),), label="爱好", initial=[1, 3], widget=forms.widgets.CheckboxSelectMultiple() )