上一篇文章
>Django入门(四)之Session操作、CSRF操作、自定义中间件、缓存、信号和Form组件
一、本机环境
操作系统:Red Hat Enterprise Linux Server release 7.3 (Maipo)
Python版本:python3.6
Django版本:Django-2.1.5
1、创建项目
[root@python _Django]# tree newproject1
newproject1
├── app
│ ├── admin.py
│ ├── apps.py
│ ├── __init__.py
│ ├── migrations
│ │ ├── __init__.py
│ │ └── __pycache__
│ │ └── __init__.cpython-36.pyc
│ ├── models.py
│ ├── __pycache__
│ │ ├── admin.cpython-36.pyc
│ │ ├── __init__.cpython-36.pyc
│ │ └── models.cpython-36.pyc
│ ├── tests.py
│ └── views.py
├── manage.py
├── newproject1
│ ├── __init__.py
│ ├── __pycache__
│ │ ├── __init__.cpython-36.pyc
│ │ ├── settings.cpython-36.pyc
│ │ ├── urls.cpython-36.pyc
│ │ └── wsgi.cpython-36.pyc
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
├── static
│ ├── jquery-1.12.4.min.js
│ └── jquery.cookie-1.4.1.min.js
└── templates
2、生成数据库表
[root@python newproject1]# vim app/models.py
from django.db import models
class UserType(models.Model):
caption = models.CharField(max_length=32)
class UserInfo(models.Model):
username = models.CharField(max_length=32)
email = models.EmailField()
user_type = models.ForeignKey(to='UserType', to_field='id', on_delete=models.CASCADE)
[root@python newproject1]# python manage.py makemigrations
[root@python newproject1]# python manage.py migrate
二、Form和ModelForm方法对比
1、Form方法
(1)配置urls.py
[root@python newproject1]# vim newproject1/urls.py
from django.contrib import admin
from django.urls import path
from app import views
urlpatterns = [
path('admin/', admin.site.urls),
path('index/', views.index),
]
(2)配置views.py
[root@python newproject1]# vim app/views.py
from django.shortcuts import render
from django import forms
from django.forms import fields
from app import models
class UserInfoForm(forms.Form):
username = fields.CharField(max_length=32)
email = fields.EmailField()
user_type = fields.ChoiceField(
choices = models.UserType.objects.values_list('id', 'caption')
)
def __init__(self, *args, **kwargs):
super(UserInfoForm,self).__init__(*args, **kwargs)
self.fields['user_type'].choices = models.UserType.objects.values_list('id', 'caption')
def index(request):
if request.method == "GET":
obj = UserInfoForm()
return render(request,'index.html', {'obj': obj})
elif request.method == "POST":
obj = UserInfoForm(request.POST)
obj.is_valid()
obj.errors
# models.UserInfo.objects.create(**obj.cleaned_data)
# models.UserInfo.objects.filter(id=1).update(**obj.cleaned_data)
return render(request,'index.html',{'obj':obj})
(3)配置HTML
[root@python newproject1]# vim templates/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/index/" method="POST">
{% csrf_token %}
{{ obj.as_p }}
<input type="submit" value="提交" />
</form>
</body>
</html>
(4)访问并查看结果
http://10.10.10.111:8000/index/
2、ModelForm方法
适用于小程序,因为耦合度较高!!!
(1)配置views.py
[root@python newproject1]# vim app/views.py
from django.shortcuts import render
from django import forms
from django.forms import fields
from app import models
### 其实是获取了models.py的UserInfo内容
class UserInfoModelForm(forms.ModelForm):
class Meta:
model = models.UserInfo
### 显示所有结果
fields = '__all__'
### 只显示这2个参数
# fields = ['username','email']
### 显示除了此参数结果
# exclude = ['username']
def index(request):
if request.method == "GET":
### 修改此处
obj = UserInfoModelForm()
return render(request,'index.html', {'obj': obj})
elif request.method == "POST":
obj = UserInfoForm(request.POST)
print (obj.is_valid())
print (obj.cleaned_data)
print (obj.errors)
# models.UserInfo.objects.create(**obj.cleaned_data)
# models.UserInfo.objects.filter(id=1).update(**obj.cleaned_data)
return render(request,'index.html',{'obj':obj})
(2)访问并查看结果
我们可以发现就User type不同,其他都一样!!!
http://10.10.10.111:8000/index/
三、ModelForm操作
1、自定义label
在app_usertype中随意添加一个数据!!!
也可以在views中通过labels
参数进行设置!!!
[root@python newproject1]# vim app/models.py ###添加verbose_name参数
http://10.10.10.111:8000/index/
2、ModelForm参数
class Meta:
model, ###对应Model
fields=None, ###字段
exclude=None, ###排除
labels=None, ###label设置,views中:labels={'username':'用户名',}
help_texts=None, ###提示信息
widgets=None, ###自定义插件,eg:导入:from django.forms import widgets as Fwidgets -->> widgets = {'username':Fwidgets.Textarea(attrs={'class': 'c1'})}
error_messages=None, ###自定义错误信息,error_messages = {'email':{'required': '邮箱不能为空','invalid': '邮箱格式错误'}}也可以通过"__all__"来设置整体报错信息
field_classes=None, ###自定义字段类,from django.forms import fields as Ffields,field_classes = {'email': Ffields.URLField}
localized_fields=('birth_date') ###本地化,eg:根据不同时区显示数据
3、通过ModelForm实现多对多
在app_usergroup表中插入2条数据!!!
(1)配置models.py
[root@python newproject1]# vim app/models.py
from django.db import models
class UserType(models.Model):
caption = models.CharField(max_length=32)
class UserGroup(models.Model):
name = models.CharField(max_length=32)
class UserInfo(models.Model):
username = models.CharField(verbose_name='用户名', max_length=32)
email = models.EmailField()
user_type = models.ForeignKey(to='UserType', to_field='id', on_delete=models.CASCADE)
u2g = models.ManyToManyField(UserGroup)
(2)更新数据库
[root@python newproject1]# python manage.py makemigrations
[root@python newproject1]# python manage.py migrate
(3)配置views.py
[root@python newproject1]# vim app/views.py
from django.shortcuts import render
from django import forms
from django.forms import fields
from app import models
class UserInfoModelForm(forms.ModelForm):
class Meta:
model = models.UserInfo
fields = '__all__'
# fields = ['username','email']
# exclude = ['username']
def index(request):
if request.method == "GET":
### 修改此处
obj = UserInfoModelForm()
return render(request,'index.html', {'obj': obj})
elif request.method == "POST":
obj = UserInfoModelForm(request.POST)
if obj.is_valid():
obj.save()
### 等同于下面3句
# instance = obj.save(False)
# instance.save()
# obj.save_m2m()
# print (obj.is_valid())
# print (obj.cleaned_data)
# print (obj.errors)
# models.UserInfo.objects.create(**obj.cleaned_data)
# models.UserInfo.objects.filter(id=1).update(**obj.cleaned_data)
return render(request,'index.html',{'obj':obj})
(4)访问并查看结果
[root@python newproject1]# python manage.py runserver 10.10.10.111:8000
可以发现app_userinfo_u2g
表中有表对应的选项!!!
4、ModelForm实现多表提交数据
(1)配置urls.py
[root@python newproject1]# vim newproject1/urls.py
from django.contrib import admin
from django.urls import path,re_path
from app import views
urlpatterns = [
path('admin/', admin.site.urls),
path('index/', views.index),
path('user_list/', views.user_list),
re_path('user_edit-(\d+)/', views.user_edit),
]
(2)配置views.py
[root@python newproject1]# vim app/views.py
from django.shortcuts import render
from django import forms
from django.forms import fields
from app import models
class UserInfoModelForm(forms.ModelForm):
class Meta:
model = models.UserInfo
fields = '__all__'
# fields = ['username','email']
# exclude = ['username']
def index(request):
if request.method == "GET":
### 修改此处
obj = UserInfoModelForm()
return render(request, 'index.html', {'obj': obj})
elif request.method == "POST":
obj = UserInfoModelForm(request.POST)
if obj.is_valid():
obj.save()
# print (obj.is_valid())
# print (obj.cleaned_data)
# print (obj.errors)
# models.UserInfo.objects.create(**obj.cleaned_data)
# models.UserInfo.objects.filter(id=1).update(**obj.cleaned_data)
return render(request, 'index.html', {'obj': obj})
def user_list(request):
li = models.UserInfo.objects.all().select_related('user_type')
return render(request, 'user_list.html', {'li': li})
def user_edit(request, nid):
if request.method == "GET":
user_obj = models.UserInfo.objects.filter(id=nid).first()
mf = UserInfoModelForm(instance=user_obj)
return render(request, 'user_edit.html', {'mf': mf, 'nid': nid, })
elif request.method == "POST":
user_obj = models.UserInfo.objects.filter(id=nid).first()
### 如果不写instance将会增加数据,而不是修改
mf = UserInfoModelForm(request.POST, instance=user_obj)
if mf.is_valid():
mf.save()
else:
print (mf.errors.as_json())
return render(request, 'user_edit.html', {'mf': mf, 'nid': nid, })
(3)配置HTML
<1> 配置user_list.html
[root@python newproject1]# vim templates/user_list.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<ul>
{% for row in li %}
<li>{row.username}-{{ row.user_type.caption }}-<a href="/user_edit-{{ row.id }}/">编辑</a></li>
{% endfor %}
</ul>
</body>
</html>
<2> 配置user_edit.html
[root@python newproject1]# vim templates/user_edit.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/user_edit-{{ nid }}/" method="POST">
{% csrf_token %}
{{ mf.as_p }}
<input type="submit" value="提交" />
</form>
</body>
</html>
(4)运行并访问
可以进行编辑,并修改数据,实现对多表的操作!!!
http://10.10.10.111:8000/user_list/
5、自定制标签
(1)配置views.py
[root@python newproject1]# vim app/views.py
from django.shortcuts import render
from django import forms
from django.forms import fields
from app import models
from django.forms import widgets as Fwidgets
class UserInfoModelForm(forms.ModelForm):
is_rem = fields.CharField(
widget = Fwidgets.CheckboxInput()
)
class Meta:
model = models.UserInfo
fields = '__all__'
# fields = ['username','email']
# exclude = ['username']
def index(request):
if request.method == "GET":
### 修改此处
obj = UserInfoModelForm()
return render(request, 'index.html', {'obj': obj})
elif request.method == "POST":
obj = UserInfoModelForm(request.POST)
if obj.is_valid():
obj.save()
# print (obj.is_valid())
# print (obj.cleaned_data)
# print (obj.errors)
# models.UserInfo.objects.create(**obj.cleaned_data)
# models.UserInfo.objects.filter(id=1).update(**obj.cleaned_data)
return render(request, 'index.html', {'obj': obj})
def user_list(request):
li = models.UserInfo.objects.all().select_related('user_type')
return render(request, 'user_list.html', {'li': li})
def user_edit(request, nid):
if request.method == "GET":
user_obj = models.UserInfo.objects.filter(id=nid).first()
mf = UserInfoModelForm(instance=user_obj)
return render(request, 'user_edit.html', {'mf': mf, 'nid': nid, })
elif request.method == "POST":
user_obj = models.UserInfo.objects.filter(id=nid).first()
### 如果不写instance将会增加数据,而不是修改
mf = UserInfoModelForm(request.POST, instance=user_obj)
if mf.is_valid():
mf.save()
else:
print (mf.errors.as_json())
return render(request, 'user_edit.html', {'mf': mf, 'nid': nid, })
(2)访问并查看结果
http://10.10.10.111:8000/index/
四、原生Ajax
1、XmlHttpRequest对象方法
void open(String method,String url,Boolen async)
用于创建请求
参数:
method: 请求方式(字符串类型),如:POST、GET、DELETE...
url: 要请求的地址(字符串类型)
async: 是否异步(布尔类型)
void send(String body)
用于发送请求
参数:
body: 要发送的数据(字符串类型)
void setRequestHeader(String header,String value)
用于设置请求头
参数:
header: 请求头的key(字符串类型)
vlaue: 请求头的value(字符串类型)
String getAllResponseHeaders()
获取所有响应头
返回值:
响应头数据(字符串类型)
String getResponseHeader(String header)
获取响应头中指定header的值
参数:
header: 响应头的key(字符串类型)
返回值:
响应头中指定的header对应的值
void abort()
终止请求
2、XmlHttpRequest对象属性
Number readyState
状态值(整数)
详细:
0-未初始化,尚未调用open()方法;
1-启动,调用了open()方法,未调用send()方法;
2-发送,已经调用了send()方法,未接收到响应;
3-接收,已经接收到部分响应数据;
4-完成,已经接收到全部响应数据;
Function onreadystatechange
当readyState的值改变时自动触发执行其对应的函数(回调函数)
String responseText
服务器返回的数据(字符串类型)
XmlDocument responseXML
服务器返回的数据(Xml对象)
Number states
状态码(整数),如:200、404...
String statesText
状态文本(字符串),如:OK、NotFound...
3、Ajax实例(get)
(1)配置urls.py
[root@python newproject1]# vim newproject1/urls.py
from django.contrib import admin
from django.urls import path,re_path
from app import views
urlpatterns = [
path('admin/', admin.site.urls),
path('index/', views.index),
path('user_list/', views.user_list),
re_path('user_edit-(\d+)/', views.user_edit),
re_path('ajax/$',views.ajax),
re_path('ajax_json/$',views.ajax_json),
]
(2)配置views.py
[root@python newproject1]# vim app/views.py
from django.shortcuts import render,HttpResponse
from django import forms
from django.forms import fields
from app import models
from django.forms import widgets as Fwidgets
class UserInfoModelForm(forms.ModelForm):
is_rem = fields.CharField(
widget = Fwidgets.CheckboxInput()
)
class Meta:
model = models.UserInfo
fields = '__all__'
# fields = ['username','email']
# exclude = ['username']
def index(request):
if request.method == "GET":
### 修改此处
obj = UserInfoModelForm()
return render(request, 'index.html', {'obj': obj})
elif request.method == "POST":
obj = UserInfoModelForm(request.POST)
if obj.is_valid():
obj.save()
# print (obj.is_valid())
# print (obj.cleaned_data)
# print (obj.errors)
# models.UserInfo.objects.create(**obj.cleaned_data)
# models.UserInfo.objects.filter(id=1).update(**obj.cleaned_data)
return render(request, 'index.html', {'obj': obj})
def user_list(request):
li = models.UserInfo.objects.all().select_related('user_type')
return render(request, 'user_list.html', {'li': li})
def user_edit(request, nid):
if request.method == "GET":
user_obj = models.UserInfo.objects.filter(id=nid).first()
mf = UserInfoModelForm(instance=user_obj)
return render(request, 'user_edit.html', {'mf': mf, 'nid': nid, })
elif request.method == "POST":
user_obj = models.UserInfo.objects.filter(id=nid).first()
### 如果不写instance将会增加数据,而不是修改
mf = UserInfoModelForm(request.POST, instance=user_obj)
if mf.is_valid():
mf.save()
else:
print (mf.errors.as_json())
return render(request, 'user_edit.html', {'mf': mf, 'nid': nid, })
def ajax(request):
return render(request,'ajax.html')
def ajax_json(request):
r = {'code': True, 'data': None}
import json
# return HttpResponse(json.dumps(r), status=404,reason='Not Found')
return HttpResponse(json.dumps(r))
(3)配置HTML
[root@python newproject1]# vim templates/ajax.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<input type="button" value="Ajax1" onclick="Ajax1();" />
<script>
function Ajax1() {
var xhr = new XMLHttpRequest();
xhr.open("GET",'/ajax_json/',true);
xhr.onreadystatechange = function(){
if(xhr.readyState == 4){
// 接收完毕数据
// var v = xhr.responseText;
//JSON格式
var v = JSON.parse(xhr.responseText)
console.log(v);
}
};
// 发送请求头,可以发送CSRF
xhr.setRequestHeader('k1','v1');
xhr.send('name=dream;pwd=1');
}
</script>
</body>
</html>
(4)访问并查看结果
http://10.10.10.111:8000/ajax/ ###控制台查看network
4、Ajax实例(post)
这里我是吧setting中的CSRF注释掉了!!!
(1)配置HTML
[root@python newproject1]# vim templates/ajax.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<input type="button" value="Ajax1" onclick="Ajax1();" />
<script>
function Ajax1() {
var xhr = new XMLHttpRequest();
xhr.open("POST",'/ajax_json/',true);
xhr.onreadystatechange = function(){
if(xhr.readyState == 4){
// 接收完毕数据
// var v = xhr.responseText;
//JSON格式
var v = JSON.parse(xhr.responseText)
console.log(v);
}
};
xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded; charset-UTF-8');
xhr.send('name=dream;pwd=1');
}
</script>
</body>
</html>
(2)配置views.py
[root@python newproject1]# vim app/views.py ###添加
(3)访问并查看结果
http://10.10.10.111:8000/ajax/
5、实现兼容性
[root@python newproject1]# vim templates/ajax.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<input type="button" value="Ajax1" onclick="Ajax1();" />
<script>
// 判断浏览器
function getXHR() {
var xhr = null;
if(XMLHttpRequest){
xhr = new XMLHttpRequest();
}else{
xhr =new ActiveXObject('Microsoft.XMLHTTP');
}
return xhr;
}
function Ajax1() {
var xhr = getXHR();
xhr.open("POST",'/ajax_json/',true);
xhr.onreadystatechange = function(){
if(xhr.readyState == 4){
// 接收完毕数据
// var v = xhr.responseText;
//JSON格式
var v = JSON.parse(xhr.responseText)
console.log(v);
}
};
xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded; charset-UTF-8');
xhr.send('name=dream;pwd=1');
}
</script>
</body>
</html>
五、伪Ajax
1、通过iframe实现发送请求
(1)配置HTML
[root@python newproject1]# vim templates/ajax.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<input type="button" value="Ajax1" onclick="Ajax1();" />
<input type="text" id="url" />
<input type="button" value="iframe请求" onclick="iframeRequest();" />
<iframe id="ifm" src="http://www.dreamya.top"></iframe>
<script src="/static/jquery-1.12.4.min.js"></script>
<script>
// 判断浏览器
function getXHR() {
var xhr = null;
if(XMLHttpRequest){
xhr = new XMLHttpRequest();
}else{
xhr =new ActiveXObject('Microsoft.XMLHTTP');
}
return xhr;
};
function Ajax1() {
var xhr = getXHR();
xhr.open("POST",'/ajax_json/',true);
xhr.onreadystatechange = function(){
if(xhr.readyState == 4){
// 接收完毕数据
// var v = xhr.responseText;
//JSON格式
var v = JSON.parse(xhr.responseText)
console.log(v);
}
};
xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded; charset-UTF-8');
xhr.send('name=dream;pwd=1');
};
function iframeRequest() {
var url = $('#url').val();
$('#ifm').attr('src',url);
};
</script>
</body>
</html>
(2)访问并查看结果
http://10.10.10.111:8000/ajax/
2、伪Ajax请求
(1)配置HTML
[root@python newproject1]# vim templates/ajax.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<input type="button" value="Ajax1" onclick="Ajax1();" />
<!--<input type="text" id="url" />-->
<!--<input type="button" value="iframe请求" onclick="iframeRequest();" />-->
<!--<iframe id="ifm" src="http://www.dreamya.top"></iframe>-->
<form action="/ajax_json/" method="POST" target="ifm1">
<iframe name="ifm1"></iframe>
<input type="text" name="username">
<input type="text" name="email">
<input type="submit" value="Form提交">
</form>
<script src="/static/jquery-1.12.4.min.js"></script>
<script>
// 判断浏览器
function getXHR() {
var xhr = null;
if(XMLHttpRequest){
xhr = new XMLHttpRequest();
}else{
xhr =new ActiveXObject('Microsoft.XMLHTTP');
}
return xhr;
};
function Ajax1() {
var xhr = getXHR();
xhr.open("POST",'/ajax_json/',true);
xhr.onreadystatechange = function(){
if(xhr.readyState == 4){
// 接收完毕数据
// var v = xhr.responseText;
//JSON格式
var v = JSON.parse(xhr.responseText)
console.log(v);
}
};
xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded; charset-UTF-8');
xhr.send('name=dream;pwd=1');
};
// function iframeRequest() {
// var url = $('#url').val();
// $('#ifm').attr('src',url);
// };
</script>
</body>
</html>
(2)访问并查看结果
http://10.10.10.111:8000/ajax/
3、iframe返回数据
(1)配置HTML
[root@python newproject1]# vim templates/ajax.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<input type="button" value="Ajax1" onclick="Ajax1();" />
<form action="/ajax_json/" method="POST" target="ifm1">
<iframe id="ifm1" name="ifm1"></iframe>
<input type="text" name="username">
<input type="text" name="email">
<input type="submit" value="Form提交" onclick="submitForm();">
</form>
<script src="/static/jquery-1.12.4.min.js"></script>
<script>
// 判断浏览器
function getXHR() {
var xhr = null;
if(XMLHttpRequest){
xhr = new XMLHttpRequest();
}else{
xhr =new ActiveXObject('Microsoft.XMLHTTP');
}
return xhr;
};
function Ajax1() {
var xhr = getXHR();
xhr.open("POST",'/ajax_json/',true);
xhr.onreadystatechange = function(){
if(xhr.readyState == 4){
// 接收完毕数据
// var v = xhr.responseText;
//JSON格式
var v = JSON.parse(xhr.responseText)
console.log(v);
}
};
xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded; charset-UTF-8');
xhr.send('name=dream;pwd=1');
};
function submitForm() {
$('#ifm1').load(function () {
var t = $('#ifm1').contents().find('body').text();
var obj = JSON.parse(t);
console.log(obj);
})
}
</script>
</body>
</html>
(2)访问并查看结果
http://10.10.10.111:8000/ajax/ ###可以在控制台看到返回内容
六、文件上传
优先用iframe方式来实现,兼容性更好,jquery和原生方式都要基于FormData!!!
1、原生方式实现
(1)配置urls.py
[root@python newproject1]# vim newproject1/urls.py
from django.contrib import admin
from django.urls import path,re_path
from app import views
urlpatterns = [
path('admin/', admin.site.urls),
path('index/', views.index),
path('user_list/', views.user_list),
re_path('user_edit-(\d+)/', views.user_edit),
re_path('ajax/$',views.ajax),
re_path('ajax_json/$',views.ajax_json),
re_path('upload/$',views.upload),
re_path('upload_file/$',views.upload_file),
]
(2)配置views.py
[root@python newproject1]# vim app/views.py
from django.shortcuts import render,HttpResponse
from django import forms
from django.forms import fields
from app import models
from django.forms import widgets as Fwidgets
...
def upload(request):
return render(request,'upload.html')
def upload_file(request):
username = request.POST.get('username')
uploadFile = request.FILES.get('uploadFile')
print(username,uploadFile)
with open(uploadFile.name,'wb') as f:
for item in uploadFile.chunks():
f.write(item)
r = {'code': True, 'data': None}
import json
return HttpResponse(json.dumps(r))
(3)配置HTML
[root@python newproject1]# vim templates/upload.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.upload{
display: inline-block;
padding: 10px;
background-color: deepskyblue;
position: absolute;
top: 0px;
right: 0px;
bottom: 0px;
left: 0px;
z-index: 90;
}
.file{
width: 100px;height: 60px;opacity: 0;
position: absolute;
top: 0px;
right: 0px;
bottom: 0px;
left: 0px;
z-index: 100;
}
</style>
</head>
<body>
<div style="position: relative;width: 100px;height: 60px;">
<input class="file" type="file" id="uploadFile" name="uploadFile" />
<a class="upload">上传</a>
</div>
<input type="button" value="提交XHR" onclick="xhrSubmit();" />
<script>
function xhrSubmit() {
// 这里是个对象
var file_obj = document.getElementById('uploadFile').files[0];
var fd = new FormData();
fd.append('username','root');
fd.append('uploadFile',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>
</body>
</html>
(4)访问并查看结果
http://10.10.10.111:8000/upload/
2、jquery方式
(1)配置HTML
[root@python newproject1]# vim templates/upload.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.upload{
display: inline-block;
padding: 10px;
background-color: deepskyblue;
position: absolute;
top: 0px;
right: 0px;
bottom: 0px;
left: 0px;
z-index: 90;
}
.file{
width: 100px;height: 60px;opacity: 0;
position: absolute;
top: 0px;
right: 0px;
bottom: 0px;
left: 0px;
z-index: 100;
}
</style>
</head>
<body>
<div style="position: relative;width: 100px;height: 60px;">
<input class="file" type="file" id="uploadFile" name="uploadFile" />
<a class="upload">上传</a>
</div>
<input type="button" value="提交jquery" onclick="jqSubmit();">
<script src="/static/jquery-1.12.4.min.js"></script>
<script>
function jqSubmit() {
var file_obj = document.getElementById('uploadFile').files[0];
var fd = new FormData();
fd.append('username','root');
fd.append('uploadFile',file_obj);
$.ajax({
url: '/upload_file/',
type: 'POST',
data: fd,
processData: false,
contentType: false,
success:function (a,b,c) {
console.log(a);
console.log(b);
console.log(c);
}
})
}
</script>
</body>
</html>
(2)访问并查看结果
http://10.10.10.111:8000/upload/
3、iframe方式
(1)配置HTML
[root@python newproject1]# vim templates/upload.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/upload_file/" method="POST" enctype="multipart/form-data" target="ifm1">
<iframe id="ifm1" name="ifm1" style="display: none;"></iframe>
<input type="file" name="uploadFile">
<input type="submit" value="iframe提交" onclick="iframeForm();">
</form>
<script>
function iframeForm() {
$('#ifm1').load(function () {
var t = $('#ifm1').contents().find('body').text();
var obj = JSON.parse(t);
console.log(obj);
})
}
</script>
</body>
</html>
(2)访问并查看结果
http://10.10.10.111:8000/upload/
4、实现图片预览
上传的文件都保存在
static
目录下!!!
(1)通过按钮提交
<1> 配置views.py
[root@python newproject1]# vim app/views.py
from django.shortcuts import render,HttpResponse
from django import forms
from django.forms import fields
from app import models
from django.forms import widgets as Fwidgets
...
def upload(request):
return render(request,'upload.html')
def upload_file(request):
username = request.POST.get('username')
uploadFile = request.FILES.get('uploadFile')
import os
img_path = os.path.join('static/',uploadFile.name)
with open(img_path,'wb') as f:
for item in uploadFile.chunks():
f.write(item)
r = {'code': True, 'data': img_path}
import json
return HttpResponse(json.dumps(r))
<2> 配置HTML
[root@python newproject1]# vim templates/upload.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/upload_file/" method="POST" enctype="multipart/form-data" target="ifm1">
<iframe id="ifm1" name="ifm1" style="display: none;"></iframe>
<input type="file" name="uploadFile" />
<input type="submit" value="iframe提交" onclick="iframeForm();">
</form>
<div id="preview"></div>
<script src="/static/jquery-1.12.4.min.js"></script>
<script>
function iframeForm() {
$('#ifm1').load(function () {
var t = $('#ifm1').contents().find('body').text();
var obj = JSON.parse(t);
$('#preview').empty();
var imgTag = document.createElement('img');
imgTag.src = "/" + obj.data;
$('#preview').append(imgTag);
})
};
</script>
</body>
</html>
<3> 访问并查看结果
http://10.10.10.111:8000/upload/
(2)自动上传
<1> 配置HTML
[root@python newproject1]# vim templates/upload.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form id="form1" action="/upload_file/" method="POST" enctype="multipart/form-data" target="ifm1">
<iframe id="ifm1" name="ifm1" style="display: none;"></iframe>
<input type="file" name="uploadFile" onchange="changeUpload();">
<!--<input type="submit" value="iframe提交" onclick="iframeForm();">-->
</form>
<div id="preview"></div>
<script src="/static/jquery-1.12.4.min.js"></script>
<script>
function changeUpload() {
$('#ifm1').load(function () {
var t = $('#ifm1').contents().find('body').text();
var obj = JSON.parse(t);
$('#preview').empty();
var imgTag = document.createElement('img');
imgTag.src = "/" + obj.data;
$('#preview').append(imgTag);
});
$('#form1').submit();
}
</script>
</body>
</html>
<2> 访问并查看结果
http://10.10.10.111:8000/upload/
七、图片验证码+Session
1、安装pillow
(1)下载安装
下载地址:https://pypi.org/project/Pillow/5.4.1/#files
联网安装:pip install pillow
[root@python ~]# wget https://files.pythonhosted.org/packages/3c/7e/443be24431324bd34d22dd9d11cc845d995bcd3b500676bcf23142756975/Pillow-5.4.1.tar.gz
[root@python ~]# cd Pillow-5.4.1/
[root@python mnt]# tar xf Pillow-5.4.1.tar.gz
[root@python Pillow-5.4.1]# python setup.py install
(2)报错解决
<1> 报错:
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "setup.py", line 812, in <module>
raise RequiredDependencyException(msg)
__main__.RequiredDependencyException:
The headers or library files could not be found for jpeg,
a required dependency when compiling Pillow from source.
Please see the install instructions at:
https://pillow.readthedocs.io/en/latest/installation.html
<2> 安装依赖
[root@python mnt]# yum install -y python-devel zlib-devel libjpeg-turbo-devel
[root@python Pillow-5.4.1]# python setup.py install
<3> 测试结果
[root@python Pillow-5.4.1]# python
Python 3.6.0 (default, Jan 8 2019, 05:27:57)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-11)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from PIL import Image
2、验证码生成
并在utils目录下放个
Monaco.ttf
字体文件,百度网盘链接:https://pan.baidu.com/s/1e4o-6rcoHvlijTIEo0cvNA 提取码: v3x9
(1)配置check_code.py
[root@python newproject1]# mkdir utils/
[root@python newproject1]# vim utils/check_code.py
#!/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="utils/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
(2)配置urls.py
[root@python newproject1]# vim newproject1/urls.py
from django.contrib import admin
from django.urls import path,re_path
from app import views
urlpatterns = [
path('admin/', admin.site.urls),
path('index/', views.index),
path('user_list/', views.user_list),
re_path('user_edit-(\d+)/', views.user_edit),
re_path('ajax/$',views.ajax),
re_path('ajax_json/$',views.ajax_json),
re_path('upload/$',views.upload),
re_path('upload_file/$',views.upload_file),
re_path('code/$',views.get_code),
path('code_img.html/',views.code_img),
]
(3)配置views.py
[root@python newproject1]# vim app/views.py
from django.shortcuts import render,HttpResponse
from django import forms
from django.forms import fields
from app import models
from django.forms import widgets as Fwidgets
...
from io import BytesIO
from utils.check_code import create_validate_code
### 验证码页面
def get_code(request):
return render(request,'code.html')
def code_img(request):
### 创建一个内存地址存放图片
f = BytesIO()
### 调用方法生成图片对象和验证码
img, code = create_validate_code()
### 设置session
request.session['check_code'] = code
print(code)
### 保存图片
img.save(f, 'PNG')
return HttpResponse(f.getvalue())
(4)配置HTML
[root@python newproject1]# vim templates/code.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<img src="/code_img.html" id="code_img">
<script src="/static/jquery-1.12.4.min.js" type="text/javascript"></script>
<script>
$('#code_img').click(function () {
this.src = this.src + '?';
})
</script>
</body>
</html>
(5)访问并查看结果
http://10.10.10.111:8000/code/