Django-CSRF,AJAX,FORM
内容总览
1.CSRF相关
1>CSRF源码分析
2>ajax的实现(ajax的实例(异步计算,参数测试,上传))
3>ajax通过csrf的校验
2.FORM组件
1>基本使用
2>内部校验器
3>自定义函数内部校验
4>is_valid()源码分析
1.django的csrf源码分析
1>global_settings与CsrfViewMiddleware
2>.ajax
a.发请求的途径
浏览器地址栏键入url--->GET
form表单提交数据 ----->根据method决定是POST/GET
a标签超链接 ---> GET
b.ajax是使用js技术发送异步请求,一般传输json数据
特点:局部刷新,当前页面不刷新
异步,客户端发出一个请求后,无需等待服务器响应结,就可以发出第二个请求
c.正常全局刷新
views def index(request): if request.method == 'POST': i1 = request.POST.get('i1') i2 = request.POST.get('i2') i3 = eval(f'{i1}+{i2}') print(locals()) return render(request,'index.html',locals()) html <form action="" method="post"> {% csrf_token %} <input type="text" name="i1" value="{{ i1 }}">+<input type="text" name="i2" value="{{ i2 }}">=<input type="text" value="{{ i3 }}"> <button>计算</button>
d.ajax局部刷新
事例一:异步ajax计算
views import time def index(request): return render(request,'index.html') def calc1(request): if request.method == 'POST': i1 = request.POST.get('i1') i2 = request.POST.get('i2') i3 = eval(f'{i1}+{i2}') time.sleep(3) return HttpResponse(i3) #返回响应体让ajax接收 def calc2(request): if request.method == 'POST': i1 = request.POST.get('i1') i2 = request.POST.get('i2') i3 = eval(f'{i1}+{i2}') return HttpResponse(i3) html <input type="text" name="i1" value="{{ i1 }}">+<input type="text" name="i2" value="{{ i2 }}">=<input type="text" name='i3' value="{{ i3 }}"> <button id="b1">计算</button> <br> <input type="text" name="i11" value="{{ i11 }}">+<input type="text" name="i22" value="{{ i22 }}">=<input type="text" name='i33' value="{{ i33 }}"> <button id="b2">计算</button> $('#b1').click(function () { $.ajax({ url:'/calc1/', type:'post', data:{ i1:$("[name='i1']").val(), i2:$("[name='i2']").val(), }, success:function (res) { {#res是返回的响应体#} {#console.log(res)#} $("[name='i3']").val(res) } }) }); $('#b2').click(function () { $.ajax({ url:'/calc2/', type:'post', data:{ i1:$("[name='i11']").val(), i2:$("[name='i22']").val(), }, success:function (res) { {#res是返回的响应体#} {#console.log(res)#} $("[name='i33']").val(res) } }) });
事例二:参数测试
1>前端数组--->序列化--->后端接收--->反序列化--->拿到数组
#########前后端交交互都应该将数据类型转化为json字符串######### ############前端使用ajax直接传一个列表的情况############# html <button id="b3">参数测试</button> $('#b3').click(function () { $.ajax({ url:'/ajax_test/', type:'post', data:{ hobby:['篮球','足球','排球'] }, success:function (res) { console.log(res) }, error:function (res) { console.log(33); console.log(res) } }) }); views def ajax_test(request): print(request.POST) #传过来的内容被格式化下属形况 #<QueryDict: {'hobby[]': ['篮球', '足球', '排球']}> print(111,request.POST.getlist('hobby[]')) #111 ['篮球', '足球', '排球'] hobby= request.POST.get('hobby') print(222,hobby,type(hobby)) #222 None <class 'NoneType'> ################前端传一个json字符串的情况############ html $('#b3').click(function () { $.ajax({ url:'/ajax_test/', type:'post', data:{ hobby:JSON.stringify(['篮球','足球','排球']) }, success:function (res) { console.log(res) }, error:function (res) { console.log(33); console.log(res) } }) }); views def ajax_test(request): print(request.POST) #前端序列化之后传来一个正常的字符串 #<QueryDict: {'hobby': ['["篮球","足球","排球"]']}> print(111,request.POST.getlist('hobby[]')) #111 [] hobby= request.POST.get('hobby') print(222,hobby,type(hobby)) #222 ["篮球","足球","排球"] <class 'str'> hobby_json = json.loads(hobby) print(type(hobby_json),hobby_json[0:2]) #<class 'list'> ['篮球', '足球'] #反序列化之后可以正常拿到前端传的列表数据类型
2>后台字典--->序列化------->前端---->反序列化----->拿到字典
#######后台返回一个Jsonresponse,,前端可以直接使用数据类型######## html $('#b3').click(function () { $.ajax({ url:'/ajax_test/', type:'post', data:{ {#hobby:['篮球','足球','排球']#} {#hobby:JSON.stringify(['篮球','足球','排球'])#} }, success:function (res) { console.log(res) }, error:function (res) { console.log(33); console.log(res) } }) }); views def ajax_test(request): data = {'name': 'sen', 'age': 26} return JsonResponse(data) #浏览器:一个数组 {name: "sen", age: 26} age: 26 name: "sen" __proto__: Object ###使用Httpresponse(json.dumps ,content_type='application/json')### html 与上面一样 views def ajax_test(request): data = {'name': 'sen', 'age': 26} return HttpResponse(json.dumps(data),content_type='application/json') #浏览器也会拿到数组,如果不加content_type 只会拿到json字符串 #例如 {"name": "sen", "age": 26}
事例三:上传
views
from django.http import JsonResponse
def upload(request): if request.is_ajax(): print(request.FILES) #<MultiValueDict: {'f1': [<InMemoryUploadedFile: 55.jpg (image/jpeg)>]}> f1 = request.FILES.get('f1') print(f1) #55.jpg with open(f1.name,'wb') as f: for i in f1.chunks(): f.write(i) #return HttpResponse('ok') return JsonResponse({'status':0,'msg':'上传成功'}) #以JSON的数据类型返给了前端
html <input type="file" id="f1"> <button id="b4">上传</button> $('#b4').click(function () { form_obj = new FormData(); {#console.log($('#f1'));#} {#jQuery.fn.init [input#f1]#} {#0: input#f1#} {#console.log($('#f1')[0].files);#} {#FileList {0: File(54312), length: 1}#} form_obj.append('f1',$('#f1')[0].files[0]); $.ajax({ url:'/upload/', type:'post', data:form_obj, processData:false, {#停止ajax对文件的编码处理#} contentType:false,
{#业务逻辑JSONRESPONSE的字符串到前端会自动反序列化成数组(字典),方便直接取值#}
success:function (res) { console.log(res)
if(res.status == 0){ alert(res.msg);
}, }) })
3.ajax通过csrf的验证
a.自行设置通过验证的csrf_token信息
html #注意:必须要有{% csrf_token%} #1>POST请求携带的form数据 $('#b1').click(function () { $.ajax({ url:'/calc1/', type:'post', data:{ i1:$("[name='i1']").val(), i2:$("[name='i2']").val(), csrfmiddlewaretoken:$("[name='csrfmiddlewaretoken']").val(), },#浏览器显示:i1=1&i2=3&csrfmiddlewaretoken=0jWWADXuWLyAdj56bFFXzgadAZziwoEvu13C9AD3Ko4bA1G1JGVfxl6THiYlNKJQ #2>设置在响应头中的键值对 $('#b2').click(function () { $.ajax({ url:'/calc2/', type:'post', headers:{'X-csrftoken':$("[name='csrfmiddlewaretoken']").val()}, data:{ i1:$("[name='i11']").val(), i2:$("[name='i22']").val(), },#浏览器显示: X-csrftoken:0jWWADXuWLyAdj56bFFXzgadAZziwoEvu13C9AD3Ko4bA1G1JGVfxl6THiYlNKJQ
b.django官网推荐的通过csrf验证的方式
#新建一个ajax-setup.js #注意 以下条件需要满足一点即可: #1>html:需要有{%csrf%} #2>from django.views.decorators.csrf import ensure_csrf_cookie 给视图函数增加一个@ensure_csrf_cookie function getCookie(name) { var cookieValue = null; if (document.cookie && document.cookie !== '') { var cookies = document.cookie.split(';'); for (var i = 0; i < cookies.length; i++) { var cookie = jQuery.trim(cookies[i]); // Does this cookie string begin with the name we want? if (cookie.substring(0, name.length + 1) === (name + '=')) { cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); break; } } } return cookieValue; } var csrftoken = getCookie('csrftoken'); function csrfSafeMethod(method) { // these HTTP methods do not require CSRF protection return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method)); } $.ajaxSetup({ beforeSend: function (xhr, settings) { if (!csrfSafeMethod(settings.type) && !this.crossDomain) { xhr.setRequestHeader("X-CSRFToken", csrftoken); } } }); html页面:最后在有需求的页面上去引入
<script src="{% static 'ajax-setup.js' %}"></script>
#注意一定页面上一定要有{%csrf%}
2.django的form组件
1>普通的form校验
缺点:校验条件自己定义,需要检验的内容非常多,很繁琐.
views def reg(request): if request.method == 'POST': user = request.POST.get('user') pwd = request.POST.get('pwd') if len(user) <6: err_msg='用户名太短了' else: return HttpResponse('注册成功') return render(request,'reg.html',locals()) html <form action="" method="post"> {% csrf_token %} <p> 用户名:<input type="text" name="user"><span style="color: red">{{ err_msg }}</span> </p> <p> 密码:<input type="password" name="pwd"> </p> <button>注册</button> </form>
2>form组件的使用
a.导入forms模块,创建一个自定义的类去继承(form.Form),在自定义类种创建一些字段对象
b.创建一个视图方法去实例化这个自定义的类,需要POST判断的时候,将request对象传入自定义类中,再实例化一次,并且用这个对象的is_valid方法进行校验
c.事例用到的参数:
initial :默认给字段对象所对应的input框填入一个字符串,类似于placeholder
min_length,max_length:前端校验,与后端校验的使用一个检测标准最小长度与最大长度.
label:对字段对象对应的input标签,生成一个配套的label标签
widget:插件可以对字段对象的属性进行变更,例如添加一个class属性,更改input的type属性
error_messgaes:根据字段对象里使用的校验标准和默认的校验参数来定义key值和自定义显示的错误信息
CharField:所有的字段对象都可以用这个类去实例化,需要不同的字段类型只需要在widget实例化进行修改即可(例如: widget=forms.widgets.PasswordInput)
ChoiceField:所有选项类的可以根据这个类实例化去修改widget
d.模板语法的使用
对象.字段对象.属性
例如:从views传来一个form_obj的对象,
模板中使用form.as_p :生成P标签(input + label)
form_obj.user.label(取得是user字段对象得label属性)与 form_obj.user.id_for_label(取得是input的id赋给label标签的for属性) 配合,嵌套在label标签中
form_obj.user: 一个input框(属性是自定义类定义的)
form_obj.user.errors.0 :取第一个错误的html的文本值
views from django import forms from app01 import models # Create your views here. #注册form class RegForm(forms.Form): user=forms.CharField( initial='lin', min_length=6, max_length=10, label='用户名', widget=forms.widgets.Input(attrs={'class':'form-control'}), error_messages={ 'min_length':'长度至少为8位', 'required':'不能为空' } ) pwd=forms.CharField(label='密码', widget=forms.widgets.PasswordInput(attrs={'class':'form-control'}), ) gender=forms.ChoiceField(choices=((1,'male'),(2,'female'),(3,'other')), widget=forms.RadioSelect() ) hobby = forms.ChoiceField( # choices=((1,'篮球'),(2,'足球'),(3,'双色球')), # choices=models.Hobby.objects.all().values_list(), #values_list取出来元组,数据全是值 label='爱好', initial=[1,3], widget=forms.SelectMultiple() ) def __init__(self,*args,**kwargs): super().__init__(*args,**kwargs) self.fields['hobby'].choices=models.Hobby.objects.all().values_list() def reg2(request): form_obj = RegForm() if request.method == 'POST': form_obj =RegForm(request.POST) if form_obj.is_valid(): return HttpResponse('注册成功') return render(request,'reg3.html',{'form_obj':form_obj}) html {% load static %} <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="{% static 'bootstrap-3.3.7-dist/css/bootstrap.css' %}"> </head> <body> <form class="form-horizontal" method="post" action="" novalidate> {% csrf_token %} <div class="form-group {% if form_obj.user.errors %}has-error{% else %} has-success{% endif %}"> <label for="{{ form_obj.user.id_for_label }}" class="col-sm-2 control-label">{{ form_obj.user.label }}</label> <div class="col-sm-10"> {{ form_obj.user }} <label class="control-label">{{ form_obj.user.errors.0 }}</label> </div> </div> <div class="form-group"> <label for="{{ form_obj.pwd.id_for_label }}" class="col-sm-2 control-label">{{ form_obj.pwd.label }}</label> <div class="col-sm-10"> {{ form_obj.pwd }} <span>{{ form_obj.pwd.errors }}</span> </div> </div> <div class="form-group"> <label for="{{ form_obj.gender.id_for_label }}" class="col-sm-2 control-label">{{ form_obj.gender.label }}</label> <div class="col-sm-10"> {{ form_obj.gender }} <span>{{ form_obj.gender.errors }}</span> </div> </div> <div class="form-group"> <label for="{{ form_obj.hobby.id_for_label }}" class="col-sm-2 control-label">{{ form_obj.hobby.label }}</label> <div class="col-sm-10"> {{ form_obj.hobby }} <span>{{ form_obj.hobby.errors }}</span> </div> </div> {# 所有的错误提示#} {{ form_obj.errors }} <div class="form-group"> <div class="col-sm-offset-2 col-sm-10"> <button type="submit" class="btn btn-default">注 册</button> </div> </div> </form>
3>form的内置校验器
min_length,max_length,require
前端检测:只要在自定义类中的字段属性例如user定义了上述方法,并且前端开启了检测,即可在input框中对条件进行校验,无需传入数据重新实例化自定义类.
def reg2(request): form_obj = RegForm() if request.method == 'POST': pass # form_obj =RegForm(request.POST) # if form_obj.is_valid(): # return HttpResponse('注册成功') return render(request,'reg3.html',{'form_obj':form_obj})
后台检测:需要前端进行POST提交之后,后台进行form_obj=RegForm(request.POST)实例化,将对象的POST方法取到的数据传入对象中,这样前端传入的form_obj的对象可以在模板语言中使用错误检测,form_obj.errors.
def reg2(request): form_obj = RegForm() if request.method == 'POST': # pass form_obj =RegForm(request.POST) #需要传入request.POST方法的数据 # if form_obj.is_valid(): # return HttpResponse('注册成功') return render(request,'reg3.html',{'form_obj':form_obj})
4>form的自定义校验(向实例化对象传入request.POST数据,实例化的同时就会执行is_valid方法)
a.使用django提供的方式校验
from django.core.validators import RegexValidator #字段对象里使用检测机制,并自定义规则 phone = forms.CharField( label='手机号', validators=[RegexValidator(r'1[3-9]\d{9}','手机号不合格')] )
b.自定以函数
from django.core.exceptions import ValidationError def check_name(value): if 'lin' in value: raise ValidationError('不符合规格') #字段对象直接使用自定义的函数进行校验 user=forms.CharField( initial='lin', min_length=6, max_length=10, label='用户名', widget=forms.widgets.Input(attrs={'class':'form-control'}), validators=[check_name], error_messages={ 'min_length':'长度至少为8位', 'required':'不能为空' } )
def reg2(request): form_obj = RegForm() if request.method == 'POST': # pass form_obj =RegForm(request.POST) #注意 必须实例化自定义对象,并且传入request.POST的数据才可以实现内置校验 # if form_obj.is_valid(): # print(form_obj.cleaned_data) # return HttpResponse('注册成功') return render(request,'reg3.html',{'form_obj':form_obj})
4>form的is_valid方法的源码分析
Django-CSRF,AJAX,FORM的更多相关文章
- Django 基于Ajax & form 简单实现文件上传
前端实现 <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="U ...
- Django框架 之 Form表单和Ajax上传文件
Django框架 之 Form表单和Ajax上传文件 浏览目录 Form表单上传文件 Ajax上传文件 伪造Ajax上传文件 Form表单上传文件 html 1 2 3 4 5 6 7 <h3& ...
- python Django之Ajax
python Django之Ajax AJAX,Asynchronous JavaScript and XML (异步的JavaScript和XML),一种创建交互式网页应用的网页开发技术方案. 异步 ...
- pythonのdjango CSRF简单使用
一.简介 django为用户实现防止跨站请求伪造的功能,通过中间件 django.middleware.csrf.CsrfViewMiddleware 来完成.而对于django中设置防跨站请求伪造功 ...
- Django之Ajax文件上传
请求头ContentType ContentType指的是请求体的编码类型,常见的类型共有3种: 1 application/x-www-form-urlencoded(看下图) 这应该是最常见的 P ...
- Django CSRF提交遇见的问题
简介 django为用户实现防止跨站请求伪造的功能,通过中间件 django.middleware.csrf.CsrfViewMiddleware 来完成.而对于django中设置防跨站请求伪造功能有 ...
- python 全栈开发,Day75(Django与Ajax,文件上传,ajax发送json数据,基于Ajax的文件上传,SweetAlert插件)
昨日内容回顾 基于对象的跨表查询 正向查询:关联属性在A表中,所以A对象找关联B表数据,正向查询 反向查询:关联属性在A表中,所以B对象找A对象,反向查询 一对多: 按字段:xx book ----- ...
- django csrf使用教程,解决Forbidden (403)CSRF verification failed. Request aborted.
Django版本号:1.11.15 django中post请求报错:Forbidden (403)CSRF verification failed. Request aborted. HelpReas ...
- Django 2.0 学习(22):Django CSRF
Django CSRF CSRF攻击过程 攻击说明: 1.用户C打开浏览器,访问受信任网站A,输入用户名和密码请求登陆网站A: 2.在用户信息通过验证后,网站A产生Cookie信息并返回给浏览器,此时 ...
- Django 之Ajax&Json&CORS&同源策略&Jsonp用法
什么是Json 定义: JSON(JavaScript Object Notation, JS 对象标记) 是一种轻量级的数据交换格式.它基于 ECMAScript (w3c制定的js规范)的一个子集 ...
随机推荐
- Python的生成器send()方法 & yield_from
生成器对象是一个迭代器.但是它比迭代器对象多了一些方法,它们包括send方法,throw方法和close方法.这些方法,主要是用于外部与生成器对象的交互.本文先介绍send方法. send send方 ...
- Windows下的命令神器Cmder
1. 下载地址: https://cmder.net/ 建议安装完整版本 2.设置与基本使用 1)将cmder添加到环境变量中PATH 2)添加到右键 Cmder.exe /REGISTER ALL ...
- centos7之zabbix3.2代理(zabbix-proxy)搭建
zabbix的强大之处也在于它是分布式监控系统,对于多机房大集群情况下,肯定不是一台zabbix-server服务器来进行信息的收集等工作,就要用到代理了.在记录zabbix-proxy之前,要系统的 ...
- IP地址、子网掩码、默认网关是什么意思?
(一) 问题解析 001. 问: IP地址,子网掩码,默认网关,DNS服务器,有什么区别呀?我知道没有IP地址就不能上网,我也知道没设DNS就不能上外网,可它们都有什么功能,有什么区别呢?还有 ...
- P2522 [HAOI2011]Problem b (莫比乌斯反演)
题目 P2522 [HAOI2011]Problem b 解析: 具体推导过程同P3455 [POI2007]ZAP-Queries 不同的是,这个题求的是\(\sum_{i=a}^b\sum_{j= ...
- CSS3基础入门03
CSS3 基础入门03 线性渐变 在css3当中,通过渐变属性实现之前只能通过图片实现的渐变效果.渐变分为线性渐变和径向渐变以及重复渐变三种.线性渐变的模式主要是颜色从一个方向过渡到另外一个方向,而径 ...
- vue stylus 格式化问题
IDE是vscode 安装了.vetur插件 由于stylus可以仅用缩进不用写大括号之类的,所以十分方便, 但有个问题,按alt shift F 格式化时,vetur这个插件会默认添加上正常css的 ...
- [LVM]创建LVM卷
https://www.cnblogs.com/softidea/p/5147090.html
- LeetCode--11_974_Subarray_Sums_Divisible_by_K
题目链接:点击这里 public static int subarraysDivByK(int[] A, int K) { int ans = 0,sum = 0; int[] B = new int ...
- Spring Boot学习总结一
Spring Boot大大简化了之前java项目的繁琐xml配置,本文简单的总结下spring boot的相关知识. 1,@RestController 配置在controller中就是control ...