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可以是以下的两种方式:
- url: "http://127.0.0.1:8888/app01/test_ajax/"
- url: "/app01/test_ajax/"
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。