13 Django与Ajax

162次阅读
没有评论

共计 9533 个字符,预计需要花费 24 分钟才能阅读完成。

一.Ajax 简介

1. 什么是 Ajax

  • AJAX(Asynchronous Javascript And XML)翻译成中文就是“异步 Javascript 和 XML”
  • 即使用 Javascript 语言与服务器进行异步交互,传输的数据为 XML
  • 当然,传输的数据不只是 XML,现在更多使用 json 数据
  • 通俗的讲 : 它是一种创建交互式网页应用的网页开发技术

2.Ajax 特点

  • 异步提交
  • 浏览器页面 局部刷新 : 这一特点给用户的感受是在不知不觉中完成请求和响应过程

3. 异步与同步提交

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

4. 前端向后端发起请求方式

  • 地址栏输入 url 回车 : GET
  • a 标签 href 属性指定的 url : GET
  • form 表单中的 submit 与 button 类型 : GET/POST
  • ajax 请求 : GET/POST
  • 注意 : 如果不想触发 form 表单提交, 1. 按钮可以不写在 form 表单中,2. 使用 input, 类型为 button

ps : 原生 js 写的 ajax 非常麻烦, 需要兼容多种浏览器, 并且企业也基本不会用, 下面的学习我们只基于 jQuery 的 Ajax 实现, 并不只有 jQuery 能够实现 ajax,其他的框架也可以 但是换汤不换药, 原理是一样的

二.Ajax 入门小示例

1. 需求

  • 页面三个输入框和一个 ''计算'' 按钮
  • 在前两个输入框内输入数字, 点击计算按钮, 在第三个输入框内动态展示前两数字乘积
  • 使用 Ajax 向后端提交请求, 页面不能进行刷新
  • 计算必须在后端进行

2. 代码示例

  • 路由层 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('^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>

3. 展示效果

13 Django 与 Ajax

三. 登入验证示例

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 请求

3. 实现代码

  • 路由层 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
  • 用户数据

13 Django 与 Ajax

  • 视图层 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>

3. 效果展示

  • 校验失败渲染 msg

13 Django 与 Ajax

  • 校验成功跳转

13 Django 与 Ajax

四. 前后端数据传输的编码格式

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() 的源码可以得到验证 :

13 Django 与 Ajax

五. 基于 form 表单上传文件

1. 代码实现

  • 路由层 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>

2. 效果展示

13 Django 与 Ajax

六. 基于 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. 效果展示

13 Django 与 Ajax

七.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. 效果展示

13 Django 与 Ajax

九.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)
  • 显示结果

13 Django 与 Ajax

从上面的结果我们可以发现 :

序列化器是将对象转成格式字符串, 但字段不能控制, 现阶段我们如果要做序列化, 最好使用 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)
  • 显示结果

13 Django 与 Ajax

字段可控, 比较清晰

正文完
 
shawn
版权声明:本站原创文章,由 shawn 2023-06-16发表,共计9533字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
评论(没有评论)