Django中的事务与ajax

事务与锁

 1.行级锁

行级锁是由存储引擎实现的。如mysql里默认指定的InnoDB存储引擎,由它实现行级锁。InnoDB的行级锁定同样分为两种类型,共享锁(X)和排他锁(S)。

对于UPDATE、DELETE和INSERT语句,InnoDB会自动给涉及数据集加排他锁(X);对于普通SELECT语句,InnoDB不会加任何锁

事务可以通过以下语句显示给记录集加共享锁或排他锁。

共享锁(S):SELECT * FROM table_name WHERE .. LOCK IN SHARE MODE

排他锁(X):SELECT * FROM table_name WHERE .. FOR UPDATE

修改时,加了排他锁,其他临时会话不能查和修改等操作

Lock table tab_name write;给表加了写锁,临时会话不能往里面写。

Unlock tables;    解除写锁

 2.ORM里加锁

加行级锁:select_for_update(nowait=False, skip_locked=False)

加行级锁必须用在事务里。

手动加互斥锁:

entries = models.Entry.objects.select_for_update().filter(author=request.user)

共享锁Mysql会自动加,因此不需用加共享锁。create、update、delete操作时,mysql自动加行级互斥锁,因此查看时可加互斥锁。

所有匹配的行将被锁定,直到事务结束。这意味着可以通过锁防止数据被其它事务修改。

 3.事务

(1)事务简介

事务具有ACID属性

事务控制语句

BEGIN或START TRANSACTION;显式地开启一个事务;

COMMIT;               COMMIT会提交事务,并使已对数据库进行的所有修改成为永久性的;

ROLLBACK;            回滚会结束用户的事务,并撤销正在进行的所有未提交的修改;

SAVEPOINT identifier;    SAVEPOINT允许在事务中创建一个保存点,一个事务中可以有多个SAVEPOINT;

RELEASE SAVEPOINT identifier;    删除一个事务的保存点,当没有指定的保存点时,执行该语句会抛出一个异常;

ROLLBACK TO identifier;   把事务回滚到标记点;

(2Django里事务操作

Django里开启事务有两大类,一是全局形式,二是局部形式。

a.全局形式

方法:在用户settings.py文件里,在DATABASES配置里,加入 "ATOMIC_REQUESTS":True。

原理:当有请求过来时,Django会在调用视图方法前开启一个事务。如果请求正确处理并正确返回了结果,Django就会提交该事务。否则,Django会回滚该事务。因此全局开启事务,绑定的是http请求响应整个过程。

b.局部形式

atomic(using=None, savepoint=True)[source]

atomic是原子性。使用atomic,我们就可以创建一个具备原子性的代码块。一旦代码块正常运行完毕,所有的修改会被提交到数据库。反之,如果有异常,更改会被回滚。(要么全成功,要么全失败)

(i)方式一:装饰器

from django.db import transaction
@transaction.atomic
def viewfunc(request):    do_stuff() 里面代码就在事务里

(ii)方式二:上下文管理器(设置事务的保存点)

from django.db import transaction
def  viewfunc(request):
     do_stuff()       #这段代码使用默认的方式
     with transaction.atomic():   #保存点
            do_more_stuff()      #这段代码在事务里
    do_other_stuff()

 注意::如果配置了全局的事务,它和局部事务可能会产生冲突。比如说:局部的事务完成之后,如果该函数里面其他的sql出了问题,那么局部事务也是提交不上。因为全局会回滚这个请求和响应所涉及到的所有的sql(局部的也被回滚了)。建议项目用局部事务。

 设置事务小原则:

1.保持事务短小

2.尽量避免事务中rollback

3.尽量避免savepoint

4.默认情况下,依赖于悲观锁

5.为吞吐量要求苛刻的事务考虑乐观锁

6.显示声明打开事务

.锁的行越少越好,锁的时间越短越好

Ajax使用

一、Ajax介绍

Ajax:Asynchronous Javascript And XML。即异步的Javascript和XML。使用Javascript语言与服务器进行异步交互,传输的数据为XML(现在多为json)

(一)Ajax两大特性:

异步交互和局部刷新。

异步交互:客户端发出一个请求后,无需等待服务器响应结束,就可以发出第二个请求。同步交互指客户端发出一个请求后,需要等待服务器响应结束后,才能发出第二个请求。

局部刷新:不会刷新整个页面,局部内容发生变化。

(二)应用场景

1.搜索引擎根据用户输入的关键字,自动提示检索关键字。

2.注册时候的用户名的查重。(提示该用户已经注册过了)

当输入用户名后,光标移动到其他表单项时,浏览器会使用AJAX技术向服务器发出请求(这个时候你可以继续其他操作,这就是异步交互),服务器会查询用户名是否存在,然后返回结果(这个页面没有刷新,只有局部内容刷新了)。

二、Ajax操作

做个简单的注册页面,利用Ajax实现异步请求和局部刷新

(一)django基本设置

静态文件配置(引入juqery.js),分发路由操作

(二)操作

1.回复html页面

2.写html文件

ajax上传文件:<input type="file" id="file">

ajax用户名:<input type="text" id="uname">

<button id="btn">提交</button>

注意:form表单最后的提交按钮的type必须时button。如果还是写submit,那么提交还是按照form表单提交,不按照ajax提交。提交方式与form表单无关了,自然服务器取数据也与input标签的name值无关了。

3.ajax代码接收用户数据

1)绑定事件

$('#btn').click(function () {}

给提交按钮绑定点击事件。

2)ajax

通过 $.ajax({})方式来使用ajax。{}里是字典,主要包括三大部分url、type和success。浏览器有数据时还需data获取数据。

data内容:

data:{
     uname:$('#username').val(),    {#  获取数据  #}
     pwd:$('#password').val(),
     //csrfmiddlewaretoken:$('[name=csrfmiddlewaretoken]').val(), {#和form表单一样的crsf #}
     //方式二:
     csrfmiddlewaretoken: '{{ csrf_token }}'
            },

data数据是字典的形式。键为后台获取值的关键字。值:先定位到html文件里数据的标签,再通过val()取值。data数据里还要给后台传输csrf值(post请求提交要验证):html标签里有,直接以键值对的形式传输过去。

4.后台处理数据并发送数据给ajax

Ajax将data数据发给后台,后台在视图函数进行处理:

1)获取ajax发来的数据

name=request.POST.get('uname')

pwd=request.POST.get('pwd')

2)匹配成功---进行数据处理和给ajax发消息

根据取来的值和数据库的进行比较,如果再数据库里,就给用户返回首页。不用ajax的话,django就直接重定向redirect。但用ajax,ajax识别不了redirect。因此要给ajax回复一个字典,让ajax进行重定向。

字典里有code码。方便ajax做判断,再做不同的处理。

发送形式:django发送给浏览器只有两种。Render发网页,HttpResponse发字符串。因此发过去的字典必须是字符串形式的。而ajax那边需要的是字典形式的数据。因此需要用到json解析。

数据传输

方式一:(不推荐)

发送端:字典外面直接包裹‘’,写成字符串的形式(注意json格式。里面都是双引号,最外面单引号),然后通过HttpResponse发送过去

 ret = '{"code":0,"redirect_url":"/index/"}'
 return HttpResponse(ret)

接收端:JSON.parse(接收数据)  去掉’’,由字符串变成字典

 var resStr=JSON.parse(res);

res是响应数据,从success:function (res)里接收

方式二:

dumps方法将ret转为json字符串

d1={"code":0,"redirect_url":"/index/"}
import json
d1_json=json.dumps(d1)     #给字典外面加个单引号,里面都是双引号 return HttpResponse(d1_json,content_type='application/json')    #声明数据是json格式的,ajax接收数据不用反序列化。

HttpResponse发送json字符串过去时,可以再后面告诉ajax这个数据的格式是json格式的,ajax接收数据不用反序列化,可以直接处理。

方式三:

利用Django的JsonResponse方法。

from django.http import JsonResponse
d1 = {"code": 0, "redirect_url": "/index/"}
return JsonResponse(d1)

 JsonResponse内部有转化json字符串的功能,同时也声明了类型是json。因此直接传输数据给ajax。Ajax也不需要反序列化。

3)匹配失败:

匹配失败,也需告诉ajax信息,让ajax操作。

ret = '{"code":3,"redirect_url":"用户名或者密码错误"}'
return HttpResponse(ret)

 5.ajax处理后台的数据,并操作dom标签

Ajax接收到后台的数据,并进行处理,这部分代码都写在success:function (res) {}字典里。参数res是后台的响应数据,即传过来的值。

1)针对不同code做不同的处理

如果是code是3,即用户名或密码错误,就新增标签给用户提示。(标签这个也可以写在html里。)

 success:function (res) {
                console.log(res);          {#res为响应数据#}
                var resStr=JSON.parse(res);    {#  反序列化 解析res,由字符串变为字典  直接传过来json字符串需要,用dumps序列化并且发送过来声明类型了或者是JsonResponse发送过来不需要反序列化#}
                if (resStr['code']===3){
                    {#局部刷新:'{"code":3,"redirect_url":"用户名或者密码错误"}'#}
                    var spanEle=document.createElement('span');
                    $(spanEle).text(resStr['redirect_url']);
                    $('form').append(spanEle);
                }

2)如果输入正确,即code=0,就重定向

 location.href=resStr['redirect_url'];

(三)Ajax补充:

1.ajax流程

Ajax代码可以通过外部文件引入的方式导入到html文件。但这有一个问题:加载顺序会导致ajax里的模板渲染失败({{}}和{%%})。

地址栏输入网址------》django进行路由分发------》执行逻辑函数--------》渲染html文件---------》把渲染好的html给浏览器渲染------》浏览器再次渲染。

 如果ajax文件是通过外部方式导入的,django在模板渲染时是渲染不到ajax的。浏览器渲染HTML文件时才加载ajex文件,此时django已经渲染结束了。

解决方法:ajax是外部文件时,js语法就不要用django的模板语法。

2.ajax的csrf_token验证

三个方式:(1)通过获取隐藏的input标签中的csrfmiddlewaretoken值,放置在data中发送。(2)模板语法。在ajax设置时发送数据过去。(3)通过获取返回的cookie中的字符串 放置在请求头中发送。

1)"csrfmiddlewaretoken": $("[name = 'csrfmiddlewaretoken']").val()

2)$.ajaxSetup({

    data: {csrfmiddlewaretoken: '{{ csrf_token }}' },

});

 三、Ajax文件上传

(一)ContentType介绍

1.简介

ContentType可在请求头中看到,指的是请求体的编码类型。表示的是数据提交的方式。

ContentType类型有三种:application/x-www-form-urlencoded、 multipart/form-data和 application/json。

2.application/x-www-form-urlencoded

urlencoded是最常见的 POST 提交数据的方式。在<form> 表单,如果不设置 enctype 属性,那么最终就会以 默认格式application/x-www-form-urlencoded 方式提交数据,ajax默认也是这个。

数据形式:以&作为分割,通过等于方式连接键和值

  3.multipart/form-data

上传文件

使用表单上传文件时,必须让 <form> 表单的 enctype 等于 multipart/form-data

 4.application/json

Network里可以查看到response headers和requests headers。response headers的contenttype是服务器告诉浏览器数据是什么格式封装的。requests headers的contenttype是浏览器告诉服务器,数据是什么格式。

5.ajax里的contenttype

ajax里面写上这个contenttype类型,表示data的数据类型也要变成这个格式。Data默认是urlencoded格式。服务端接受到数据之后,通过contenttype类型的值来使用不同的方法解析数据。django能解析application/x-www-form-urlencoded 和multipart/form-data,但不能解析application/json类型。

 Django里可通过request.body取出原始值,再将byte类型的数据转化为字符串。

 (二)ajax文件上传

1.操作

Ajax给服务端上传文件的数据不能直接写在data里了,要借助一个FormData的类生成的对象formdata,把文件添加到这个对象中,在通过data发送给服务端。其次,还要在data下面写两个参数,保证ajax上传文件时不对文件内容做任何处理。

 1)把数据添加到formdata对象里

var formdata=new FormData();
formdata.append('aa',$('#uname').val());
formdata.append('headpic',$('#file')[0].files[0]);
formdata.append('csrfmiddlewaretoken',$('[name=csrfmiddlewaretoken]').val());

找到文件操作: $('#file')[0]将jquery对象变为dom对象,利用dom的files方法拿到文件(是个列表),再取第一个值,即是文件内容。

2)将formdata放到data里,提交给服务端。并且设置参数

data:formdata,
processData:false,    //不处理数据(不让预处理)
contentType:false,   //不设置内容类型    这两个在ajax上传文件是固定死的.不对文件做任何操作

3)视图函数最开始要返回页面

    if request.method=='GET':
        return render(request,'upload.html')

4)取到数据

file_obj=request.FILES.get('headpic')

文件必须通过FILES方法取得,file_obj里就有数据。调用该对象的name属性,获得文件名。

5)写入数据

方式一:   

  with open(path,'wb')as f:
            for i in file_obj:     #每次读一行(以\r   \n   \r\n为分隔符)
                f.write(i)

方式二:

with open(path, 'wb')as f:
             for chunk in file_obj.chunks():    #读数据有个固定大小    默认64KB 最大2.5M .django的全局配置里面可以改chunks大小
                f.write(chunk)           # 64 * 2 ** 10  在base里

猜你喜欢

转载自www.cnblogs.com/yq055783/p/12370397.html
今日推荐