1. Django
1.1 Ajax
1.1.1 Ajax简介
AJAX(Asynchronous Javascript And XML)翻译成中文就是“异步Javascript和XML”。即使用Javascript语言与服务器进行异步交互,传输的数据为XML(当然,传输的数据不只是XML,可以指定json),相对于Form表单而言的,提交时可以偷偷向后台发数据,页面不刷新;
2大特点:
- 和server端异步交互
- 偷偷向server端发送数据,页面
和form、a标签的区别:
ajax、form、a标签都可以基于HTML页面向server端发送request,
但本质区别是form、a标签一般向server索要的是页面,而ajax则是字符串数据。
Jquery和Ajax关系:
Jquery没有Ajax功能,它之所以可以调用Ajax向服务端提交数据,是因为Jquey封装了原生Ajax的代码
使用原生Ajax的优势:
使用Ajax直接使用JS的XMLHttp Request对象, 无需引入Jquery了。这样响应客户端携带信息量减少,可节省流量。
1.1.2 原生Ajax
Ajax主要就是使用 【XmlHttpRequest】对象来完成请求的操作,该对象在主流浏览器中均存在(除早起的IE),Ajax首次出现IE5.5中存在(ActiveX控件)。
XmlHttpRequest对象介绍
XmlHttpRequest对象的主要方法:
a. void open(String method,String url,Boolen async)
用于创建请求
参数:
method: 请求方式(字符串类型),如:POST、GET、DELETE...
url: 要请求的地址(字符串类型)
async: 是否异步(布尔类型)
b. void send(String body)
用于发送请求
参数:
body: 要发送的数据(字符串类型)
c. void setRequestHeader(String header,String value)
用于设置请求头
参数:
header: 请求头的key(字符串类型)
vlaue: 请求头的value(字符串类型)
d. String getAllResponseHeaders()
获取所有响应头
返回值:
响应头数据(字符串类型)
e. String getResponseHeader(String header)
获取响应头中指定header的值
参数:
header: 响应头的key(字符串类型)
返回值:
响应头中指定的header对应的值
f. void abort()
终止请求
XmlHttpRequest对象的主要属性:
a. Number readyState
状态值(整数)
详细:
0-未初始化,尚未调用open()方法;
1-启动,调用了open()方法,未调用send()方法;
2-发送,已经调用了send()方法,未接收到响应;
3-接收,已经接收到部分响应数据;
4-完成,已经接收到全部响应数据;
b. Function onreadystatechange
当readyState的值改变时自动触发执行其对应的函数(回调函数)
c. String responseText
服务器返回的数据(字符串类型)
d. XmlDocument responseXML
服务器返回的数据(Xml对象)
e. Number states
状态码(整数),如:200、404...
f. String statesText
状态文本(字符串),如:OK、NotFound...
实例
def ajax(request):
return render(request,'ajax.html')
def ajax_json(request):
from django.http import JsonResponse
if request.method=='GET':
return JsonResponse({'name':'小张','age':18})
if request.method=='POST':
name=request.POST.get('name')
age=request.POST.get('age')
print(name)
print(age)
return JsonResponse({'name':name,'age':age})
ajax.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>ajax</title>
</head>
<body>
<input type="button" value="原生ajax" onclick="ajaxl();">
<script>
{#跨浏览器支持#}
function getXHR() {
var xhr=null;
if(XMLHttpRequest){
xhr=new XMLHttpRequest();
}
else {
xhr=new ActiveXObject('Microsoft.XMLHTTP');
}
return xhr;
}
function ajaxl() {
var xhr=getXHR();
{#xhr.open('GET','/ajax_json',true);#}
xhr.open('POST','/ajax_json',true);
xhr.onreadystatechange=function () {
if(xhr.readyState==4){
//数据接收完毕
var obj=JSON.parse(xhr.responseText);
console.log(obj);
}
}
{#POST请求必须设置这个请求头#}
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset-UTF-8');
xhr.send('name=张三;age=35')
}
</script>
</body>
</html>
1.1.3 jquery的ajax
function ajax_jq() {
$.ajax(
{
url:'/ajax_json',
type:'POST',
{# traditional:一般是我们的data数据有数组时会用到 #}
traditional:false,
data:{'name':'张三','age':'35'},
{# ----------------- ajax的回调函数----------------------#}
{# 1、server端response 200成功,执行的回调函数#}
success:function (data) {
data=JSON.parse(data)
console.log(typeof data)},
{# 2、server端 response错误,执行的回调函数 #}
error:function () {
console.log(arguments)
alert(123) },
{# 3、无论server端返回的结果如何,都会执行的回调函数#}
complete:function () {
alert(321) },
{# 4、根据server端返回的状态码,执行的回调函数#}
statusCode:{
'403':function () {alert(403)},
'503':function () {alert(503)}}
})
}
def ajax_json(request):
from django.http import JsonResponse
if request.method=='GET':
return JsonResponse({'name':'小张','age':18})
if request.method=='POST':
name=request.POST.get('name')
age=request.POST.get('age')
print(name)
print(age)
JsonResponse.status_code=503
return JsonResponse({'name':name,'age':age})
1.1.4 伪Ajax
所谓伪装Ajax操作就是不利于任何Ajax,利于其他技术向后台发送数据,这个其他的技术要从 iframa标签说起
<form action="/ajax_json" method="post" target="ifm">
<iframe id='ifm' name="ifm" ></iframe>
<input type="text" name="username">
<input type="text" name="age">
<input type="submit" onclick="sumbitForm();" value="form提交">
</form>
<script>
function sumbitForm(){
$('#ifm').load(function () {
var con=$('#ifm').contents().find('body').text();
console.log(con);
});
}
</script>
1.1.5 Ajax选择
上传方法总结
上传文件—>iframe+input(伪造ajax)
上传数据---->Jquery、XMLHttpRespose(原生ajax)
图片预览功能实现思路:
1、上传图片到服务端
2、服务端返回一个URL到客户端
3、客户端再去通过img标签src服务端的返回的URL地址
1.2 文件上传
原生ajax文件上传
{% extends 'base.html' %}
{% block title %}ajax{% endblock %}
{% block content %}
<div class="container" style="margin-top: 30px;">
<div class="col-xs-12 col-sm-4 col-md-4">
<div class="file-container"
style="display:inline-block;position:relative;overflow: hidden;vertical-align:middle">
<button class="btn btn-success fileinput-button" type="button">上传</button>
<input type="file" id="jobData" onchange="loadFile(this.files[0])"
style="position:absolute;top:0;left:0;font-size:34px; opacity:0">
</div>
<span id="filename" style="vertical-align: middle">未上传文件</span>
<input class="btn btn-outline-primary" type="button" value="提交" onclick="sumbitFile();"></input>
</div>
</div>
{% endblock %}
{% block custom_js %}
<script >
function loadFile(file) {
$("#filename").html(file.name);
}
function sumbitFile() {
var file_obj=document.getElementById('jobData').files[0];
var fd=new FormData();
fd.append('upload_file',file_obj);
var xhr=new XMLHttpRequest();
xhr.open('POST','/upload_file',true);
xhr.onreadystatechange=function () {
if(xhr.readyState==4){
var obj=JSON.parse(xhr.responseText);
console.log(obj);
}
};
xhr.send(fd);
}
</script>
{% endblock %}
jQuery提交
function sumbitFileJquery() {
var file_obj = $('#jobData')[0].files[0];
var fd = new FormData();
fd.append('upload_file', file_obj);
$.ajax({
url: '/upload_file',
type: 'POST',
contentType: false,
{#告诉Jquery不要对请求头做特殊处理,因为formDta已经把数据封装好了#}
processData: false,
data: fd,
success: function (args) {
console.log(args)
}
})
}
iframe+form标签伪造ajax操作(兼容性更好)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>伪造Ajax上传</title>
</head>
<body>
<h1>伪造Ajax上传</h1>
<form method="post" id="f1" action="/upload_file" target='ifr'enctype="multipart/form-data">
<p><input type="file" name="k1"></p>
<p><iframe id="ifr"name="ifr" style="display: none"></iframe></p>
<p><input type="button" value="提交" onclick="upfile()"></p>
</form>
<div id="container"></div>
</body>
<script>
function upfile() {
{# 找到iframe标签在线绑定事件 页面加载事件()#}
document.getElementById('ifr').onload=loadIframe
{# 使用.submit()方法 提交表单#}
document.getElementById('f1').submit()
}
function loadIframe() {
{# 服务端有返回值 iframe标签就会加载,利用此特性绑定 加载事件,然后创建img标签,apendchilder到 一个div中显示 #}
var return_value=document.getElementById('ifr').contentWindow.document.body.innerHTML
var tag=document.createElement('img')
tag.src='/'+return_value
document.getElementById('container').appendChild(tag)}
</script>
</html>
1.3 图片验证码
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import random
from PIL import Image, ImageDraw, ImageFont, ImageFilter
_letter_cases = "abcdefghjkmnpqrstuvwxy" # 小写字母,去除可能干扰的i,l,o,z
_upper_cases = _letter_cases.upper() # 大写字母
_numbers = ''.join(map(str, range(3, 10))) # 数字
init_chars = ''.join((_letter_cases, _upper_cases, _numbers))
def create_validate_code(size=(120, 30),
chars=init_chars,
img_type="GIF",
mode="RGB",
bg_color=(255, 255, 255),
fg_color=(0, 0, 255),
font_size=18,
font_type="Monaco.ttf",
length=4,
draw_lines=True,
n_line=(1, 2),
draw_points=True,
point_chance=2):
"""
@todo: 生成验证码图片
@param size: 图片的大小,格式(宽,高),默认为(120, 30)
@param chars: 允许的字符集合,格式字符串
@param img_type: 图片保存的格式,默认为GIF,可选的为GIF,JPEG,TIFF,PNG
@param mode: 图片模式,默认为RGB
@param bg_color: 背景颜色,默认为白色
@param fg_color: 前景色,验证码字符颜色,默认为蓝色#0000FF
@param font_size: 验证码字体大小
@param font_type: 验证码字体,默认为 ae_AlArabiya.ttf
@param length: 验证码字符个数
@param draw_lines: 是否划干扰线
@param n_lines: 干扰线的条数范围,格式元组,默认为(1, 2),只有draw_lines为True时有效
@param draw_points: 是否画干扰点
@param point_chance: 干扰点出现的概率,大小范围[0, 100]
@return: [0]: PIL Image实例
@return: [1]: 验证码图片中的字符串
"""
width, height = size # 宽高
# 创建图形
img = Image.new(mode, size, bg_color)
draw = ImageDraw.Draw(img) # 创建画笔
def get_chars():
"""生成给定长度的字符串,返回列表格式"""
return random.sample(chars, length)
def create_lines():
"""绘制干扰线"""
line_num = random.randint(*n_line) # 干扰线条数
for i in range(line_num):
# 起始点
begin = (random.randint(0, size[0]), random.randint(0, size[1]))
# 结束点
end = (random.randint(0, size[0]), random.randint(0, size[1]))
draw.line([begin, end], fill=(0, 0, 0))
def create_points():
"""绘制干扰点"""
chance = min(100, max(0, int(point_chance))) # 大小限制在[0, 100]
for w in range(width):
for h in range(height):
tmp = random.randint(0, 100)
if tmp > 100 - chance:
draw.point((w, h), fill=(0, 0, 0))
def create_strs():
"""绘制验证码字符"""
c_chars = get_chars()
strs = ' %s ' % ' '.join(c_chars) # 每个字符前后以空格隔开
font = ImageFont.truetype(font_type, font_size)
font_width, font_height = font.getsize(strs)
draw.text(((width - font_width) / 3, (height - font_height) / 3),
strs, font=font, fill=fg_color)
return ''.join(c_chars)
if draw_lines:
create_lines()
if draw_points:
create_points()
strs = create_strs()
# 图形扭曲参数
params = [1 - float(random.randint(1, 2)) / 100,
0,
0,
0,
1 - float(random.randint(1, 10)) / 100,
float(random.randint(1, 2)) / 500,
0.001,
float(random.randint(1, 2)) / 500
]
img = img.transform(size, Image.PERSPECTIVE, params) # 创建扭曲
img = img.filter(ImageFilter.EDGE_ENHANCE_MORE) # 滤镜,边界加强(阈值更大)
return img, strs