JQuery之ajax异步请求Django后端

1. 创建项目 ajax

1.1. 命令行创建:

django-admin startproject mysite

1.2. pycharm创建:

File --> New project --> 左侧选Django --> 右侧填项目路径,并且勾选python.exe

2. 启动应用 app01

python manage.py startapp app01

3. 配置 settings.py

INSTALLED_APPS = [
    # 注册应用 app01
    'app01.apps.App01Config',
    # or
    'app01',
]

........

MIDDLEWARE = [
    ......
    # 处理 csrf
    # 'django.middleware.csrf.CsrfViewMiddleware',
    ......
]

........

TEMPLATES = [
    {
        ......
        # 检查模板路径配置
        'DIRS': [os.path.join(BASE_DIR, 'templates')]
        ......
    },
]

........

# 如需要连接数据库,通过下面的方法进行配置连数据库连接,本实例没有连接数据库
# Database
# https://docs.djangoproject.com/en/1.11/ref/settings/#databases

#DATABASES = {
#    'default': {
#        'ENGINE': 'django.db.backends.mysql',
#        'NAME': 'blog',
#        'USER': 'scm',
#        'PASSWORD': '123456',
#        'HOST': '192.168.27.100',
#        'PORT': '3306',
#    }
#}

........

# Internationalization
# https://docs.djangoproject.com/en/1.11/topics/i18n/

LANGUAGE_CODE = 'zh-Hans'#'en-us'

TIME_ZONE = 'Asia/Shanghai'#'UTC'

........

# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.11/howto/static-files/

STATIC_URL = '/static/'
# 配置静态文件的路径
STATICFILES_DIRS = [
    os.path.join(BASE_DIR, "static"),
]

........

# 配置控制台打印SQL语句,连接数据库的时候,用来查看具体执行的SQL语句是什么
#LOGGING = {
#    'version': 1,
#    'disable_existing_loggers': False,
#    'handlers': {
#        'console': {
#            'class': 'logging.StreamHandler',
#        },
#    },
#    'loggers': {
#        'django': {
#            'handlers': ['console'],
#            'level': 'DEBUG',
#        },
#    },
#}

4. 在项目根目录下创建目录 static, 将 jquery-min.js 拷贝到 static 下面。

5. 配置 ajax/__init__.py (需要连接数据库的时候才配置)

由于django-1.11 版本不支持mysqldb引擎,所以需要使用pymysql替代mysqldb引擎

import pymysql
pymysql.install_as_MySQLdb()

6. 配置 ajax/urls.py

from django.conf.urls import url, include

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

7. 配置 app01/urls.py

urlpatterns = [
    url(r'^test/$', views.test),
    url(r'^test_ajax/$', views.test_ajax),
]

8. app01/views.py 代码

from django.shortcuts import render, HttpResponse

# Create your views here.

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

def test_ajax(request):
    print(request)
    v1 = request.POST.get('v1')
    v2 = request.POST.get('v2')
    name = request.POST.get('name')
    age = request.POST.get('age')
    # v1 = request.GET.get('v1')
    # v2 = request.GET.get('v2')
    # name = request.GET.get('name')
    # age = request.GET.get('age')
    ret = int(v1) + int(v2)
    print(v1)
    print(v2)
    print(ret)
    print('-' * 30)
    print('{}:{}'.format(name, age))
    return HttpResponse(ret)

9. 在 templates 下创建 html 文件 test.html

9.1. 快捷方法$.post()

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

</head>
<body>

<input type="text" id="i1" placeholder="v1"> +
<input type="text" id="i2" placeholder="v2"> =
<input type="text" id="i3" placeholder="ret=v1+v2">
<!--<button id="submit">AJAX请求</button>-->
<input type="button" id="submit" value="AJAX请求">


<script src="/static/jquery-3.2.1.min.js"></script>
<script>
    $("#submit").on("click", function () {
    $.post("http://127.0.0.1:8888/app01/test_ajax/",
        {'v1': $('#i1').val(), 'v2': $('#i2').val(), 'name': 'lady', 'age': 23},
        function (retdata) {
            console.log(retdata);
            $('#i3').val(retdata);
        });
     });
</script>

</body>
</html>

9.2. 通用方法$.ajax()

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

</head>
<body>

<input type="text" id="i1" placeholder="v1"> +
<input type="text" id="i2" placeholder="v2"> =
<input type="text" id="i3" placeholder="ret=v1+v2">
<!--<button id="submit">AJAX请求</button>-->
<input type="button" id="submit" value="AJAX请求">


<script src="/static/jquery-3.2.1.min.js"></script>
<script>
    $("#submit").on("click", function () {
        $.ajax({
            url: "/app01/test_ajax/",
            type: 'POST',
            data: {'v1': $('#i1').val(), 'v2': $('#i2').val(), name: 'lady', age: 23},
            success: function (retdata) {
                console.log(retdata);
                $('#i3').val(retdata);
            }
        });
     });
</script>

</body>
</html>

10. $.post, $.get 和 $.ajax

10.1. 以上两种写法中,get方法和post方法都可以通过 data 提交数据,(只能为当前页提交数据,不能跨页面提交)

  • post 方法提交的时候数据是通过 Form Data 的方式提交的
  • get 方法提交的时候数据是通过 Query String 的方式提交的

10.2. $.post 和 $.get 方法只能在成功响应之后调用

    $.ajax({ 
        url: "test.html", 
        context: document.body, 
        success: function(){
            $(this).addClass("done");
        }
    });

10.3. $.ajax 可以在成功响应后调用也可以在响应失败后调用

    $.ajax({ 
        url: "test.html", 
        context: document.body, 
        error: function (XMLHttpRequest, textStatus, errorThrown) {
            // 通常 textStatus 和 errorThrown 之中只有一个会包含信息
            this; // 调用本次AJAX请求时传递的options参数
        }
    });

10.4. test.html文件中ajax请求的url可以是以下的两种方式:

10.5. test.html文件中的url必须要和Django中的路由urls.py中的url 一致;同时有后缀 '/' 或同时没有 "/", 否则回

urlpatterns = [
    url(r'^test/$', views.test),
    url(r'^test_ajax/$', views.test_ajax),  # 如果test.html中ajax请求的url有后缀 "/",那么这里一定也要有 '/' 后缀。
]

11. 启动server

python manage.py runserver

12. ajax 实现跳转

  • app01/urls.py
from app01 import views

urlpatterns = [
    url(r'^test/$', views.test),
    url(r'^test_ajax/$', views.test_ajax),
    url(r'^baidu_ajax/$', views.baidu_ajax),
]
  • app01/views.py 代码
def baidu_ajax(request):
    return HttpResponse('http://www.baidu.com')
  • static/test.html 代码
<input type="button" id="hop1" value="AJAX跳转到百度">

<script src="/static/jquery-3.2.1.min.js"></script>
<script>
    $('#hop1').on('click', function () {
        $.get('/app01/baidu_ajax/', function (retdata) {
            location.href = retdata
        })
    })
</script>

13. AJAX请求如何设置csrf_token

13.1. 问题

Django中启用了csrf之后,如果没有配置csrf_token,在post提交数据的时候会有下面的问题:

Forbidden (CSRF cookie not set.): /app01/csrf_ajax/
"POST /app01/csrf_ajax/ HTTP/1.1" 403 2829

13.2. 解决方法1:通过JQuery获取隐藏input标签中的csrftoken值

html代码

<body>
{% csrf_token %}  <!--在这里加入csrf_token-->

<input type="text" id="i1" placeholder="v1"> +
<input type="text" id="i2" placeholder="v2"> =
<input type="text" id="i3" placeholder="ret=v1+v2">
<input type="button" id="hop2" value="AJAX_CSRF">

<script src="/static/jquery-3.2.1.min.js"></script>
<script>
    var csrfToke = $('[name="csrfmiddlewaretoken"]').val(); // 在这里获取csrf_token值
    $('#hop2').on('click', function () {
        $.post('http://127.0.0.1:8888/app01/csrf_ajax/',
            {'v1': $('#i1').val(), 'v2': $('#i2').val(), 'name': 'yuan', 'age': 23, 'csrfmiddlewaretoken': csrfToke},  // 在这里将csrf_token传递到服务端供验证
            function (retdata) {
                console.log(csrfToke);
                $('#i3').val(retdata)
        })
    });
</script>
</body>

提示:
如果使用form表单的形式提交,需要将 {% csrf_token %} 放在 form 表单中
{% csrf_token %} 会自动生成一个隐藏的input标签

<input type="hidden" name="csrfmiddlewaretoken" value="RqzdrlFnOVrVxCE848UX0NJdmV2UGrQ2aCkvzZaapNw46dwriEP62jl4cPOUGdFa">

13.3. 解决方法2:通过插件jquery.cookie.js获取cookie中的csrftoken值

在请求的HEADER中增加一个"X-CSRFToken", 其值来自 cookie中获取的csrftoken值。

下载jquery.cookie.js(是一个插件)到/static/
文件内容下载地址:https://github.com/carhartl/jquery-cookie

html代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
{% csrf_token %}   <!--一定要有这个-->
<input type="text" id="i1" placeholder="v1"> +
<input type="text" id="i2" placeholder="v2"> =
<input type="text" id="i3" placeholder="ret=v1+v2">
<input type="button" id="hop2" value="AJAX_CSRF">

<script src="/static/jquery-3.2.1.min.js"></script>
<script src="/static/jquery.cookie.js"></script>
<script>
    $('#hop2').on('click', function () {
        $.ajax({
            url: 'http://127.0.0.1:8888/app01/csrf_ajax/',
            type: 'POST',
            headers: {"X-CSRFToken": $.cookie('csrftoken')},  // 从Cookie取csrftoken,并设置到请求头中
            data: {'v1': $('#i1').val(), 'v2': $('#i2').val(), 'name': 'yuan', 'age': 23},
            success: function (retdata) {
                $('#i3').val(retdata)
            }
        });
    });
</script>

</body>
</html>

13.4. 解决方法3:自己定义getCookie方法获取csrftoken值

13.4.1. 创建一个js文件 ajax_scrf.js

function getCookie(name) {
    var cookieValue = null;
    if (document.cookie && document.cookie !== '') {
        var cookies = document.cookie.split(';');
        for (var i = 0; i < cookies.length; i++) {
            var cookie = jQuery.trim(cookies[i]);
            // Does this cookie string begin with the name we want?
            if (cookie.substring(0, name.length + 1) === (name + '=')) {
                cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                break;
            }
        }
    }
    return cookieValue;
}

var csrftoken = getCookie('csrftoken');

function csrfSafeMethod(method) {
    // these HTTP methods do not require CSRF protection
    return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}

// 每一次都这么写太麻烦了,可以使用$.ajaxSetup()方法为ajax请求统一设置。
$.ajaxSetup({
    beforeSend: function (xhr, settings) {
        if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
            xhr.setRequestHeader("X-CSRFToken", csrftoken);
        }
    }
});

注意:
如果使用从cookie中取csrftoken的方式,需要确保cookie存在csrftoken值。
如果你的视图渲染的HTML文件中没有包含 {% csrf_token %},Django可能不会设置CSRFtoken的cookie。
这个时候需要使用ensure_csrf_cookie()装饰器强制设置Cookie。

django.views.decorators.csrf import ensure_csrf_cookie
@ensure_csrf_cookie
def login(request):
    pass

更多细节详见:Djagno官方文档中关于CSRF的内容

13.4.2. html代码中引用上面的js文件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    {#    <meta http-equiv="X-UA-Compatible" content="IE=edge">#}
    {#    <meta name="viewport" content="width=device-width, initial-scale=1">#}
    <!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
    <title>Title</title>

</head>
<body>
{% csrf_token %}  <!--这里一定要有,否则九无法通过csrf_token进行验证了-->
<input type="text" id="i1" placeholder="v1"> +
<input type="text" id="i2" placeholder="v2"> =
<input type="text" id="i3" placeholder="ret=v1+v2">
<input type="button" id="hop2" value="AJAX_CSRF">

<script src="/static/jquery-3.2.1.min.js"></script>
<script src="/static/ajax_scrf.js"></script>  <!--这里引用以下自定义的js文件-->

<script>
    $('#hop2').on('click', function () {
        $.ajax({
            url: 'http://127.0.0.1:8888/app01/csrf_ajax/',
            type: 'POST',
            data: {'v1': $('#i1').val(), 'v2': $('#i2').val(), 'name': 'yuan', 'age': 23},
            success: function (retdata) {
                $('#i3').val(retdata)
            }
        });
    });
</script>
</body>
</html>

上面的js脚本也可以使用快捷方法

<script>
    $('#hop2').on('click', function () {
        $.post(
            'http://127.0.0.1:8888/app01/csrf_ajax/',
            {'v1': $('#i1').val(), 'v2': $('#i2').val(), 'name': 'yuan', 'age': 23},
            function (retdata) {
                $('#i3').val(retdata)
            }

        )
    })
</script>

14. AJAX上传文件

XMLHttpRequest 是一个浏览器接口,通过它,我们可以使得 Javascript 进行 HTTP(S) 通信。XMLHttpRequest 在现在浏览器中是一种常用的前后台交互数据的方式。2008年 2 月,XMLHttpRequest Level 2 草案提出来了,相对于上一代,它有一些新的特性,其中 FormData 就是 XMLHttpRequest Level 2 新增的一个对象,利用它来提交表单、模拟表单提交,当然最大的优势就是可以上传二进制文件。

首先看一下formData的基本用法:FormData对象,可以把所有表单元素的name与value组成一个queryString,提交到后台。只需要把 form 表单作为参数传入 FormData 构造函数即可

14.1. 利用 FormData 来上传文件示例

本示例中 csrf_token 的实现可参考上面的示例

ajax/settings.py

from app01 import views

urlpatterns = [
    url(r'^ajax_upload/$', views.ajax_upload),
]

app01/views.py

def ajax_upload(request):
    filename = request.FILES['file_name'].name
    if request.FILES:
        with open(filename, 'wb') as f:
            for chunk in request.FILES['file_name'].chunks():
                f.write(chunk)
    return HttpResponse('upload successful')

templates/test.html

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

<div id="uploadForm">
    <input id="file_input" type="file"/>
    <button id="file_upload" type="button">AJAX_UPLOAD</button>
</div>

<script src="/static/jquery-3.2.1.min.js"></script>
<script src="/static/ajax_scrf.js"></script>

<script>
    $("#file_upload").click(function () {
        var formData = new FormData();
        formData.append("csrfmiddlewaretoken", $("[name='csrfmiddlewaretoken']").val());
        formData.append('file_name', $('#file_input')[0].files[0]);
        $.ajax({
            url: 'http://127.0.0.1:8888/app01/ajax_upload/',
            type: 'POST',
            cache: false,
            data: formData,
            processData: false,
            contentType: false,
            success: function (ret) {
                console.log(ret)
            }
        });
    });
</script>

</body>
</html>

或者使用下面的写法,这样也可以直接通过ajax的send()方法将formData发送到后台。

<script>
    $("#file_upload").click(function () {
        var form = document.getElementById("uploadForm");
        var formData = new FormData(form);
        formData.append("csrfmiddlewaretoken", $("[name='csrfmiddlewaretoken']").val());
        formData.append('file_name', $('#file_input')[0].files[0]);
        $.ajax({
            url: 'http://127.0.0.1:8888/app01/ajax_upload/',
            type: 'POST',
            cache: false,
            data: formData,
            processData: false,
            contentType: false,
            success: function (ret) {
                console.log(ret)
            }
        });
    });
</script>

注意:由于 FormData 是 XMLHttpRequest Level 2 新增的接口,现在 低于IE10 的IE浏览器不支持 FormData。

posted @ 2018-05-11 22:27  scm1911  阅读(1287)  评论(0编辑  收藏  举报
/** ####################################################################### */