🍖Django与Ajax

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

三.登入验证示例

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

image-20210325153532652

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

  • 校验成功跳转

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

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

image-20210325211347934

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

六.基于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)
  • 显示结果

image-20210325223136130

字段可控, 比较清晰

posted @ 2021-03-26 17:21  给你骨质唱疏松  阅读(490)  评论(1编辑  收藏  举报