Django09Ajax介绍

JsonResponse复习下。

一:Ajax介绍

AJAX = Asynchronous JavaScript and XML(异步的 JavaScript 和 XML)。

即使用Javascript语言与服务器进行异步交互,传输的数据为XML(当然,传输的数据不只是XML,现在更多使用json数据)。

AJAX 不是新的编程语言,而是一种使用现有标准的新方法。

AJAX 是与服务器交换数据并更新部分网页的艺术,在不重新加载整个页面的情况下。

  • 异步:请求发出去,不会卡在这,可以干其他事。
  • 局部刷新:js的dom操作,使页面局部刷新。
  • 基本上web页面都有很多ajax请求。

1.什么是Ajax?

AJAX(Asynchronous Javascript And XML)翻译成中文就是“异步Javascript和XML”。

  • 异步:和同步对应;
  • JavaScript:通过JavaScript来操作,发送请求到服务端;
  • XML:数据交互使用XML,现在主流使用JSON格式;
  • 局部刷新:JS的DOM操作。

刚发明的时候穿的是XML后来截至目前21世纪20年代前后兴起用json格式。

即使用Javascript语言与服务器进行异步交互,传输的数据为XML(当然,传输的数据不只是XML,现在更多使用json数据)。

AJAX 是一种用于创建快速动态网页的技术。

通过在后台与服务器进行少量数据交换,AJAX 可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。

传统的网页(不使用 AJAX)如果需要更新内容,必需重载整个网页面。

有很多使用 AJAX 的应用程序案例:新浪微博、Google 地图、开心网等等。

❗ AJAX应用程序与浏览器和平台无关的!

2.同步与异步

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

3.XML格式与JSON格式

XML格式:

<name>BAOBAO</name>
<age>18</age>
<gender>male</gender>

JSON格式:

{
    "name": "Darker",
    "age": "18",
    "gender": "male",
}

对比:

格式 可阅读性 解析难度 空间占用
XML 复杂
JSON 简单

Ajax--->服务器---->Ajax执行流程图

img

写ajax跟后端交互

1 使用原生js写ajax请求(没有人用)

  • 第一:麻烦;
  • 第二:区分浏览器,需要做浏览器兼容。

2 现在主流做法(现成有人封装好了,jquery,axios..)

前后端分离开发主流用Ajax。

前后端混合开发用jQuery。(公司几乎不用原生js)

  • 以jquery为例讲;
  • 后面会讲axios。

1 ajax发送其他请求

1 大坑
	-如果在form表单中,写button和input是submit类型,会触发form表单的提交
    -如果不想触发:
    	-不写在form表单中
        -使用input,类型是button
        
2 坑
	-后端响应格式如果是:html/text格式,ajax接收到数据后需要自己转成对象
    -后端响应格式是:json,ajax接收到数据后会自动转成对象
    -总结:后端返回数据,统一都用JsonResponse、
    
3 坑
	-如果使用了ajax,后端就不要返回rediret,render,HttpResponse
    -直接返回JsonResponse

二:Ajax的简单使用

原生JS可以写Ajax请求的,但是写起来很复杂,而且需要考虑浏览器的版本(不推荐使用)

JQuery已经封装了1个ajax方法,直接调用JQuery,就可以发送Ajax请求

前后端分离的项目,依旧可以使用JQuery的ajax,但是axios更加主流一些

本质:通过JS发送HTTP请求(异步请求)

基本格式

$ 是jQuery对象;写在script标签内。

$.ajax({
    url: '/add/',  //ajax请求的地址
    method: 'post',  # 指定请求方式
    data: {
        'a': $('#first').val(), //取到first的值
        'b': $('#second').val(), //取到second的值
    },
    success: function (data) {  // success:函数(形参)
        // 成功后 触发
    },
    error: function () {
        // 失败后 触发 
    }
})
  • $.ajax()  # 相当于jQuery提供了Ajax函数;括号内传参数。
    
  • 上面$.ajax() 中传的参数是对象类型用 key:vlaue 形式。

  • data 是数据形式key:value形式,js中key可以不加引号 “ ”。

实例一:ajax实现计算

1.需求

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

后端views.py

def ajax_test(request):

    return render(request,'ajax_test.html')

def sum(request):
    import time
    time.sleep(2)
    a1=int(request.GET.get('a1'))
    a2=int(request.GET.get('a2'))
    return HttpResponse(a1+a2)

前端ajax_test.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>计算</title>
    <script src="/static/jquery-3.3.1.js"></script>
</head>
<body>

<input type="text" id="a1"> + <input type="text" id="a2">=<input type="text" id="sum">
<button id="btn_submit">计算</button>
</body>
<script>
	// 设置点击事件
    $('#btn_submit').click(function () {
        var a1 = $('#a1').val()  //取到a1的值
        var a2 = $('#a2').val()  //取到a2的值
        // 发送ajax请求,计算,返回结果
        $.ajax({
            url: '/sum1/',  //ajax请求的地址,这里和url中要一致。指定后端地址,不指定则提交到当前地址。
            method: 'get',//请求方式,不指定默认get
            data: {'a1': a1, 'a2': a2}, //携带参数;需要发送的数据。
             // 回调函数:后端返回结果的时候自动触发,并将结果传给args
            success:function (data) {   //服务端成功返回会回调,执行匿名函数
                console.log(data)
                $('#sum').val(data)
            }
        })
    })
</script>
</html>

路由urls.p

from django.conf.urls import url
from django.contrib import admin
from app01 import views

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^ajax/', views.ajax),
    url(r'^sum1/', views.sum),
]

实例二:ajax实现计算

效果:

index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>计算</title>
    <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.css">
    <script src="/static/js/jquery-3.5.1.min.js"></script>
</head>
<body>
<div class="container-fluid">
    <div class="row">
        <div class="col-md-6 col-lg-offset-3" style="margin-top: 100px;">
            <input type="text" id="first"> +
            <input type="text" id="second"> =
            <input type="text" id="sum">
            <button class="btn btn-success btn-sm" id="btn">计算</button>
        </div>
    </div>
</div>
<script>
    $('#btn').click(function () {

        $.ajax({
            url: '/add/',    // 向哪个地址发送请求
            method: 'post',  // 发送什么请求
            // 使用jQuery获取输入框内的值
            // data:向后端传输的数据(没有指定编码,就默认使用urlencoded)
            data: {
                'a': $('#first').val(),
                'b': $('#second').val(),
            },
            success: function (data) {
                // 数据正常返回,就会触发该匿名函数的执行,返回的数据就会赋值给data
                console.log(data)
                // 把后端返回的数据,通过DOM操作,返回到框中
                $('#sum').val(data)
            },
            error: function () {
                // 失败,会触发这个
                console.log('出错了')
            }
        })
    })
</script>
</body>
</html>
views.py
from django.shortcuts import render, HttpResponse

def index(request):
    return render(request, 'index.html')

def add(request):
    # request.is_ajax(): 判断是否是ajax请求
    if request.method == 'POST':
        a = int(request.POST.get('a'))
        b = int(request.POST.get('b'))
        print(a, b)
        return HttpResponse(a + b)
urls.py
urlpatterns = [
    path('', views.index),
    path('add/', views.add),
]

实例三:ajax实现认证后跳转

ajax能不能自动解析取决于响应头的类型;例如:

# return HttpResponse(json.dumps(response))  #  转成json格式发送到前端
# 返回的head头的'content_type'是html格式;
        
return JsonResponse(response)  # 用json格式发送到前端;JsonResponse源码中已经用到了json.dumps功能
# 返回的head头的'content_type'是jsonapplication/json格式;ajax会自动解析p

准备数据库表:记得迁移

class User(models.Model):
    name = models.CharField(max_length=16, verbose_name='用户名')
    password = models.CharField(max_length=16, verbose_name='密码')

   def __str__(self):
       return self.name

迁移后再继续写

urls.py

from django.conf.urls import url
from django.contrib import admin
from app01 import views

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^login/', views.login),
]

views.py

from django.shortcuts import render, HttpResponse, redirect
from django.http import JsonResponse

# Create your views here.
from app01 import models
import json


def login(request):
    if request.method == 'GET':  # 判断请求方式若是GET
        return render(request, 'login.html')
    elif request.is_ajax():  # 判断是不是ajax请求
        response = {'status': 100, 'msg': None}  # 定义一个响应的字典
        name = request.POST.get('username')  # 取出name字段
        password = request.POST.get('password')
        user = models.User.objects.filter(name=name, password=password).first()  # 拿提交来的用户+密码到数据表中进行查询
        if user:  # 查到了说明是有的。
            # 用户名和密码都对了
            # return redirect('')  出错,不可以用redirect重定向
            response['msg'] = "登录成功"
        else:
            response['status'] = 101
            response['msg'] = '用户名或密码错误'
        # return HttpResponse(json.dumps(response))  #  转成json格式发送到前端
        # 返回的head头的'content_type'是html格式;
        return JsonResponse(response)  # 用json格式发送到前端;JsonResponse源码中已经用到了json.dumps功能
        # 返回的head头的'content_type'是jsonapplication/json格式;ajax会自动解析

login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登录认证+跳转</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
</head>
<body>

<p> 用户名:<input type="text" id="id_name"></p>
<p> 密码:<input type="password" id="id_password"></p>
<button id="id_btn">提交</button>
<span class="error" style="color: red"></span>

</body>
<script>
    $('#id_btn').click(function () {
        $.ajax({
            url: '/login/',
            method: 'post',
            // username=bao&password=123
            data: {username: $('#id_name').val(), password: $('#id_password').val()},
            success: function (data) {
                //如果ajax拿到响应是json格式字符串自动转成对象;ajax认为是字符串则需手动转
                // res=JSON.parse(data)
                //console.log(data)
                //console.log(res)
                // data 现在是对象类型(因为用jsonresponse)

                if (data.status === 100) {
                    //登录成功,重定向到百度,前端重定向
                    location.href = 'http://www.baidu.com'
                    //location.href='/index/' //这是前端重定向,匹配自己的网页时用文件名即可,http会自己补上。

                } else {
                    //登录失败
                    //$('.error').html(data.msg).css({'color':'red'}) //.css设置颜色,span标签写过了这里就不写了
                    $('.error').html(data.msg) //取到spn标签的error向标签内写提示;
                }
            },
            error: function (data) {  # 请求出错会到这里来
                console.log(data)
            }
        })
    })

</script>

</html>

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

模板层第一节也提到过

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

三:Ajax文件上传

1.HTTP请求中,body体中存放文件内容,ajax的本质就是发送HTTP请求,所以 它可以上传文件

2.上传文件的方式有2种:① form表单,② ajax

固定模板

var formdata=new FormData() 
formdata.append('myfile',$("#id_file")[0].files[0])
// 还可以带数据
$.ajax({
    url:'/uploadfile/',
    method: 'post',
    //上传文件必须写这两句话
    processData:false,  # 预处理数据,
    contentType:false,  # 不指定编码,如果不写contentType,默认用urlencoded
    data:formdata,      # formdata内部指定了编码,并且自行处理数据
    success:function (data) {  
    console.log(data)
    }
})

基于ajax上传文件

aja_files.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.css">
    <script src="/static/js/jquery-3.5.1.min.js"></script>
</head>
<body>
<div class="container-fluid">
    <div class="row">
        <div class="col-md-6 col-lg-offset-3" style="margin-top: 100px;">
            <h2>通过ajax上传</h2><br>
            <input type="file" name="myfile" id="file1"><br>
            <button id="btn" class="btn btn-success">上传</button>
        </div>
    </div>
</div>
<script>
    $('#btn').click(function () {
        var formdata = new FormData()
        formdata.append('myfile', $('#file1')[0].files[0])
        $.ajax({
            url: '/upload/',
            method: 'post',
            processData: false,
            contentType: false,
            data: formdata,
            success: function (data) {
                alert(data)
            },
            error: function () {
                console.log('出错了')
            }
        })
    })
</script>
</body>
</html>

views.py

from django.shortcuts import render, HttpResponse

def ajax_files(request):
    return render(request, 'aja_files.html')
#1、简单的视图函数。
def upload(request):
    file = request.FILES.get('myfile')
    with open(file.name, 'wb') as f:
        for line in file:
            f.write(line)
    return HttpResponse('上传成功')
#2、 或者下面的视图函数也行
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, 'aja_files.html')

urls.py

from django.conf.urls import url
from django.contrib import admin
from app01 import views

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^ajax_file/', views.index),
    url(r'^upload/', views.upload),
    #url(r'^upload/', views.ajax_file),
]

基于form表单上传文件

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.css">
</head>
<body>
<div class="container-fluid">
    <div class="row">
        <div class="col-md-6" style="margin-top: 10px;">
            <h2>通过form表单上传文件</h2><br>
            <form action="/upload/" method="post" enctype="multipart/form-data"> 
                		{# 上传文件使用multipart/form-data编码类型 #}
                <input type="file" name="myfile"><br>
                <input type="submit" value="提交" class="btn btn-success">
            </form>
        </div>
    </div>
</div>
</body>
</html>

views.py

from django.shortcuts import render, HttpResponse

def index(request):
    return render(request, 'index.html')

def upload(request):
    file = request.FILES.get('myfile')
    with open(file.name, 'wb') as f:
        for line in file:
            f.write(line)
    return HttpResponse('上传成功')

# 改写
def file_upload(request):
    if request.method=='GET':
        return render(request,'file_upload.html')
    else:
        name=request.POST.get('name')
        myfile=request.FILES.get('myfile')
        print(type(myfile)) # 查看类型
        from django.core.files.uploadedfile import InMemoryUploadedFile
        with open(myfile.name,'wb') as f:
            for line in myfile:
                f.write(line)

        return HttpResponse('上传成功')

urls.py

from django.conf.urls import url
from django.contrib import admin
from app01 import views

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url('^index/', views.index),
    url('^upload/', views.upload),
]

form表单上传文件版本二:

file_upload.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>上传文件</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
    <link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>
<body>
<h1>form表单上传文件</h1>
<form action="" method="post" enctype="multipart/form-data"> {# 上传文件使用multipart/form-data编码类型 #}
    <p>用户名:<input type="text" name="name"></p>
    <p>文件:<input type="file" name="myfile"></p>
    <input type="submit" value="提交">
</form>
</body>
</html>

views.py

from django.shortcuts import render, HttpResponse, redirect
from django.http import JsonResponse

# Create your views here.
from app01 import models

def file_upload(request):
    if request.method == 'GET':
        return render(request, 'file_upload.html')
    else:
        name = request.POST.get('name')
        myfile = request.FILES.get('myfile')
        print(type(myfile))  # 查看类型
        from django.core.files.uploadedfile import InMemoryUploadedFile
        with open(myfile.name, 'wb') as f:
            for line in myfile:
                f.write(line)
        return HttpResponse('上传成功')

urls.py

from django.conf.urls import url
from django.contrib import admin
from app01 import views

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^file_upload/', views.file_upload),
]

四:Ajax提交JSON格式

固定格式 - 简

$.ajax({
    url:'/uploadjson/', 
    method:'post',
    contentType: 'application/json',
    data:JSON.stringify({name:$("#id_name1").val(),password:$("#id_password1").val()}),
    success: function (data) {
        // 成功,会触发这个
    },
    error: function () {
        // 失败,会触发这个
    }
})

固定格式 - 繁

$.ajax({
    url:'/uploadjson/',  //写全,是什么样就写什么样
    method:'post',
    contentType: 'application/json',
    //data要是json格式字符串
    //data:'{"name":"","password":""}',
    //把字典转成json格式字符串
    //JSON.stringify(dic)
    //把json格式字符串转成对象
    //JSON.parse(data)
    data:JSON.stringify({name:$("#id_name1").val(),password:$("#id_password1").val()}),
    success:function (data) {
        //返回字符串类型,需要转成js的对象,字典
        //1 如果:django 返回的是HttpResponse,data是json格式字符串,需要自行转成字典
        //2 如果:django 返回的是JsonResponse,data是就是字典
        //ajax这个方法做的是,如果响应数据是json格式,自动反序列化
        console.log(typeof data)
        var res=JSON.parse(data)
        console.log(typeof res)
        console.log(res.status)
        console.log(res.msg)
    }
})

后端返回数据

  • HttpResponse:没有指定响应编码,默认使用text/html
  • JsonResponse:指定关联相应编码:application/json
  • ajax方法:会进行判断,如果相应编码是application/json,就自动调用JSON.parser(),如果不是json格式的数据,就不会处理

js中的json序列化和反序列化:

  • 序列化:JSON.stringfy(data)
  • 反序列化:JSON.parser()

五:Django内置序列化器

1.在django中,把JS对象(字典)转成JSON格式,json.dumps实现不了,

2.但是,Django内置了一个东西,可以把对象转换成JSON格式,这个东西,就是:序列化器

伪代码

from bms_book.models import Book

from django.core import serializers

book_list = Book.objects.all()
res = serializers.serialize("json", book_list)
print(res)

内部原理

ll=[]
for book in book_list:
    ll.append({'name':book.name,'price':book.price, 'date':book.publish_date, 'publisher': book.publisher, 'authors': book.authors})  
import json
res=json.dumps(ll)

实例

import os

if __name__ == '__main__':
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "BookManagementSystem_v1.settings")
    
    import django
    
    django.setup()
    
    from bms_book.models import Book

    from django.core import serializers

    book_list = Book.objects.all()
    res = serializers.serialize("json", book_list)
    print(res)

分页器

练习

1.登录校验

(使用ajax实现)用户在表单输入用户名与密码,通过Ajax提交给服务器,服务器验证后返回响应信息,客户端通过响应信息确定是否登录成功,成功,则跳转到首页,否则,在页面上显示相应的错误信息

login.html

<div class="input-group">
    <span class="input-group-addon">
        <i class="fa fa-user" aria-hidden="true"></i>
    </span>
    <input type="text" class="form-control" id="usr" name="username" placeholder="请输入用户名" required>
</div>
<div class="input-group">
    <span class="input-group-addon">
        <i class="fa fa-unlock-alt" aria-hidden="true"></i>
    </span>
    <input type="password" class="form-control" id="pwd" name="password" placeholder="请输入密码" required>
</div>
<div class="form-group">
    <button type="submit" class="btn btn-success btn-block" id="btn-login">登录</button>
</div>

views.py

def login(request):
    if request.method == "POST":
        username = request.POST.get('username')
        password = request.POST.get('password')
        if not username:
            return JsonResponse({'code': 3, 'info': '请填写用户名!'})
        elif not password:
            return JsonResponse({'code': 3, 'info': '请填写密码!'})
        try:
            user = models.UserInfo.objects.get(username=username)
            if user:
                if user.password == password:
                    request.session["login_user"] = username
                    return JsonResponse({'code': 1, 'info': '登录成功!'})
                else:
                    return JsonResponse({'code': 2, 'info': '密码错误!'})
            else:
                return JsonResponse({'code': 4, 'info': '该账号不存在!'})
        except:
            return JsonResponse({'code': 4, 'info': '该账号不存在!'})
    return render(request, "general/Login.html")

2.文件上传的2种方式

使用ajax和form表单两种方式上传文件,保存到项目跟路径下的media文件加

〇 media文件夹添加设置

  • settings.py中添加
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, "media").replace("\\", "/")
  • 在项目根目录下创建media文件夹,再创建二级文件夹`upload_files,用于存放上传的文件

① form表单上传文件

upload.html
<form action="{% url 'upload' %}" method="post" enctype="multipart/form-data">
    <input type="file" name="my_file"><br>
    <button type="submit" class="btn btn-success">上传</button>
</form>
views.py
def upload(request):
    import os
    if request.method == 'POST':
        file = request.FILES.get('my_file')
        if file:
            from BookManagementSystem_v1 import settings
            path = os.path.join(settings.MEDIA_ROOT, "upload_files", file.name)
            with open(path, 'wb') as f:
                for line in file.chunks():
                    f.write(line)
            return HttpResponse('文件上传成功!')

        else:
            return HttpResponse('请选择文件')
    return render(request, 'general/Upload.html')

② ajax上传文件

upload.html
<div class="col-md-3">
    <div class="panel panel-default">
        <div class="panel-heading">
            <ol class="breadcrumb margin-bottom-0">
                当前位置:
                <li class="active">文件上传</li>
            </ol>
        </div>
        <div class="panel-body max-height-800">
            <div class="col-md-4">
                <br>
                <input type="file" id="my_file"><br>
                <button type="submit" class="btn btn-success" id="btn-upload">上传</button>
                <br>
            </div>
        </div>
    </div>
</div>
<div class="col-md-2">
    <div class="alert alert-success alert-dismissible" role="alert" id="my-info"
         style="display: none">
        <button type="button" class="close" data-dismiss="alert" aria-label="Close">
            <span aria-hidden="true">&times;</span>
        </button>
        <strong></strong>
    </div>
</div>


<script>
    $('#btn-upload').click(function () {
        var formData = new FormData()
        formData.append('my_file', $("#my_file")[0].files[0])
        $.ajax({
            url: '{% url 'upload_backend' %}',
            method: 'post',
            processData: false,
            contentType: false,
            data: formData,
            success: function (data) {
            if (data.code == 1) {
                $('#my-info').css('display', 'block')
                $('#my-info').removeClass('alert-danger').addClass('alert-success')
                $('#my-info strong').text(data.info)
            } else {
                $('#my-info').css('display', 'block')
                $('#my-info').removeClass('alert-success').addClass('alert-danger')
                $('#my-info strong').text(data.info)
            }
        },
            error: function () {
                $('#my-info').css('display', 'block')
                $('#my-info').removeClass('alert-success').addClass('alert-danger')
                $('#my-info strong').text('系统出错了!')
            }
    })
    })
</script>
views.py
def upload(request):
    return render(request, 'general/Upload.html')


def upload_backend(request):
    import os
    file = request.FILES.get('my_file')
    print(file)
    print(type(file))
    if file:
        from BookManagementSystem_v1 import settings
        path = os.path.join(settings.MEDIA_ROOT, "upload_img", file.name)
        with open(path, 'wb') as f:
            for line in file.chunks():
                f.write(line)
        print('文件上传成功!')
        return JsonResponse({'code': 1, 'info': '文件上传成功!'})
    else:
        print('请选择文件!')
        return JsonResponse({'code': 2, 'info': '请选择文件!'})

3.使用ajax提交json格式数据

前端用ajax获取标签内数据,并转换成json格式的字符串对象,提交到后端后,对象转换成json格式,返回给前端

upload_json.html
<div class="col-md-3">
    <div class="panel panel-default">
        <div class="panel-heading">
            <ol class="breadcrumb margin-bottom-0">
                当前位置:
                <li class="active">JSON上传数据</li>
            </ol>
        </div>
        <div class="panel-body max-height-800">
            <div class="col-md-10 col-md-offset-1">
                <br>
                <input type="text" id="usr" class="form-control" placeholder="请输入昵称"><br>
                <input type="text" id="msg" class="form-control" placeholder="请输入留言内容"><br>
                <button class="btn btn-success btn-block" id="btn-upload">上传</button>
                <br>
            </div>
        </div>
    </div>
</div>
<div class="col-md-2">
    <div class="alert alert-success alert-dismissible" role="alert" id="my-info"
         style="display: none">
        <button type="button" class="close" data-dismiss="alert" aria-label="Close">
            <span aria-hidden="true">&times;</span>
        </button>
        <strong></strong>
        <p></p>
    </div>
</div>

<script>
    $('#btn-upload').click(function () {
        $.ajax({
            url: '{% url 'upload_json_backend' %}',
            method: 'post',
            contentType: 'application/json',
            data: JSON.stringify({name: $("#usr").val(), message: $("#msg").val()}),
        success: function (data) {
            $('#my-info').css('display', 'block')
            $('#my-info').removeClass('alert-danger').addClass('alert-success')
            $('#my-info strong').text(data.msg)
            $('#my-info p').text(data.info)
        },
            error: function () {
                $('#my-info').css('display', 'block')
                $('#my-info').removeClass('alert-success').addClass('alert-danger')
                $('#my-info strong').text('系统出错了!')
            }
    })
    })
</script>
views.py
import json

def upload_json_backend(request):
    data = request.body
    data1 = json.loads(data.decode('utf-8'))
    ret = f'用户:{data1["name"]}  发表了留言:{data1["message"]}'
    dic = {'msg': '成功', 'info': ret}
    return JsonResponse(dic)

4.实现简单的注册功能

实现简单的注册功能,当光标移除用户名的输入框,去后端校验,如果用户名存在,提示错误,并且把输入框中的文字清除

5.django处理XSS攻击的底层原理

把标签中的特殊字符进行替换

总结1:

1 ajax发送其他请求

1 大坑
	-如果在form表单中,写button和input是submit类型,会触发form表单的提交
    -如果不想触发:
    	-不写在form表单中
        -使用input,类型是button
        
2 坑
	-后端响应格式如果是:html/text格式,ajax接收到数据后需要自己转成对象
    -后端响应格式是:json,ajax接收到数据后会自动转成对象
    -总结:后端返回数据,统一都用JsonResponse、
    
3 坑
	-如果使用了ajax,后端就不要返回rediret,render,HttpResponse
    -直接返回JsonResponse

1.1 登录功能前端

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
</head>
<body>


    <p> 用户名:<input type="text" id="id_name"></p>
    <p> 密码:<input type="password" id="id_password"></p>
    <button id="id_btn">提交</button> <span class="error" style="color: red"></span>



</body>
<script>

    $('#id_btn').click(function () {
        $.ajax({
            url: '/login/',
            method: 'post',
            data: {username: $('#id_name').val(), password: $('#id_password').val()},
            success: function (data) {
                //res=JSON.parse(data)
                //console.log(data)
                //console.log(res)
                // data 现在是对象类型

                if(data.status==100){
                    //登录成功,重定向到百度,前端重定向
                    location.href='http://www.baidu.com'
                    //location.href='/index/'

                }else {
                    //登录失败
                    //$('.error').html(data.msg).css({'color':'red'})
                    $('.error').html(data.msg)
                }
            },
            error: function (data) {
                console.log(data)
            }
        })

    })



</script>

</html>

1.2 登录功能后端

from django.shortcuts import render,redirect,HttpResponse
from django.http import JsonResponse

# Create your views here.

from app01 import models
import json
def login(request):
    if request.method=='GET':
        return render(request,'login.html')
    # elif request.method=='POST':
    elif request.is_ajax():
        response={'status':100,'msg':None}
        name=request.POST.get('username')
        password=request.POST.get('password')
        user=models.User.objects.filter(name=name,password=password).first()
        if user:
            # 用户名和密码都对了
            # return redirect('')  出错
            response['msg']="登录成功"

        else:
            response['status']=101
            response['msg'] = "用户名或密码错误"
        # return  HttpResponse(json.dumps(response))
        return  JsonResponse(response)
        # return redirect('http://www.baidu.com')
        # return render(request,'login.html')

1.3 登录功能路由

url(r'^login/', views.login),

1.4 登录功能模型类

from django.db import models

# Create your models here.

class User(models.Model):
    name=models.CharField(max_length=32)
    password=models.CharField(max_length=32)

2 上传文件(ajax和form两种方式)

1 http --post--请求,有编码格式,主流有三种
	-urlencoded :默认的----》从request.POST取提交的数据
    -form-data :上传文件的----》从request.POST取提交的数据,request.FILES中取文件
    -json      :ajax发送json格式数据-----》request.POST取不出数据了
    
2 使用ajax和form表单,默认都是urlencoded格式
3 如果上传文件:form表单指定格式,ajax要使用Formdata对象

4 如果编码方式是urlencoded格式,放到body体中数据格式如下
	username=lqz&password=123
    
5 如果是formdata编码格式,body体中是:两部分,数据和文件
	
6 如果是json格式,body体中的格式是:就是json格式字符串
	-注意:注意:注意:如果这种格式,request.POST取不到值了
	

2.1 form表单上传文件

<h1>form表单上传文件</h1>
<form action="" method="post" enctype="multipart/form-data">
    <p>用户名:<input type="text" name="name"></p>
    <p>文件:<input type="file" name="myfile"></p>
    <input type="submit" value="提交">

</form> 

2.2 ajax 上传文件

<h1>ajax上传文件</h1>
<p>用户名:<input type="text" id="id_name"></p>
<p>文件:<input type="file" id="id_myfile"></p>
<button id="id_btn">提交</button>


<script>

    $('#id_btn').click(function () {
        //如果要上传文件,需要借助于一个js的FormData对象

        var formdata = new FormData() //实例化得到一个FormData对象
        formdata.append('name', $('#id_name').val()) //追加了一个name对应填入的值
        //能追加文件
        var file = $('#id_myfile')[0].files[0]
        formdata.append('myfile', file)
        $.ajax({
            url: 'file_upload',
            method: 'post',
            //上传文件,一定要注意如下两行
            processData: false,  //不预处理数据,
            contentType: false,  //不指定编码格式,使用formdata对象的默认编码就是formdata格式
            data: formdata,
            success: function (data) {
                console.log(data)

            }
        })

    })
</script>

2.3 后端

def file_upload(request):
    if request.method=='GET':
        return render(request,'file_upload.html')
    else:
        name=request.POST.get('name')
        myfile=request.FILES.get('myfile')
        print(type(myfile)) # 查看类型
        from django.core.files.uploadedfile import InMemoryUploadedFile
        with open(myfile.name,'wb') as f:
            for line in myfile:
                f.write(line)

        return HttpResponse('上传成功')

2.4 路由

url(r'^file_upload/', views.file_upload),

3 ajax上传json格式

3.1 前端

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
</head>
<body>

<h1>ajax提交json格式</h1>


<p>用户名: <input type="text" id="id_name"></p>
<p>密码: <input type="password" id="id_password"></p>
<button id="id_button">提交</button>
</body>

<script>

    $('#id_button').click(function () {

        $.ajax({
            url: '/ajax_json/',
            method: 'post',
            contentType: 'application/json',  //指定编码格式
            data: JSON.stringify({name:$('#id_name').val(),password:$('#id_password').val()}), //json格式字符串
            success: function (data) {
                console.log(data)

            }
        })

    })
</script>
</html>

3.2 后端

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

    else:
        # json格式,从POST中取不出来

        name=request.POST.get('name')
        print(type(request.POST))
        # from  django.http.request import QueryDict
        print(name)
        # 在body体中,b格式

        request.data=json.loads(request.body)

        name=request.data.get('name')
        password=request.data.get('password')
        print(name)
        print(password)
        return HttpResponse('ok')

4 django内置序列化(了解)

把对象转成json格式字符串,django内置的不好用,字段不能控制

目前阶段,要做序列化,for循环拼列表套字典

4.1 后端

def test(request):
    user_list = models.User.objects.all()
    ret = serializers.serialize("json", user_list)

    return HttpResponse(ret)

4.2 路由

url(r'^test/', views.test),

5 分页器的使用

##############分页器
###批量插入数据

# def books_page(request):
#     # 第一种方案,每循环依次,操作一下数据库,性能低
#     # for i in range(1000):
#     #     book=models.Books.objects.create(name='图书%s'%i,price=i+10,publish='东京出版社')
#     #
#     # 第二种方案,批量插入
#     book_list=[]
#     for i in range(1000):
#         book=models.Books(name='图书%s'%i,price=i+10,publish='东京出版社')
#         book_list.append(book)
#
#     models.Books.objects.bulk_create(book_list,batch_size=100)
#
#
#     return HttpResponse('ok')


from django.core.paginator import Paginator
def books_page(request):
    book_list=models.Books.objects.all()
    paginator=Paginator(book_list,10)
    # Paginator对象的属性
    print(paginator.count) # 数据总条数
    print(paginator.num_pages) # 总页数
    print(paginator.per_page) # 每页显示条数
    print(paginator.page_range) # range(1, 101)
    print(paginator.page(1))
    # Page对象的属性和方法
    # has_next              是否有下一页
    # next_page_number      下一页页码
    # has_previous          是否有上一页
    # previous_page_number  上一页页码
    # object_list           分页之后的数据列表
    # number                当前页
    page=paginator.page(2)
    print(page.has_next())
    print(page.next_page_number())
    print(page.has_previous())
    print(page.previous_page_number())
    print(page.object_list)
    print(page.number)

    return render(request,'book_page.html',locals())

练习

1 使用ajax发送post请求,完成注册功能,注册成功,跳转到登陆,登陆成功跳转到百度

2 使用ajax上传文件,保存到项目路径的media路径下(登录成功才能上传文件)

3 使用ajax上传json格式数据,写一个装饰器,实现不论前端以什么格式传递数据,我从视图函数中都从request.data中取值(POST的数据)

补充

json.loads(b'dfdasfda')
问题:json可以直接loads    bytes格式吗?
	-3.5之前不可以
    -3.6以后可以
posted @ 2021-04-05 10:30  只有时间是永恒  阅读(68)  评论(0编辑  收藏  举报