Django 系列博客(十四)

Django 系列博客(十四)

前言

本篇博客介紹在 html 中使用 ajax 與後臺進行數據交互。css

什麼是 ajax

ajax(Asynchronous Javascript And XML)翻譯成中文就是‘’異步 JavaScript 和 XML‘’。即便用 JavaScript 語言與服務器進行異步交互,傳輸的數據爲 XML(如今更多地使用 json)。html

  • 同步交互:客戶端發出一個請求後,須要等待服務器響應結束,才能發出第二個請求;
  • 異步交互:客戶端發出一個請求後,無需等待服務器響應結束,也能發出第二個請求。

ajax 除了異步的特色外,還有一個就是:瀏覽器頁面局部刷新。在頁面沒有進行刷新的狀況下進行數據交互。前端

優勢:python

  • ajax 使用JavaScript 技術向服務器發送異步請求;
  • ajax 無需刷新整個頁面。

基於 jQuery 的 ajax 實現

前端代碼

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <script src="/static/jquery-3.3.1.js"></script>

    <title>regist</title>
{#    <link rel="stylesheet" href="/static/jquery-3.3.1.js">#}
</head>
<body>
<p>用戶:<input type="text" id="name"></p>
<p>密碼:<input type="password" id="pwd"></p>
<p>確認密碼:<input type="password" id="tpwd"></p>
<input type="button" id="submit" value="提交"><span id="error"></span>
</body>

<script>

    $('#submit').click(function () {
        console.log($('#submit'));
        {#$.ajax({#}
        {#    url:'/regist/',#}
        {#    type:'post',#}
        {#    data:{name:$("#name").val(), pwd:$("#pwd").val(), tpwd:$("#tpwd")},#}
        {#    success:function (data) {#}
        {#        console.log(data)#}
        {#    }#}
        $.ajax({
            url:'/regist/',
            type:'post',
            data:{name:$("#name").val(), pwd:$("#pwd").val(), tpwd:$("#tpwd").val()},
            success:function (data) {
                console.log(data)
            }
        })

    })
</script>
</html>

後端代碼

from django.http import JsonResponse
from django.shortcuts import render, redirect
from app01.models import *

# Create your views here.


def wrapper(func):
    def inner(*args, **kwargs):
        if args[0].method == 'GET':
            return func(*args, **kwargs)
        elif kwargs['contentType'] == 'application/json':
            import json
            args[0].POST = json.loads(args[0].body)
            return func(*args, **kwargs)
        else:
            return func(*args, **kwargs)
    return inner

import json
# json.loads()


def regist(request):
    dic = {'status': 200, 'msg': None}
    print(request.body)
    if request.method == 'GET':
        return render(request, 'regist.html')
    else:
        print('/////')
        print(request.POST, 'dddd')
        name = request.POST.get('name')
        pwd = request.POST.get('pwd')
        tpwd = request.POST.get('tpwd')

        user = UserInfo.objects.filter(name=name).first()
        if user:
            dic['status'] = 100
            dic['msg'] = '用戶已存在'
            return JsonResponse(dic)
        else:
            if name and pwd and tpwd:
                if pwd == tpwd:
                    UserInfo.objects.create(name=name, pwd=pwd)
                    dic['msg'] = '註冊成功'
                    return JsonResponse(dic)
                else:
                    dic['status'] = 101
                    dic['msg'] = '兩次密碼不同'
                    return JsonResponse(dic)
            else:
                dic['status'] = 101
                dic['msg'] = '密碼不正確'
                return JsonResponse(dic)


@wrapper
def login(request):
    dic = {'status': 200, 'msg': None}
    if request.method == 'GET':
        return render(request, 'login.html')
    else:
        name = request.POST.get('name')
        pwd = request.POST.get('pwd')

        user = UserInfo.objects.filter(name=name).first()
        if not user:
            dic['status'] = 100
            dic['msg'] = '用戶不存在,請註冊'
            return JsonResponse(dic)
        else:
            if pwd == user.pwd:
                dic['msg'] = '登錄成功'
                return JsonResponse(dic)
            else:
                dic['status'] = 101
                dic['msg'] = '密碼錯誤'
                return JsonResponse(dic)

js代碼

$("#submit3").click(function () {
            $.ajax({
                url: '/auth/',
                type: 'post',
                data: {
                    'user': $("#id_name").val(),
                    'password': $('#id_password').val()
                },

                success: function (data) {
                    {#console.log(data)#}
                    var data=JSON.parse(data)
                    if (data.user){
                        location.href='https://www.baidu.com'
                    }else {
                        $(".error").html(data.message).css({'color':'red','margin-left':'20px'})
                    }
                }


            })
        }
    )

文件上傳

請求頭

  1. application/x-www-form-urlencoded

這是最多見的 POST 提交數據的方式了。瀏覽器的原生<form>表單,若是不設置 enctype 屬性,那麼最終會以 application/x-www-form-urlencoded方式提交數據。相似於下面:jquery

POST http://www.example.com HTTP/1.1
Content-Type: application/x-www-form-urlencoded;charset=utf-8

請求體
  1. multipart/form-data

當咱們使用表單上傳文件時,必須讓<form>表單的 enctype 等於multipart/form-data。web

POST http://www.example.com HTTP/1.1
Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryrGKCBY7qhFd3TrwA

------WebKitFormBoundaryrGKCBY7qhFd3TrwA
Content-Disposition: form-data; name="user"

yuan
------WebKitFormBoundaryrGKCBY7qhFd3TrwA
Content-Disposition: form-data; name="file"; filename="chrome.png"
Content-Type: image/png

PNG ... content of chrome.png ...
------WebKitFormBoundaryrGKCBY7qhFd3TrwA--

這個例子稍微複雜點。首先生成了一個 boundary 用於分割不一樣的字段,爲了不與正文內容重複,boundary 很長很複雜。而後 Content-Type 裏指明瞭數據是以 multipart/form-data 來編碼,本次請求的 boundary 是什麼內容。消息主體裏按照字段個數又分爲多個結構相似的部分,每部分都是以--boundary 開始,緊接着是內容描述信息,而後回車,最後是字段具體內容(文本或二進制)。若是傳輸的是文件,還要包含文件名和文件類型信息。消息主體最後以--boundary--表示結束。ajax

這種方式通常用於上傳文件,各大服務端語言也有很好的支持。chrome

這兩種POST 提交的方式,都是瀏覽器原生支持的,並且先階段標準中原生<form>表單也只支持這兩種方式(經過<form>元素的 enctype 屬性指定,默認爲 application/x-www-form-urlencoded)。隨着愈來愈多的web站點尤爲是 WebApp,所有使用 Ajax 進行數據交互以後,咱們徹底能夠定義新的數據提交方式,給開發帶來更多便利。django

  1. application/json

application/json是另一種請求頭,不過更多的是做爲響應頭,由於 json 格式的數據時通用數據格式。不過目前也用來做爲請求頭,用來告訴服務器端主體是序列化後的 json 字符串。因爲 json 規範的流行,除了低版本的 IE 以外的各大瀏覽器都原生支持 json.stringfy,服務器端語言也都有處理 json數據的函數,使用 json 不會遇到什麼麻煩。json

json 格式支持比鍵值對複雜的多的結構化數據,這點對數據傳輸頗有用。

基於form表單上傳文件

前端代碼

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<form action="" method="post" enctype="multipart/form-data">
    <p>用戶名:<input type="text" name="name"></p>
    <input type="file" name="myfile">
{#    <input type="file" name="myfile2">#}
    <input type="submit" value="提交">

</form>

</body>
</html>

後端代碼

class UploadFile(View):

    def get(self, request):
        return render(request, 'upload_file.html')

    def post(self, request):
        file = request.FILES.get('myfile')
        # print(file['file'])
        from django.core.files.uploadedfile import InMemoryUploadedFile
        print(time.time())
        filename = str(time.time()).split('.')[0] + file.name
        with open(filename, 'wb') as f:
            for line in file:
                f.write(line)
        return HttpResponse('上傳成功')

基於ajax 的文件上傳

前端代碼

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>uploadfile</title>
    <script src="/static/jquery-3.3.1.js"></script>
</head>
<body>
<p>用戶名:<input type="text" id="name"></p>
<p>選擇文件:<input type="file" id="my_file"></p>
<button id="btn">上傳</button><span id="msg"></span>
</body>

<script>
    $('#btn').click(function () {
        var myfile = $('#my_file')[0].files[0];
        var formdata = new FormData();
        formdata.append('name', $('#name').val());
        formdata.append('myfile', myfile);
        $.ajax({
            url:'/uploadfile/',
            type:'post',
            processData:false, // 告訴 jQuery 不要處理髮送的數據
            contentType:false, // 告訴 jQuery 不要設置 Content-Type 請求頭
            data:formdata,
            success:function (data) {
                console.log(data);
                $('#msg').text(data)
            }
        })
    })

</script>
</html>

後端代碼

MEDIA_PATH = '/Users/jingxing/Django/homework/paging/media'

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

        myfile = request.FILES.get('myfile')
        print(myfile)
        filepath = os.path.join(MEDIA_PATH, myfile.name[32:-3]+'jpg')
        with open(filepath, 'wb') as f:
            for line in myfile:
                f.write(line)
        FileInfo.objects.create(name=request.POST.get('name'), filepath=filepath)
        return HttpResponse('上傳成功')

ajax 提交 json 格式數據

前端代碼

$('#submit1').click(function () {
        postdata={name1:$("#name").val(),pwd2:$("#pwd").val()}
        $.ajax({
            url:'/loginjson/',
            type:'post',
            // 指定提交的編碼格式是json格式,
            contentType:'application/json',
            data:JSON.stringify(postdata),
            // data:postdata,
            // data:'123',
            success:function (data) {
                console.log(data)

            }
        })
    })

後端代碼

def loginjson(request):
    dic={'status':100,'msg':None}
    if request.method=='POST':
        print(request.POST)
        print(request.GET)
        print(request.body)
        xx=request.body.decode('utf-8')
        # re是個字典{"name1":"lqz","pwd2":"123"}
        re=json.loads(xx)
        request.POST=11


        print(request.POST)
        #
        #
        # name=re.get('name1')
        # pwd=re.get('pwd2')
        # print(name)
        # print(pwd)
        return HttpResponse('ok')

後端返回 json 數據

前端代碼

$('#submit').click(function () {
        $.ajax({
            url:'/login/',
            type:'post',
            data:{name1:$("#name").val(),pwd2:$("#pwd").val()},
            success:function (data) {
                //後臺用JsonResponse返回數據
                //data 就會被轉成字典
                console.log(data)
                console.log(typeof data)
                //JSON.parse(data) 把字符串類型轉成字典
                data=JSON.parse(data)
                {#JSON.stringify()#}
                console.log(typeof dat1)
                if(data.status == 100){
                    //成功,跳轉到指定頁面
                    //location.href=地址,前端就會跳轉到指定的url
                    alert(data.msg)
                    //$("#error").text(data.msg+'正在跳轉')
                    //location.href=data.url
                }else{
                    $("#error").text(data.msg)
                }


            }
        })
    })

後端代碼

def login(request):
    dic={'status':100,'msg':None}
    if request.method == 'GET':
        return render(request, 'login.html')
    # if request.is_ajax():
    if request.method=='POST':
        name=request.POST.get('name1')
        pwd=request.POST.get('pwd2')
        if name=='lqz' and pwd=='123':
            dic['msg'] = '登錄成功'
            # 想讓前端跳轉
            # dic['url']='http://www.baidu.com'
            dic['url']='/test/'
        else:
            # 返回json格式字符串
            dic['status']=101
            dic['msg']='用戶名或密碼錯誤'
        # return JsonResponse(dic)
        return HttpResponse(json.dumps(dic))

Django內置的序列化數據方法

from django.core import serializers

def test(request):
    book_list = Book.objects.all()
    ret = serializers.serialize('json', book_list)
    return HttpResponse(ret)