• 🍖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":"xe8xaexb8xe6x96x87xe5xbcxba","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'提交成功
    返回数据:
    name:{name}
    pwd:{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

    字段可控, 比较清晰

  • 相关阅读:
    20145327 《信息安全系统设计基础》实验三 实时系统的移植
    20145327 《信息安全系统设计基础》第十周学习总结
    20145327 《信息安全系统设计基础》第九周学习总结
    20145327 《信息安全系统设计基础》 实验五 网络通信
    20145326蔡馨熤《计算机病毒》——静态分析(2)
    20145326蔡馨熤《计算机病毒》——静态分析(1)
    20145326蔡馨熤《网络对抗》——恶意代码伪装技术实践
    20145326蔡馨熠《网络对抗》——恶意代码分析
    20145326蔡馨熠《网络对抗》——免杀原理与实践
    20145326蔡馨熠《网络对抗》 后门原理与实践
  • 原文地址:https://www.cnblogs.com/songhaixing/p/14583287.html
Copyright © 2020-2023  润新知