Django与Ajax
一、Ajax简介
1.什么是AJax
AJAX(Asynchronous Javascript And XML)翻译成中文就是“异步的Javascript和XML”。即使用Javascript语言与服务器进行异步交互,传输的数据为XML(当然,传输的数据不只是XML,现在更多使用json数据)。
- Ajax 不是新的编程语言,而是一种使用现有标准的新方法。
 - 通俗的讲:它是一种创建交互式网页应用的网页开发技术
 
2.Ajax特点
AJAX 最大的优点是在不重新加载整个页面的情况下,可以与服务器交换数据并更新部分网页内容。
Ajax不需要任何浏览器插件,但需要用户允许JavaScript在浏览器上
- 
异步提交:请求发出去,不会卡在这,可以干其他事
 - 
浏览器页面局部刷新:js的dom操作,使页面局部刷新,给用户的感受是在不知不觉中完成请求和响应过程
 
3.异步与同步提交
- 同步交互:客户端发出一个请求后,需要等待服务器响应结束后,才能发出第二个请求
 - 异步提交:客户端发出一个请求后,无需等待服务器响应结束,就可以发出第二个请求
 
4.应用场景
搜索引擎根据用户输入的关键字,自动提示检索关键字
还有一个很重要的应用场景就是注册时候的用户名的查重。
其实这里就使用了AJAX技术!当文件框发生了输入变化时,使用AJAX技术向服务器发送一个请求,然后服务器会把查询到的结果响应给浏览器,最后再把后端返回的结果展示出来。
- 整个过程中页面没有刷新,只是刷新页面中的局部位置而已!
 - 当请求发出后,浏览器还可以进行其他操作,无需等待服务器的响应!
 
当输入用户名后,把光标移动到其他表单项上时,浏览器会使用AJAX技术向服务器发出请求,服务器会查询名为lemontree7777777的用户是否存在,最终服务器返回true表示名为lemontree7777777的用户已经存在了,浏览器在得到结果后显示“用户名已被注册!”。
- 整个过程中页面没有刷新,只是局部刷新了;
 - 在请求发出后,浏览器不用等待服务器响应结果就可以进行其他操作;
 
5.Ajax优缺点
- AJAX使用JavaScript技术向服务器发送异步请求;
 - AJAX请求无须刷新整个页面;
 - 因为服务器响应内容不再是整个页面,而是页面中的部分内容,所以AJAX性能高;
 - 两个关键点:1.局部刷新,2.异步请求
 
6.前端朝后端发送请求的方式
- 地址栏输入url回车:GET
 - a标签href属性指定的url : GET
 - form表单中的submit与button类型 : GET/POST
 - Ajax请求:GET/POST
 - 注意:如果不想触发form表单提交, 1.按钮可以不写在form表单中,2.使用input,类型为button
 
二、Ajax示例
原生js写的ajax非常麻烦, 需要兼容多种浏览器, 并且企业也基本不会用, 下面的学习我们只基于jQuery的Ajax实现, 并不只有jQuery能够实现ajax,其他的框架也可以 但是换汤不换药, 原理是一样的
1.需求
- 页面输入两个整数,通过Ajax传输到后端计算出结果并返回。
 - 强调:整个过程页面不准有刷新,也不能在前端计算
 
2.示例代码
路由层url.py文件
from django.contrib import admin
from django.urls import path,re_path
from app01 import views
urlpatterns = [
    path('admin/', admin.site.urls),
    re_path('^ajax/', views.ajax_test),
    re_path('^pro/', views.product),
]
视图层views.py文件
def ajax_test(request):
    return render(request,'ajax.html')
def product(request):
    if request.method == "POST":
        a1 = request.POST.get('a1')
        a2 = request.POST.get('a2')
        a = int(a1)*int(a2)
        return HttpResponse(a)
模板层ajax.html文件
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    {% load static %}
    <script src="{% static 'jquery-3.4.1/jquery.min.js' %}"></script>
    <link href="{% static 'bootstrap-3.3.7/css/bootstrap.min.css' %}" rel="stylesheet">
    <script src="{% static 'bootstrap-3.3.7/js/bootstrap.min.js' %}"></script>
</head>
<body>
<input type="number" class="form-control text-center" id="a1">
<p class="text-center">x</p>
<input type="number" class="form-control text-center" id="a2">
<p class="text-center">=</p>
<input type="number" class="form-control text-center" id="a3">
<button class="btn btn-warning btn-block">计算</button>
<script>
    // 设置点击事件
    $('.btn').click(function (){
        // 朝后端发送ajax请求
        $.ajax({
            // 指定后端地址,不指定则提交到当前地址
            url:'/pro/',
            // 指定请求方式,不指定默认get
            method:'post',
            // 需要发送的数据
            data:{'a1':$('#a1').val(),'a2':$('#a2').val()},
            // 回调函数:后端返回结果的时候自动触发,并将结果传给args
            success:function(args){
                // 通过DOM操作渲染到第三个input内
                $('#a3').val(args)
            }
        })
    })
</script>
</body>
</html>
效果展示:
三、登入验证示例
1.form表单提交与ajax提交
前面我们说到ajax的提交会与form表单的提交先后进行, 也就是进行了两次提交, 这显然不是我们想看到的结果, 解决方法有两种:
- 将submit或button按钮放在form表单外面(上面的例子我们是直接没有写form表单)
 - 使用input输入框+type='button'来替代按钮,这样就无法触发form表单的提交(下面这个示例我们使用这种)
 
2.需求
- 用户输入用户名和密码, 点击登入朝后端进行提交
 - 后端从数据库拿到数据进行校验, 返回状态码和登入信息
 - 登入成功通过前端进行跳转网站 http://124.71.206.179:8000
 - 登入失败显示错误提示信息
 - 使用ajax向后端提交请求
 
ps :
request.is_ajax( )判断是否是Ajax请求
实现代码
路由层urls.py文件
from django.contrib import admin
from django.urls import path,re_path
from app01 import views
urlpatterns = [
    path('admin/', admin.site.urls),
    re_path('^login/', views.login),
]
模板层models.py文件
from django.db import models
class User(models.Model):
    name = models.CharField(max_length=16,verbose_name='用户名')
    pwd = models.CharField(max_length=16,verbose_name='密码')
    def __str__(self):
        return self.name
用户数据
视图层views.py文件
from django.shortcuts import render,HttpResponse,redirect
from app01 import models
from django.http import JsonResponse
def login(request):
    dic = {'status':None,'msg':None}  # 设置dic保存状态码及登入状态信息
    # 如果是ajax请求
    if request.is_ajax():
        name = request.POST.get('name')  # 获取用户名
        pwd = request.POST.get('pwd')    # 获取密码
        user_obj = models.User.objects.filter(name=name,pwd=pwd).first()  # 拿到对象
        if user_obj:
            dic['status'] = 200  # 存在状态码设置成200
        else:
            dic['status'] = 201
            dic['msg'] = '用户名或密码错误'
        # 方式一 : 直接使用JsonResponse
        return JsonResponse(dic)  # 将登入状态dic返回给前端ajax
        # 方式二 : 手动转json格式
        # import json
        # return HttpResponse(json.dumps(dic))
    return render(request,'login.html')  # get请求展示login页面
上面可以使用方式一和方式二向后端返回响应 :
- 方式一返回的是json格式, 那么ajax接收到数据后会自动转成对象, 然后前端直接可以拿对象进行操作
 - 方式二是以字符串的方式返回了json格式的字符串(html/text格式), ajax接收后需要我们自己去反序列化成对象
 - 总结 : 后端返回数据我们统一使用JsonResponse就可以了
 ps : 如果使用了ajax, 后端就不要再使用redirect、render、HttpResponse了, 直接使用JsonReponse
模板层login.html文件
<body>
<div class="container">
    <div class="row">
        <div class="col-md-8 col-md-offset-2">
            <div class="panel panel-info">
              <div class="panel-heading">用户登入</div>
                  <div class="panel-body">
                      <form action="">
                          用户名:
                          <input type="text" class="form-control" id="a1">
                           密码:
                          <input type="password" class="form-control" id="a2">
                          <br>
                          <input type="button" class="btn btn-warning btn-block" value="登入">
                          <p class="aa" style="color: red"></p>{# 设置一个标签用来展示用户登入状态信息 #}
                      </form>
                  </div>
            </div>
        </div>
    </div>
</div>
</body>
<script>
    $('.btn').click(function () {
        $.ajax({
            url:'/login/',
            method:'post',
            data:{'name':$('#a1').val(),'pwd':$('#a2').val()},
            success:function (data) {
                // 方式二 : 加一行,将json格式字符串转成字典
                // data = JSON.parse(data)
                // 状态码为200则表示登入成功
                if (data.status === 200){
                    // 前端进行网页跳转
                    location.href='http://124.71.206.179:8000'
                }else {
                    // 登入失败则使用DOM操作渲染msg    
                    $('.aa').html(data.msg)
                }
            }
        })
    })
</script>
效果展示
- 校验失败渲染msg
 
- 校验成功跳转
 
四.前后端数据传输的编码格式
1.前端中可以向后端发起post请求的方式
- form表单
 - Ajax请求
 
2.基于post请求, 前后端数据传输的主流编码格式有三种
- urlencoded : 默认的编码格式, 提交的数据从
request.POST中提取 - form-data : 上传文件时使用的编码格式, 提交的数据从
request.POST中提取, 上传的文件从request.FILES中提取 - json : ajax发送的json格式数据, 在
request.POST中取不到数据, 需要在request.body中提取数据 
3.基于post请求, form表单传输数据默认的编码格式
- 默认编码格式为 : urlencoded
 - 如果要上传文件需要在标签中指定 : enctype="multipart/form-data" 编码格式
 - 数据格式 : username=shawn&password=1111
 - 提交位置 : django后端针对符合urlencoded编码格式的数据都会自动帮你解析封装到request.POST中, 文件提交到
request.FILES中 
4.基于post请求, ajax传输数据默认编码格式
- 默认编码格式 : urlencoded
 - 如果要上传文件需要使用 Formdata 对象
 - 数据格式 : username=shawn&password=1111
 - 提交位置 : django后端会自动帮你解析封装到request.POST中, 文件提交到
request.FILES中 
5.json.loads( )是否可以转Bytes格式
- 3.5之前不行, 需要我们手动将 Bytes 格式转成 str 类型, 然后再进行转换
 - 3.6以后可以, Bytes无需手动转 str 类型, 它内部会自动帮你转成 str, 再转成 json
 - 查看 
json.loads( )的源码可以得到验证 : 
五、基于form表单上传文件
实现代码
路由层urls.py文件
re_path('^files/', views.files),
视图层views.py文件
def files(request):
    if request.method == 'POST':
        remark = request.POST.get('remark')
        myfile = request.FILES.get('files')
        print(remark)  # hello
        print(myfile)  # 11.png 
        print(type(myfile))  # <class 'django.core.files.uploadedfile.InMemoryUploadedFile'>
        with open(myfile,'wb')as f:
            for line in myfile:
                f.write(line)
        return HttpResponse('上传成功')
    return render(request,'files.html')
模板层files.html文件
<form action="" method="post" enctype="multipart/form-data">
    留言 : <input type="text" class="form-control" id="a2" name="remark">
    文件 : <input type="file" class="form-control" id="a1" name="myfile">
    <br>
    <input type="submit" class="btn btn-success btn-block" value="提交">
</form>
效果展示
六、基于Ajax上传文件
1.储备知识
- 使用 ajax 发送文件对象需要借助于 js 内置对象 FormData
 - new 一个 FormData 对象
 
var FormDataObj = new FormData
- jQuery表单中获取文件对象
 
<input type="file" class="form-control" id="file" name="myfile">
$('#file')              // jQuery 对象
$('#file')[0]           // 拿到原生js文件对象集
$('#file')[0].files[0]  // 从中取到第一个文件对象
- FormData对象添加数据方式 
.append 
语法 : FormDataObj.append([key],[value])  // 支持添加文件
var file = $('#file')[0].files[0]
FormDataObj.append('myfile',file)
- ajax中参数
 
// 上传文件必须注意的参数
processData: false,  // 不预处理数据,让浏览器不要额外的处理data中的数据
contentType: false,  // 不指定编码格式,使用FormDataObj对象的默认编码就是formdata格式
data:FormDataObj,    // 指定要发送的数据,直接放FormData对象
2.实现代码
路由层urls.py文件
re_path('^ajax_file/', views.ajax_file)
视图层views.py文件
def ajax_file(request):
    if request.is_ajax():
        remark = request.POST.get('remark')
        myfile = request.FILES.get('myfile')
        print(remark)  # haha
        print(myfile)  # 1.jpg
        print(type(myfile))  # <class 'django.core.files.uploadedfile.InMemoryUploadedFile'>
        with open(myfile.name,'wb')as f:
            for line in myfile:
                f.write(line)
        return HttpResponse('使用ajax文件上传成功')
    return render(request,'ajax_file.html')
- 模板层 ajax_file.html 文件
 
// html标签
<form action="">
    留言 : <input type="text" class="form-control" id="a2">
    文件 : <input type="file" class="form-control" id="a1">
    <br>
    <input type="button" class="btn btn-success btn-block" value="提交">
</form>
// script
<script>
    $('.btn').click(function () {
        var FormDataObj = new FormData()  // new一个FormData对象
        var remark = $('#a2').val()       // 取到remark值
        var myfile = $('#a1')[0].files[0] // 取到文件对象
        FormDataObj.append('remark', remark)  // 将remark添加到对象中
        FormDataObj.append('myfile', myfile)  // 将文件对象添加到对象中
        $.ajax({
            url: '/ajax_file/',
            method: 'post',
            processData: false,
            contentType: false,
            data: FormDataObj,
            success: function (args) {
                alert(args)
                location.href='/ajax_file/'
            }
        })
    })
</script>
3.效果展示
七.stringify 与 parse 方法
stringify 和 parse 都是 JavaScript 中关于 JSON 对象和字符串转换的方法:
1.JSON.stringify( ) 序列化
- 用于将 JavaScript 值转换为 JSON 字符串
 
res = JSON.stringify({'name':"shawn"})
2.JSON.parse( ) 反序列化
- 用于将一个 JSON 字符串转换成 JavaScript 对象
 - json 只能识别双引号的字符串格式
 
res = JSON.parse('{"name":"shawn"}')
八.ajax发送json格式数据
提示 : 前端向后端发送数据的时候, 必须要保证数据格式与发送时contentType指定的数据格式一致
1.代码实现
- 路由层 urls.py 文件
 
re_path('^ajax_json/', views.ajax_json)
- 视图层 views.py 文件
 
def ajax_json(request):
    if request.is_ajax():
        # json格式数据需要到request.body中取,其他里面没有
        print(request.POST)  # <QueryDict: {}>(空的)
        print(request.FILES) # <MultiValueDict: {}>(空的)
        print(request.body)  # b'{"name":"\xe8\xae\xb8\xe6\x96\x87\xe5\xbc\xba","pwd":"123456"}'
        # 3.5Python解释器以前需要手动将Bytes格式转换成str格式,再进行反序列化
        # data_bytes = request.body
        # data_json_str = data_bytes.decode()
        # data_dict = json.loads(data_json_str)
        # 3.6版本以后,json.loads支持支持反序列化Bytes格式(第四小节有源码介绍)
        data_dict = json.loads(request.body)
        name = data_dict['name']
        pwd = data_dict['pwd']
        print(name,pwd)  # 许文强 123456
        return HttpResponse(f'提交成功\n返回数据:\nname:{name}\npwd:{pwd}')
    return render(request,'ajax_json.html')
- 模板层 ajax_json.html 文件
 
// html标签
<form action="" >
    用户名:
    <input type="text" class="form-control" id="a1">
    密码:
    <input type="password" class="form-control" id="a2">
    <br>
    <input type="button" class="btn btn-warning btn-block" value="上传信息">
</form>
// script
<script>
    $('.btn').click(function () {
        var name = $('#a1').val()
        var pwd = $('#a2').val()
        var data = JSON.stringify({'name':name,'pwd':pwd})  // 将其转成json格式字符串
        $.ajax({
            url:'ajax_json',
            method:'post',
            contentType:'application/json',  // 指定数据格式
            data:data,  // json格式的数据,需要与上面指定的一致
            success:function (args) {
                alert(args)
            }
        })
    })
</script>
2.效果展示
九、django自带的序列化组件(序列化器)
1.组件介绍
- 导入组件
 
from django.core import serializers
- 组件使用/参数介绍
 
serializers.serialize('json', user_queryset)
# 第一个参数是指定需要序列化的类型
# 第二个参数是指定需要序列化的数据
# 返回的结果是一个列表套字典格式的序列化之后的数据
2.代码示例
from django.core import serializers
def dj_json(request):
    user_list = models.User.objects.all()
    res = serializers.serialize("json",user_list)
    return HttpResponse(res)
- 显示结果
 
从上面的结果我们可以发现 :
序列化器是将对象转成格式字符串, 但字段不能控制, 现阶段我们如果要做序列化, 最好使用for循环+列表套字典; 但这个组件在后面drf中会使用到
3.使用for循环+列表套字典做序列化
def for_json(request):
    user_list = models.User.objects.all()
    l = []
    for obj in user_list:
        l.append({'id':obj.id,'name':obj.name,'pwd':obj.pwd})
    return JsonResponse(l, safe=False)
- 显示结果
 
字段可控, 比较清晰
十、小结
# Ajax简介
    # ajax 全称 asynchronous javascript and xml
    # 特点: 异步提交. 局部刷新
    # 描述
        1. 不是编程语言. 可类比成装饰器. 是在原js的基础之上的新方法
        2. 可以在不重载页面. 局部与后端进行数据交互.
        3. 注意: ajax我们只争对jquery封装的版本. 所以我们要先导入jquery
        4. 提示: JQuery实现Ajax并不是唯一的. 其它框架也是可以.
    # 前后端发送请求的4种方式:
        1. 浏览器地址栏输入url                      get请求
        2. a标签的href属性                         get请求
        3. form表单的input的submit和button按钮     post请求, get请求
        4. ajax                                   post请求, get请求
# 实际应用小栗子
    # ajax前端使用方法
        $.ajax({
            url: '',          // 指定路径. 默认不指定就是当前地址提交
            type: 'post',     // 指定请求方式. 默认不指定就是get
            data: {},         // 发送给后端的数据. 以key:value对的形式存在. 后端通过.get(key)拿到对应的value数据. 注意: 后端拿到的一律是字符串类型.
            dataType: 'json',
            /*
            指定自动将后端序列化好的string格式的json格式进行反序列化成前端的对象.
            后端如果是使用HttppResponse返回序列化的数据. 我们这里可以指定也可以不指定. 不指定就使用JASON.parse进行反序列化.
            如果后端使用JsonResponse返回序列化的数据. 那么就可以省略这一步操作. 在前端默认拿到的就是对象.
            */
            success: function(args) {   // 回调函数. args就是后端return返回的结果
            },
        })
    # 后端返回需要注意的事情
        1. request.POST.get到前端发送过来的数据都是str类型
        2. 如果使用HttpResponse. 要返回其它类型数据. 需要json序列化
        3. 如果使用JsonResponse. 返回给前端的数据无需手动序列化.
                版权声明:
                                    
作者:淘小欣                                    
链接:https://blog.taoxiaoxin.club/163.html
                                    
来源:淘小欣的博客                                    
文章版权归作者所有,未经允许请勿转载。
                                
                










共有 0 条评论