Ajax简介
什么是Ajax
AJAX(Asynchronous Javascript And XML)翻译成中文就是“异步Javascript和XML”。即使用Javascript语言与服务器进行异步交互,传输的数据为XML(当然,传输的数据不只是XML,现在更多使用json数据)。
- 同步交互:客户端发出一个请求后,需要等待服务器响应结束后,才能发出第二个请求;
- 异步交互:客户端发出一个请求后,无需等待服务器响应结束,就可以发出第二个请求。
AJAX除了异步的特点外,还有一个就是:浏览器页面局部刷新;(这一特点给用户的感受是在不知不觉中完成请求和响应过程)
## Ajax应用场景 登录注册时的校验,以百度为例 ![](https://img2018.cnblogs.com/blog/1542801/201903/1542801-20190326205349008-802468394.png) 当输入框失去焦点时,触发事件,浏览器发送Ajax请求,服务端进行校验,返回数据给浏览器,显示相应的错误信息 ![](https://img2018.cnblogs.com/blog/1542801/201903/1542801-20190326205534125-1716891331.png) 此过程中,整个页面是没有刷新的,同时请求发出后我们还可以进行其他操作,因此是异步的,这就体现了Ajax的两大特点: `异步请求`和 `局部刷新`
## Ajax流程 Ajax请求的流程如下 ![](https://img2018.cnblogs.com/blog/1542801/201903/1542801-20190326205950026-2135596492.png) 1. 客户端触发异步操作 2. 创建新的XMLHttpRequest对象,这是ajax的核心 3. 通过send()方法实现与server的连接 4. 服务器端接收请求,并处理 5. 返回处理的结果,这个结果可以是XML文档、也可以是josn字符串(一般情况下josn就可以处理大部分的结果、而且相对的比较好操作) 6. 在客户端去接收服务器传回来的结果,并且通过javascript进行你想要的处理
小结
Ajax特点
- 异步请求
- 局部刷新
实例
Ajax登录验证
准备工作
新建一个项目ajaxDemo,创建一个APP,命名为app1
新建一个数据库ajaxdemo,增加User表模型
models.py
from django.db import models
# Create your models here.
class User(models.Model):
username = models.CharField(max_length=32)
password = models.CharField(max_length=32)
配置urls
urls.py
from django.contrib import admin
from django.urls import path, re_path
from app1 import views
urlpatterns = [
path('admin/', admin.site.urls),
path('login/', views.login),
path('index/', views.index),
]
### 编写视图函数 views.py ```python from django.shortcuts import render, HttpResponse, redirect from app1 import models import json # Create your views here.
def login(request):
if request.method == "POST":
username = request.POST.get('username')
password = request.POST.get('password')
response = {"status": False, "username": None, 'msg': None}
user_obj = models.User.objects.filter(username=username, password=password).first()
if user_obj:
response['status'] = True
response['username'] = username
else:
response['msg'] = '用户名或密码错误'
# 注意发送之前要序列化
return HttpResponse(json.dumps(response, ensure_ascii=False))
else:
return render(request, 'login.html')
def index(request):
return render(request, 'index.html')
<br>
### 编写HTML页面
login.html
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>用户登录</title>
<script src="/static/plugins/js/jquery.js"></script>
</head>
<body>
<form action="">
{% csrf_token %}
<p>用户名:<input type="text" name="username"></p>
<p>密码:<input type="text" name="password"></p>
<input type="button" class='btn' value="登录">
<span class="error"></span>
</form>
<script>
$('.btn').on('click', function () {
$.ajax({
url: '/login/',
//注意这里的方式是type,不是method!!!
type: 'post',
data: {
username: $("[name='username']").val(),
password: $("[name='password']").val(),
csrfmiddlewaretoken: $("[name='csrfmiddlewaretoken']").val(),
},
//成功之后执行回调函数
success:function (data) {
//反序列化
console.log(data);
//console.log(typeof data);
data = JSON.parse(data);
if (data['status'] == true) {
//登录成功跳转到个人主页
window.location.href = '/index/';
} else {
//登录失败显示错误信息
$('.error').html(data['msg']).css('color','red');
}
}
})
})
</script>
</body>
</html>
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>个人主页</title>
</head>
<body>
<h3>欢迎来到个人主页</h3>
</body>
</html>
密码正确时
![](https://img2018.cnblogs.com/blog/1542801/201903/1542801-20190326214637742-925346363.gif)
密码错误时
![](https://img2018.cnblogs.com/blog/1542801/201903/1542801-20190326214647190-699313987.gif)
## 小结 ### Ajax语法 发送Ajax请求的语法为:`$.ajax({ })`,大括号里放Ajax请求的四要素
### Ajax请求四要素 - url: 发送请求的网址 - type:请求的类型,注意不是method - data: 要发送的数据,是一个javascript对象,可以带上csrfmiddlewaretoken键值对 - 响应状态(通常是success)及回调函数
### 需要注意的地方 - 前端页面发送Ajax请求时要带上csrfmiddlewaretoken,否则会返回403 - 视图函数里登录成功后不能直接跳转,应返回一个字典(记录状态)交给前端页面完成跳转 - 返回字典之前要序列化(json.dumps()) - 前端页面跳转使用`window.location.href = '/index/'`
ajax还有其他参数,可以设置,如下: ```html ```
响应错误时,会执行error中的代码。
当 AJAX 请求正在进行时,执行complete的代码。它可以做一个请求等待的效果!
## ajax文件上传 首先来看form表单上传文件 ### 上传文件
修改urls.py,增加路径file_upload
from django.contrib import admin
from django.urls import path, re_path
from app1 import views
urlpatterns = [
path('admin/', admin.site.urls),
path('login/', views.login),
path('index/', views.index),
path('file_put', views.file_upload),
]
修改views.py,增加视图函数file_upload
def file_upload(request):
if request.method == "POST":
print(request.POST)
return HttpResponse('ok')
return render(request, 'file_upload.html')
在templates里面增加页面file_put.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h3>form表单文件上传</h3>
<form action="" method="post" enctype="multipart/form-data">
{% csrf_token %}
<input type="text" name="user">
<input type="file" name="img"><br/><br/>
<input type="submit">
</form>
</body>
</html>
注意:enctype的类型不同,发送数据格式也会不同。
form表单enctype默认为application/x-www-form-urlencoded。它的数据格式为key1=value1&key1=value1形式。
它不能发送图片,那么需要指定为multipart/form-data才可以!
选中一个文件,提交
pycharm控制台打印的信息
<QueryDict: {'csrfmiddlewaretoken': ['MiMUVVMla9s9TJ6CVYV4JUiQ6FJFlvU7GBs7RiMEQOfcm2jlybLSEOZBLvZVuEIP'], 'user': ['']}>
可以看到request.POST里面并没有文件的信息,这是因为Django把文件单独封装到另一个属性里面了,这就是request.FILS
修改视图函数
def file_upload(request):
if request.method == "POST":
print(request.POST)
print(request.FILES)
return HttpResponse('ok')
return render(request, 'file_upload.html')
查看pycharm控制台打印的信息 ```python
这次得到了img信息,它的类型为MultiValueDict。描述了图片的文件名以及图片类型jpeg
<br>
### 存储文件
以上完成了从浏览器上传的部分,但是服务器接收之后还得对文件进行处理如存放等操作
修改file_upload视图函数
```python
def file_upload(request):
if request.method == "POST":
print(request.POST)
print(request.FILES) # 打印文件信息
file_obj = request.FILES.get('img')
print(file_obj)
print(type(file_obj)) # 打印file_obj对象属性
print(file_obj.name)
with open(file_obj.name, 'wb') as f:
for line in file_obj:
f.write(line) # 写入文件
return HttpResponse('ok')
return render(request, 'file_upload.html')
重新上传,查看控制台打印信息 ```python
左侧目录下出现了一张图片
因为没有指定路径,所以默认是项目根目录
### 指定路径存储
在项目根目录下新建statics文件夹,再在statics目录下新建imgs文件夹
修改file_upload视图函数
def file_upload(request):
if request.method == "POST":
print(request.POST)
print(request.FILES) # 打印文件信息
file_obj = request.FILES.get('img')
print(file_obj)
print(type(file_obj)) # 打印file_obj对象属性
print(file_obj.name)
with open('statics/imgs/' + file_obj.name, 'wb') as f:
for line in file_obj:
f.write(line) # 写入文件
return HttpResponse('ok')
return render(request, 'file_upload.html')
再次上传文件,就保存在了指定的目录
再来看Ajax上传文件
利用Ajax和FormData实现页面无刷新的文件上传效果,主要用到了jQuery的ajax()方法和XMLHttpRequest Level 2的FormData接口。
修改视图函数file_upload
def file_upload(request):
# form表单上传
# if request.method == "POST":
# print(request.POST)
# print(request.FILES) # 打印文件信息
#
# file_obj = request.FILES.get('img')
# print(file_obj)
# print(type(file_obj)) # 打印file_obj对象属性
# print(file_obj.name)
# # 图片读取出来是二进制形式
# with open('statics/imgs/' + file_obj.name, 'wb') as f:
# for line in file_obj:
# f.write(line) # 写入文件
#
# return HttpResponse('ok')
# return render(request, 'file_upload.html')
# Ajax上传文件
if request.method == "POST":
print(request.POST)
print(request.FILES) # 打印文件信息
file_obj = request.FILES.get('img') # 获取img对象
print(file_obj, type(file_obj))
print(file_obj.__dict__)
print(file_obj.name)
# 返回给ajax回调函数的数据
response = {"status": False}
with open('statics/imgs/' + file_obj.name, 'wb') as f:
for line in file_obj:
# write的返回值是写入的字符长度
ret = f.write(line)
# 判断写入的文件是否为空,不为空时才把status置为True
if ret:
response["status"] = True
return HttpResponse(json.dumps(response)) # 返回json数据
修改file_upload.html ```html
{#
form表单文件上传
#}{# 表单默认为application/x-www-form-urlencoded。它的数据格式为key1=value1&key1=value1形式。 #}
{##}
Ajax上传文件
{% csrf_token %}<br>
## 小结
### form表单上传文件要点
- 需在form表单设置enctype="multipart/form-data"然后用submit提交
- 视图函数里用request.FILES.get('file')获取文件对象
- 服务端接收到文件对象后对其逐行读取并写入新文件
### Ajax上传文件要点
- 使用FormData对象发送文件数据(把FormData对象设为data的值)
- FormData对象添加数据用`formdata.append(key,value)`的形式
- 需要加上`processData: false`和`contentType: false`来告诉jQuery不处理数据,不设置内容类型