一、Form表单
在实际的生产环境中比如登录和验证的时候,我们一般都使用Jquery+ajax来判断用户的输入是否为空,假如JS被禁用的话,咱们这个认证屏障是不是就消失了呢?(虽然一般不会禁用掉但是还是存在风险)所以我们一般做两种认证一种是前端做一遍认证,在后端做一遍认证。
如果前端中要涉及到很多input,提交到后台,后台要一一取出,分别做验证,这是件很痛苦的事。
def register(request): if request.method == "POST": ret = {"status":False,"msg":""} u = request.POST.get(‘user‘,None) e = request.POST.get(‘email‘,None) p = request.POST.get(‘password‘,None) p2 = request.POST.get(‘password2‘,None) #这里有个问题,如果,这个from表单有20个input,你在这里是不是的取20次? count = models.UserInfo.objects.filter(user=u).count() if count == 0: if p == p2: print("注册成功") models.UserInfo.objects.create(user=u, email=e, password=p) data_list = models.UserInfo.objects.all() ret["status"] = True ret["msg"] = "注册成功,请登录" return HttpResponse(json.dumps(ret)) # return redirect(‘/index/‘) else: print(‘diff‘) ret["msg"] = "两次输入密码不一致" return HttpResponse(json.dumps(ret)) elif len(u) > 0 and count >= 1: print(‘用户名已经存在‘ ) ret["msg"] = "用户名已经存在" return HttpResponse(json.dumps(ret)) else: return render( request, ‘cmdb/register.html‘, ) #验证: #输入不能为空,并且有的可以为空有的不可以为空 #如果email = xxxx 这样合法吗 ‘‘‘ 你在这里是不是需要做一大堆的输入验证啊?并且有很多这种页面会存在这种情况,如果每个函数都这样做估计就累死了 ‘‘‘ if request.method == ‘GET‘: return render( request, ‘cmdb/register.html‘, )
在样能解决这个问题呢?通过Django的form来实现,其他语言也有叫做(模型绑定)
Django的form的作用:
1、生成html标签
2、用来做用户提交的验证
1、生成html标签
views
from django import forms class LoginForm(forms.Form): user = forms.CharField(required=True, error_messages={‘required‘: ‘用户名不能为空.‘}) pwd = forms.CharField(required=True, min_length=6, max_length=10, error_messages={‘required‘: ‘密码不能为空.‘, ‘min_length‘: "至少6位"}) num = forms.IntegerField(error_messages={‘required‘: ‘数字不能空.‘,‘invalid‘: ‘必须输入数字‘}) phone = forms.CharField(validators=[mobile_validate, ],) test = forms.CharField(widget=forms.Textarea(attrs={‘class‘: ‘c1‘})) def login(request): if request.POST: objPost = LoginForm(request.POST) ret = objPost.is_valid() # print(objPost) print(ret) if ret: print(objPost.clean()) else: from django.forms.utils import ErrorDict #print(type(obj.errors),obj.errors.as_json()) # obj1.errors print(objPost.errors.as_json()) return render(request, ‘login.html‘,{‘obj1‘: objPost}) else: objGet = LoginForm() return render(request, ‘login.html‘,{‘obj1‘: objGet})
html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> .error-msg{ color: red; } </style> </head> </head> <body> <form action="/app01/login/" method="POST"> <div> <div> {{ obj1.user }} {% if obj1.errors.user %} <span class="error-msg">{{ obj1.errors.user.0 }}</span> {% endif %} </div> <div> {{ obj1.pwd }} <span class="error-msg">{{ obj1.errors.pwd.0 }}</span> </div> <div> {{ obj1.num }} <span class="error-msg">{{ obj1.errors.num.0 }}</span> </div> <div> {{ obj1.phone }} <span class="error-msg">{{ obj1.errors.phone.0 }}</span> </div> <div> {{ obj1.test }} <span class="error-msg">{{ obj1.errors.test.0 }}</span> </div> <input type="submit" value="提交"> </div> </form> </body> </html>
2、简单的form表单验证用户输入的内容
def login(request): if request.POST: #获取用户输入一句话就搞定 objPost = LoginForm(request.POST) ‘‘‘ 咱们把post过来的数据当参数传给LoginForm咱们定义的这个类,LoginForm会自动会去你提交的数据 user/pwd/num/phone 自动的封装到objPost里,封装到这个对象里我们就可以判断输入是否合法 ‘‘‘ ret = objPost.is_valid() # print(objPost) print(ret) if ret: print(objPost.clean()) else: from django.forms.utils import ErrorDict #print(type(obj.errors),obj.errors.as_json()) # obj1.errors print(objPost.errors.as_json()) return render(request, ‘login.html‘,{‘obj1‘: objPost})#然后把对象传给html else: objGet = LoginForm() #创建了这个对象 return render(request, ‘login.html‘,{‘obj1‘: objGet}) from django.views.decorators.csrf import csrf_exempt,csrf_protect
当我们输入不合法的时候,(在创建类设置的需求)为空、或者不是email格式的时候!
这样在后端我们是不是就有一套验证的机制?就可以通过is_valid()来判断用户输入是否合法!如果不合法就把返回信息发送过去,如果合法获取数据操作即可!
捕获错误信息并返回
from django import forms class LoginForm(forms.Form): user = forms.CharField(required=True, error_messages={‘required‘: ‘用户名不能为空.‘}) pwd = forms.CharField(required=True, min_length=6, max_length=10, error_messages={‘required‘: ‘密码不能为空.‘, ‘min_length‘: "至少6位"}) num = forms.IntegerField(error_messages={‘required‘: ‘数字不能空.‘,‘invalid‘: ‘必须输入数字‘}) phone = forms.CharField(validators=[mobile_validate, ],) test = forms.CharField(widget=forms.Textarea(attrs={‘class‘: ‘c1‘}))
def login(request): if request.POST: #获取用户输入一句话就搞定 objPost = LoginForm(request.POST) ‘‘‘ 咱们把post过来的数据当参数传给LoginForm咱们定义的这个类,LoginForm会自动会去你提交的数据 user/pwd/num/phone 自动的封装到objPost里,封装到这个对象里我们就可以判断输入是否合法 ‘‘‘ ret = objPost.is_valid() # print(objPost) print(ret) if ret: print(objPost.clean()) #通过验证,获取提交的数据 ‘‘‘ {‘user‘: ‘asfd‘, ‘num‘: 1, ‘pwd‘: ‘dsafss‘, ‘test‘: ‘32‘, ‘phone‘: ‘13331525685‘} ‘‘‘ else: from django.forms.utils import ErrorDict #print(type(obj.errors),obj.errors.as_json()) # obj1.errors print(objPost.errors) ‘‘‘ <ul class="errorlist"><li>phone<ul class="errorlist"><li>手机号码格式错误</li></ul></li></ul> ‘‘‘ return render(request, ‘login.html‘,{‘obj1‘: objPost})#然后把对象传给html,在把错误信息传递过去 else: objGet = LoginForm() #创建了这个对象 return render(request, ‘login.html‘,{‘obj1‘: objGet})#然后把对象传给html
html标签,使用 login 中定义的obj1 对应的errors输出
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> .error-msg{ color: red; } </style> </head> </head> <body> <form action="/app01/login/" method="POST"> <div> <div> {{ obj1.user }} {% if obj1.errors.user %} <span class="error-msg">{{ obj1.errors.user.0 }}</span> {% endif %} </div> <div> {{ obj1.pwd }} <span class="error-msg">{{ obj1.errors.pwd.0 }}</span> </div> <div> {{ obj1.num }} <span class="error-msg">{{ obj1.errors.num.0 }}</span> </div> <div> {{ obj1.phone }} <span class="error-msg">{{ obj1.errors.phone.0 }}</span> </div> <div> {{ obj1.test }} <span class="error-msg">{{ obj1.errors.test.0 }}</span> </div> <input type="submit" value="提交"> </div> </form> </body> </html>
这样如果,我都按照要求提交,就可以取到数据了?这样咱们就不用自己去拿数据是
1 |
|
3、form表单定制化
3.1、自定义报错内容
在form里有一个参数:error_messages 在他这里就可以定义报错内容
class UserInfo(forms.Form): email = forms.EmailField(required=True,error_messages={‘required‘:u‘邮箱不能为空‘}) #required是否可以为空,如果为False说明可以为空 host = forms.CharField(error_messages={‘required‘:u‘主机不能为空‘}) #如果required不写默认为Ture port = forms.CharField(error_messages={‘required‘:u‘端口不能为空‘}) mobile = forms.CharField(error_messages={‘required‘:u‘手机不能为空‘}, widget=forms.TextInput(attrs={‘class‘:‘form-control‘,‘placeholder‘:u‘手机号码‘})#给input添加属性 #这里默认是TextInput,标签 )
效果:
3.2给userinfo增加一个备注
class UserInfo(forms.Form): email = forms.EmailField(required=True,error_messages={‘required‘:u‘邮箱不能为空‘}) #required是否可以为空,如果为False说明可以为空 host = forms.CharField(error_messages={‘required‘:u‘主机不能为空‘}) #如果required不写默认为Ture port = forms.CharField(error_messages={‘required‘:u‘端口不能为空‘}) #默认mobile里有一个默认为空的机制,我们在原有的参数里增加怎们自定义的方法 mobile = forms.CharField(validators=[mobile_validate,],#应用咱们自己定义的规则 error_messages={‘required‘:u‘手机不能为空‘}, widget=forms.TextInput(attrs={‘class‘:‘form-control‘,‘placeholder‘:u‘手机号码‘}) #这里默认是TextInput,标签 ) #咱们在新增一个备注 memo = forms.CharField(required=False, widget=forms.Textarea(attrs={‘class‘:‘form-control‘,‘placeholder‘:u‘备注‘}) )
效果如下:
3.3 生成select标签
class UserInfo(forms.Form): email = forms.EmailField(required=True,error_messages={‘required‘:u‘邮箱不能为空‘}) #required是否可以为空,如果为False说明可以为空 host = forms.CharField(error_messages={‘required‘:u‘主机不能为空‘}) #如果required不写默认为Ture port = forms.CharField(error_messages={‘required‘:u‘端口不能为空‘}) #默认mobile里有一个默认为空的机制,我们在原有的参数里增加怎们自定义的方法 mobile = forms.CharField(validators=[mobile_validate,],#应用咱们自己定义的规则 error_messages={‘required‘:u‘手机不能为空‘}, widget=forms.TextInput(attrs={‘class‘:‘form-control‘,‘placeholder‘:u‘手机号码‘}) #这里默认是TextInput,标签 ) #咱们在新增一个备注 memo = forms.CharField(required=False, widget=forms.Textarea(attrs={‘class‘:‘form-control‘,‘placeholder‘:u‘备注‘}) ) user_type_choice = ( (0, u‘普通用户‘), (1, u‘高级用户‘),) user_type = forms.IntegerField(widget=forms.widgets.Select(choices=user_type_choice,attrs={‘class‘:‘form-control‘}))
3.4、关于后端验证
这个后端验证是必须要有验证机制的,前端可以不写但是后端必须要写!前端的JS是可以被禁用掉到。
3.5 Django 优化错误信息显示
设置显示error的样式
error_msg = user_input_obj.errors.as_data()#这里原来什么都没写,默认是ul的样式,默认是as_ul(),如果我们写成as_data()返回的就是一个原生的字符串 #还有一个as_json
实例:
import re from django import forms 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 UserInfo(forms.Form): user_type_choice = ( (0, u‘普通用户‘), (1, u‘高级用户‘),) user_type = forms.IntegerField(widget=forms.widgets.Select(choices=user_type_choice,attrs={‘class‘:‘form-control‘})) email = forms.EmailField(required=True,error_messages={‘required‘:u‘邮箱不能为空‘}) #required是否可以为空,如果为False说明可以为空 host = forms.CharField(error_messages={‘required‘:u‘主机不能为空‘}) #如果required不写默认为Ture port = forms.CharField(error_messages={‘required‘:u‘端口不能为空‘}) #默认mobile里有一个默认为空的机制,我们在原有的参数里增加怎们自定义的方法 mobile = forms.CharField(validators=[mobile_validate,],#应用咱们自己定义的规则 error_messages={‘required‘:u‘手机不能为空‘}, widget=forms.TextInput(attrs={‘class‘:‘form-control‘,‘placeholder‘:u‘手机号码‘}) #这里默认是TextInput,标签 ) #咱们在新增一个备注 memo = forms.CharField(required=False, widget=forms.Textarea(attrs={‘class‘:‘form-control‘,‘placeholder‘:u‘备注‘}))
def user_list(request): obj = UserInfo() #创建了这个对象 if request.method == ‘POST‘: #获取用户输入一句话就搞定 user_input_obj = UserInfo(request.POST) if user_input_obj.is_valid(): #判断用户输入是否合法 data = user_input_obj.clean() #获取用户输入 print(data) else: #如果发生错误,捕捉错误 error_msg = user_input_obj.errors.as_data()#这里原来什么都没写,默认是ul的样式,默认是as_ul(),如果我们写成as_data()返回的就是一个原生的字符串 #还有一个as_json print(error_msg) #打印一下然后看下他的类型 #然后把错误信息返回 return render(request,‘user_list.html‘,{‘obj‘:obj,‘errors‘:error_msg,})#然后把对象传给html,在把错误信息传递过去 return render(request,‘user_list.html‘,{‘obj‘:obj,})#然后把对象传给html
html
{% load mytag %} <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Shuai</title> </head> <body> <form action="/app01/user_list/" method="post"> <p>用户类型:{{ obj.user_type }}<span>{% error_message errors.user_type %}</span></p> <p>主机:{{ obj.host }}<span>{% errors.host %}</span></p> <p>端口:{{ obj.port }}<span>{% error_message errors.port %}</span></p> <p>邮箱:{{ obj.email }}<span>{% error_message errors.email %}</span></p> <p>手机:{{ obj.mobile }}<span>{% error_message errors.mobile %}</span></p> <p>备注:{{ obj.memo }}<span>{% error_message errors.memo %}</span></p> <input type="submit" value="submit"/> </form> </body> </html>
二、CSRF 跨站请求
viwes.py
from django.views.decorators.csrf import csrf_exempt,csrf_protect @csrf_exempt def csrf(request): return render(request,‘csrf.html‘)
csrf.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <form action="/csrf/" method="post"> {% csrf_token %} <input type="text" name="v" /> <input type="submit" value="提交" /> </form> <input type="button" value="Ajax提交" onclick="DoAjax();" /> <script src="/static/jquery-2.1.4.min.js"></script> <script src="/static/jquery.cookie.js"></script> <script> // 去cookie中获取值 var csrftoken = $.cookie(‘csrftoken‘); function csrfSafeMethod(method) { // these HTTP methods do not require CSRF protection return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method)); } $.ajaxSetup({ #用于ajax请求绑定cookie beforeSend: function(xhr, settings) { if (!csrfSafeMethod(settings.type) && !this.crossDomain) { xhr.setRequestHeader("X-CSRFToken", csrftoken); } } }); function DoAjax(){ $.ajax({ url: ‘/csrf/‘, type: ‘POST‘, data: {‘k1‘: ‘v1‘}, success: function (data) { console.log(data); } }) } </script> </body> </html>
三、cookie
1.cookie设置
viwes.py
def cookie(request): print(request.COOKIES) obj = render(request, ‘cookie.html‘) obj.set_cookie(‘k3‘,‘v3‘,path=‘/cookie/‘) #浏览器设置cookie return obj
2.cookie登陆(cookie内容可以串改,登陆不使用cookie登陆,cookie一般保存不敏感的信息)
viwes.py
def log(request): if request.method == ‘POST‘: u = request.POST.get(‘user‘) p = request.POST.get(‘pwd‘) if u == ‘alex‘ and p == ‘123‘: print(u) red = redirect(‘/index/‘) red.set_cookie(‘username‘, u) return red else: return render(request, ‘log.html‘) else: return render(request, ‘log.html‘)
log.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <form action="/log/" method="POST"> <input type="text" name="user"> <input type="text" name="pwd"> <input type="submit" value="提交" /> </form> </body> </html>
四、session登陆
viwes.py
USER_LIST = [‘alex‘,‘eric‘,‘wangminglong‘, ‘hu‘] def session_login(request): if request.method == ‘POST‘: u = request.POST.get(‘user‘) p = request.POST.get(‘pwd‘) if p == ‘123‘ and u in USER_LIST: request.session[‘user‘] = u return redirect(‘/session_index/‘) return render(request,‘session_login.html‘) """ def session_index(request): user = request.session.get(‘user‘,None) if not user: return redirect(‘/session_login/‘) else: return render(request,‘session_index.html‘,{‘user‘: user}) """ def auth(func): def inner(request, *args,**kwargs): # print(request,args,kwargs) user = request.session.get(‘user‘, None) print(user) if not user: return redirect(‘/session_login/‘) return func(request, *args,**kwargs) return inner @auth def session_index(request): user = request.session.get(‘user‘, None) return render(request,‘session_index.html‘,{‘user‘: user}) @auth def session_logout(request): del request.session[‘user‘] return redirect(‘/session_login/‘)
session_login.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <h1>欢迎:{{ user }}登录</h1> <a href="/session_logout/">注销</a> </body> </html>
session_index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <form action="/session_login/" method="POST"> <input type="text" name="user"> <input type="text" name="pwd"> <input type="submit" value="提交" /> </form> </body> </html>
显示 登陆成功后
数据自动实现