python xlsx 样式 谷歌开源 样式_python 全栈开发,Day86(上传文件,上传头像,CBV,python读写Excel,虚拟环境virtualenv)...

一、上传文件

上传一个图片

使用input type="file",来上传一个文件。注意:form表单必须添加属性enctype="multipart/form-data"

在views.py视图函数中,获取文件对象,必须使用request.FILES.get

新建项目upload_file,在项目中新建static文件夹,在文件夹里面创建upload目录,用来保存上传的文件。

修改settings.py,定义static路径

STATIC_URL = '/static/'STATICFILES_DIRS=(

os.path.join(BASE_DIR,'static'),

)

View Code

修改urls.py,增加路径

from app01 importviews

urlpatterns=[

path('admin/', admin.site.urls),

path('index/', views.index),

]

View Code

修改views.py,增加视图函数

from django.shortcuts importrender,HttpResponseimportosfrom upload_file import settings #导入settings。注意:upload_file为项目名

#Create your views here.

defindex(request):if request.method == "GET":return render(request,'index.html')

user= request.POST.get('user')#获取文件对象,必须使用request.FILES.get

avatar = request.FILES.get('avatar')print(user)print(avatar,type(avatar))print(avatar.__dict__) #查看对象所有属性

#文件存储的绝对路径

path = os.path.join(settings.BASE_DIR, "static", "upload", avatar.name)

with open(path,'wb') as f:#将大文件分割成若干小文件处理,处理完每个小文件后释放该部分内存

for line inavatar.chunks():

f.write(line)#写入文件

return HttpResponse('上传成功')

View Code

新建index.html

Title{% csrf_token %}上传图片

用户名

View Code

启动项目,访问url: http://127.0.0.1:8000/index/

选择一个图片

提示上传成功

在upload目录,就会多出一个图片  QQ图片20180327153648.jpg

上传按钮美化

所有好看的上传按钮,都是经过修饰的。那么它是如何做到的呢!原理如下:

修饰的样式一般是用html做的,将前面的input上传控件变成透明。

那么用户看到的是一个经过修饰的按钮,实际点击的是input上传控件!

注意:上传控件的尺寸和后面的html控件,大小是一样的,比如div

举例:

修改index.html

Title{% csrf_token %}

点击上传文件

{#opacity表示设置透明度,0表示完全透明#}

用户名:

{#当元素的值发生改变时,会发生 change 事件#}

$('#excelFile').change(function (e) {

{#event.currentTarget 属性是在事件冒泡阶段内的当前 DOM 元素,通常等于 this#}

{#:file 选择器选取带有 type=file 的 input 元素#}

{#0表示获取第一个元素,name表示获取文件名#}

var fileName =e.currentTarget.files[0].name;

{#prev() 获得匹配元素集合中每个元素紧邻的前一个同胞元素,通过选择器进行筛选是可选的#}

{#$(this)表示上传控件,那么它前一个同胞元素为div style="position:...#}

{#find() 方法获得当前元素集合中每个元素的后代,通过选择器、jQuery 对象或元素来筛选。#}

{#text() 方法方法设置或返回被选元素的文本内容#}

$(this).prev().find('span').text(fileName);

})

})

View Code

重新访问网页,效果如下:

重新上传一个图片,效果如下:

点击提交,提示上传成功!

这个是重点,考试必考!

二、上传头像

一般做上传头像功能,会有一个预览效果。总共有4种方法:

createObjectURL

FileReader

FormData

iframe

前2种,是在浏览器端可以做图片预览,没有上传图片到服务器!

后2种,图片需要上传到服务器。

兼容性效果对比: iframe > FormData > FileReader -> createObjectURL

iframe的兼容性是最好的,即使ie6也支持。FormData对浏览器,有一定要求

参考兼容性:

createObjectURL

举例:

修改urls.py,增加路径

urlpatterns =[

path('admin/', admin.site.urls),

path('index/', views.index),

path('upload_file/', views.upload_file),

]

View Code

修改views.py,增加视图函数

defupload_file(request):if request.method == "GET":print(11)return render(request,'upload_file.html')

user= request.POST.get('user')

avatar= request.FILES.get('avatar')#文件存储的绝对路径

path = os.path.join(settings.BASE_DIR, "static", "upload", avatar.name)

with open(path,'wb') as f:for line inavatar.chunks():

f.write(line)return HttpResponse('上传成功')

View Code

创建upload_file.html,注意:不是所有浏览器都有createObjectURL

Title{% csrf_token %}

点击图片更换( 撤销)

用户名:

$(function () {

{#执行函数#}

bindChangeAvatar1();

});

function bindChangeAvatar1() {

{#绑定change事件#}

$('#avatarImg').change(function () {

{#$(this)表示input上传控件,0表示第一个元素#}

{#files[0] 获取file input中的File对象#}

var file_obj =$(this)[0].files[0];

console.log(file_obj);

{#通过createObjectURL读取对象,生成url#}

var blob =window.URL.createObjectURL(file_obj);

{#修改src的值#}

document.getElementById('previewImg').src =blob;

{#load() 当资源加载完成之后才会执行#}

$('#previewImg').load(function () {

{#revokeObjectURL释放对象#}

window.URL.revokeObjectURL(blob);

})

})

}

View Code

访问url: http://127.0.0.1:8000/upload_file/

上传一个图片

点击提交,提示上传成功

在upload目录,会有一个文件  QQ图片20180327153648.jpg

FileReader

举例:

修改upload_file.html里面的js代码即可,readAsDataURL也有兼容问题

Title{% csrf_token %}

点击图片更换( 撤销)

用户名:

bindChangeAvatar2();

});

function bindChangeAvatar2() {

$('#avatarImg').change(function () {

var file_obj=$(this)[0].files[0];//使用fileReader对文件对象进行操作

var reader=new FileReader();//readAsDataURL 将文件读取为 DataURL

reader.readAsDataURL(file_obj);//onload 事件会在页面或图像加载完成后立即发生

reader.οnlοad=function (e) {//修改src属性

$('#previewImg')[0].src =this.result;

};

})

}

View Code

上传一个图片

点击提交,提示上传成功

在upload目录,会有一个文件  59fffde43ed74.jpg

FormData

上面的保存图片方式有问题,因为用户上传的图片,可能会重名。为了解决这个问题,需要使用uuid模块。

uuid

UUID是128位的全局唯一标识符,通常由32字节的字符串表示。

它可以保证时间和空间的唯一性,也称为GUID,全称为:

UUID —— Universally Unique IDentifier。Python 中叫 UUID

它通过MAC地址、时间戳、命名空间、随机数、伪随机数来保证生成ID的唯一性。

UUID主要有五个算法,也就是五种方法来实现:

1、uuid1()——基于时间戳

由MAC地址、当前时间戳、随机数生成。可以保证全球范围内的唯一性,

但MAC的使用同时带来安全性问题,局域网中可以使用IP来代替MAC。2、uuid2()——基于分布式计算环境DCE(Python中没有这个函数)

算法与uuid1相同,不同的是把时间戳的前4位置换为POSIX的UID。

实际中很少用到该方法。3、uuid3()——基于名字的MD5散列值

通过计算名字和命名空间的MD5散列值得到,保证了同一命名空间中不同名字的唯一性,

和不同命名空间的唯一性,但同一命名空间的同一名字生成相同的uuid。4、uuid4()——基于随机数

由伪随机数得到,有一定的重复概率,该概率可以计算出来。5、uuid5()——基于名字的SHA-1散列值

算法与uuid3相同,不同的是使用 Secure Hash Algorithm1 算法

View Code

使用方面:

首先,Python中没有基于DCE的,所以uuid2可以忽略;

其次,uuid4存在概率性重复,由无映射性,最好不用;

再次,若在Global的分布式计算环境下,最好用uuid1;

最后,若有名字的唯一性要求,最好用uuid3或uuid5。

View Code

编码方法:

#-*- coding: utf-8 -*-

importuuid

name= "test_name"namespace= "test_namespace"

print(uuid.uuid1()) #带参的方法参见Python Doc

print(uuid.uuid3(namespace, name))print(uuid.uuid4())print(uuid.uuid5(namespace, name))

View Code

修改urls.py,增加路径form_data_upload,用来和ajax交互的

urlpatterns =[

path('admin/', admin.site.urls),

path('index/', views.index),

path('upload_file/', views.upload_file),

path('form_data_upload/', views.form_data_upload),

]

View Code

修改upload_file视图函数,使用uuid,完整代码如下:

importosimportjsonimportuuidfrom django.shortcuts importrender,HttpResponsefrom upload_file import settings #导入settings。注意:upload_file为项目名

#Create your views here.

defindex(request):if request.method == "GET":return render(request,'index.html')

user= request.POST.get('user')#获取文件对象,必须使用request.FILES.get

avatar = request.FILES.get('avatar')print(user)print(avatar,type(avatar))print(avatar.__dict__) #查看对象所有属性

#文件存储的绝对路径

path = os.path.join(settings.BASE_DIR, "static", "upload", avatar.name)

with open(path,'wb') as f:#将大文件分割成若干小文件处理,处理完每个小文件后释放该部分内存

for line inavatar.chunks():

f.write(line)#写入文件

return HttpResponse('上传成功')defupload_file(request):if request.method == "GET":return render(request, 'upload_file.html')#直接获取图片地址即可,因为ajax已经将图片上传了

avatar = request.POST.get('avatar')

user= request.POST.get('user')print(avatar,user)return HttpResponse("上传成功")defform_data_upload(request):"""ajax上传文件

:param request:

:return:"""img_upload= request.FILES.get('img_upload') #获取文件对象

#生成随机文件名

file_name = str(uuid.uuid4()) + "." + img_upload.name.rsplit('.', maxsplit=1)[1]#文件保存到static下的images目录

img_file_path = os.path.join('static', 'images', file_name)

with open(img_file_path,'wb') as f: #写入问题

for line inimg_upload.chunks():

f.write(line)#因为ajax发送的图片路径的static前面没有带/,所以这里要拼接一下

return HttpResponse(os.path.join("/",img_file_path))

View Code

修改upload_file.html,要全部修改

Title

点击图片更换( 撤销)
{% csrf_token %}

bindChangeAvatar3();

});

function bindChangeAvatar3() {

$('#avatarImg').change(function () {

var csrf= $("[name=csrfmiddlewaretoken]").val();

var file_obj=$(this)[0].files[0];

var formdata=new FormData();

formdata.append('img_upload', file_obj);

formdata.append("csrfmiddlewaretoken",csrf);

$.ajax({

url:'/form_data_upload/',

type:'POST',

data: formdata,

processData: false,// tell jQuery notto process the data

contentType: false,// tell jQuery notto set contentType

success: function (arg) {//给img标签设置src属性,预览

console.log(arg);

$('#previewImg').attr('src',arg);

console.log(arg);

var avatar= $('#avatar').val(arg);

console.log(avatar);//打印头像地址,用于后续表单提交

}

})

})

}

View Code

访问网页,上传一张图片

点击提交,提示上传成功

查看upload目录,会多一个文件 d405ecde-59bc-40f0-a2eb-c8dfe8c8645f.jpg

注意:form_data_upload和upload_file虽然都处理了POST数据。但是它们接收的数据是不一样的!

用户点击上传时,走form_data_upload视图函数,将图片上传到服务器

用户点击提交时,将服务器的图片url地址和用户名提交给upload_file视图函数。

为什么呢?因为用户点击上传时,已经将图片上传到服务器了。所以点击提交按钮时,需要再将图片上传一次。

只需要将图片的url地址传给服务器即可!

iframe

所有浏览器都支持 标签,它是兼容性最好的一种方式

iframe 元素会创建包含另外一个文档的内联框架(即行内框架)

举例:内嵌汽车之家

创建文件iframe.html

Title

View Code

直接使用谷歌浏览器打开,效果如下:

它直接内嵌了一个网页,如果width和height设置合理的话,打开网页,将会和汽车直接,是一摸一样的。

举例2:输入什么地址,就跳转什么地址

修改iframe.html,增加一个输入框,加入一段js代码。

Title

var addr= document.getElementById("addr").value;//修改iframe的src的值

document.getElementById("ifr").src =addr;

}

View Code

访问页面,效果如下:

注意:整体页面并没有刷新,只是iframe里面刷新了!

它有2个应用场景:

1. iframe标签

可以修改src,且页面不刷新

2. form表单

提交表单数据,但刷新数据

修改urls.py,增加路径

urlpatterns =[

path('admin/', admin.site.urls),

path('index/', views.index),

path('upload_file/', views.upload_file),

path('form_data_upload/', views.form_data_upload),

path('iframe_upload_img/', views.iframe_upload_img),

path('upload_iframe/', views.upload_iframe),

]

View Code

修改views.py,增加视图函数

defiframe_upload_img(request):if request.method == "GET":return render(request,'iframe_upload_img.html')

USER_LIST= [] #空列表

user = request.POST.get('user')

pwd= request.POST.get('pwd')

avatar= request.POST.get('avatar')#最加到列表中

USER_LIST.append(

{'user':user,'pwd':pwd,'avatar':avatar

}

)return HttpResponse("上传成功")def upload_iframe(request): #iframe post提交

ret = {'status':True,'data':None}try:

avatar= request.FILES.get('avatar')

file_name= str(uuid.uuid4()) + "." + avatar.name.rsplit('.', maxsplit=1)[1]

img_file_path= os.path.join('static', 'upload', file_name)

with open(img_file_path,'wb') as f:for line inavatar.chunks():

f.write(line)

ret['data'] = os.path.join("/",img_file_path)exceptException as e:

ret['status'] =False

ret['error'] = '上传失败'

return HttpResponse(json.dumps(ret))

View Code

增加iframe_upload_img.html

Title
{% csrf_token %}
{% csrf_token %}

bindChangeAvatar4();

});

function bindChangeAvatar4() {

$('#avatar').change(function () {//parent该变量指的是包含当前分割窗口的父窗口

$(this).parent().submit();//onload 事件会在页面或图像加载完成后立即发生

$('#ifr')[0].onload =function (){//获取post返回值,比如{"status": true, "data": "/static\\upload\\bc72823e-b274-4a76-8ec2-af844a738959.jpg"}

var iframeContents= $('#ifr')[0].contentWindow.document.body.innerText;

console.log(iframeContents);//反向序列化数据

iframeContents=JSON.parse(iframeContents);if(iframeContents.status) {//修改图片的src属性

$('#prevImg').attr('src', iframeContents.data);//修改隐藏输入框的值

$('#formAvatar').val(iframeContents.data);

}

}

})

}

View Code

访问url:  http://127.0.0.1:8000/iframe_upload_img/

上传一个图片

点击提交,提示上传成功

查看upload目录,会多一个文件 de83205e-2e8b-4839-a1c4-19656df9c49f.jpg

总结:

1. 在浏览器端可以做图片预览-createObjectURL-FileReader2. 使用Ajax上传文件:-FormData对象3. 伪ajax上传文件:-iframe-form4. 图片预览

本质就是修改img的src数据5. 使用场景:

a. 文件上传-FormData对象-iframe

b. 图片预览-createObjectURL、FileReader- iframe

文件上传场景:

假如是政府,或者传统企业,使用最后一种

假如是互联网企业,使用第3种!

三、CBV

CBV(class base views) 就是在视图里使用类处理请求

之前我们写的视图函数,都是FBV(function base views)

路径url的配置

cbv 顾名知义就是通过类的方法来调用,我们在url中配置为如下路径

path('user/', views.UserView.as_view()),

这里的UserView是一个class 类,View不是必须的。一般约定成俗,会加一个View!

要想使用此方法,这个路径后面还得必须有一个as_view()这个是必须的固定格式

views里面函数的格式

在views里面配置类,需要导入一个模块View

from django.views importView#这里必须要继承View这个类,只有继承了这个url那里的as_view()才会有这个方法

classUserView(View):defget(self, request):return HttpResponse('cbv-get')defpost(self, request):return HttpResponse('cbv-post')

View Code

注意:get和post的方法名,必须是小写。因为在源码中,使用了request.method.lower(),通过反射来找到类中的方法!

详情请参考下面的内容

get方式访问

post方式访问

login登陆页面

修改views.py

from django.views importView#这里必须要继承View这个类,只有继承了这个url那里的as_view()才会有这个方法

classUserView(View):defget(self, request):#return HttpResponse('cbv-get')

return render(request, 'login.html') #发送到login.html

defpost(self, request):return HttpResponse('cbv-post')

View Code

新建login.html

Title{% csrf_token %}

View Code

访问页面,点击提交

输出:

这里通过查看View的源码,可以看到里面会有很多种提交方法

http_method_names= ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']

使用ajax的时候这些方法都是可以使用的。

cbv匹配原理

这种根据url来匹配方法的是通过反射方法(getattr)来做的。请求过来后先走dispatch这个方法,这个方法存在View类中。

def dispatch(self, request, *args, **kwargs):#Try to dispatch to the right method; if a method doesn't exist,

#defer to the error handler. Also defer to the error handler if the

#request method isn't on the approved list.

if request.method.lower() inself.http_method_names:

handler=getattr(self, request.method.lower(), self.http_method_not_allowed)else:

handler=self.http_method_not_allowedreturn handler(request, *args, **kwargs)

request.method.lower() 将请求方式变成小写。通过反射来找到类中对应的方法!

所有的框架,本质都是通过请求方式,反射不同的函数!

所以CBV的本质,实际还是用的FBV,只不过了类封装而已!

定制dispatch

如果需要批量对方法,例如get,post等方法做一些操作的时候,这里我们可以手动写一个dispatch,这个dispatch就和装饰器的效果一样。因为请求来的时候总是先走的dispatch。

from django.views importView#这里必须要继承View这个类,只有继承了这个url那里的as_view()才会有这个方法

classUserView(View):def dispatch(self, request, *args, **kwargs):print('操作前的代码...')

obj= super(UserView, self).dispatch(request, *args, **kwargs)print('操作后的代码...')returnobjdefget(self, request):#return HttpResponse('cbv-get')

return render(request, 'login1.html') #发送到login.html

defpost(self, request):return HttpResponse('cbv-post')

View Code

这次我们再通过浏览器访问的时候,发现不管get或者post方法,都会走print代码

四、python读写Excel

python操作excel主要用到xlrd和xlwt这两个库,即xlrd是读excel,xlwt是写excel的库。

需要安装2个模块

pip3 install xlrd

pip3 install xlwt

读excel-->xlrd

新建一个excel,文件名为fruits.xlsx,内容如下:

抛开django框架,新建一个test.py文件

importxlrd#打开excel文件,创建一个workbook对象,book对象也就是fruits.xlsx文件,表含有sheet名

rbook=xlrd.open_workbook(r'C:\Users\xiao\Desktop\fruits.xlsx')#sheets方法返回对象列表,[]

rbook.sheets()#xls默认有3个工作簿,Sheet1,Sheet2,Sheet3

rsheet=rbook.sheet_by_index(0) #取第一个工作簿#获取总行数

rows=rsheet.nrows#获取总列数

cols=rsheet.ncolsprint('行数:',rows,'列数',cols)#通过cell的位置坐标取得cell值

cell=rsheet.cell(0,0)print('0,0坐标的值是:',cell.value)print('3,1坐标的值是:',rsheet.cell(3,1).value)#取得第二行的值,参数是(行数,起点,终点)

row1=rsheet.row_values(1)print('第一行的值是:',row1)

View Code

执行输出:

行数: 4 列数 2

0,0坐标的值是: 名称

3,1坐标的值是: 0.5

第一行的值是: ['西瓜', 0.3]

注意:a1单元格的坐标为0,0。在xlrd模块里面,坐标都是数字,所以不能用a1表示。

坐标如下:

A,B,C纵坐标分别为0,1,2

所以3,1坐标的值是最后一行的价格,也就是0.5

循环工作簿的所有行和列

在末尾增加以下代码

#循环工作簿的所有行

for row inrsheet.get_rows():#循环一行的所有列

for col inrow:#获取一个单元格中的值

print(col.value)

View Code

执行输出:

名称

价格/斤

西瓜

0.3

脐橙

3.5

黄金梨

0.5

写excel-->xltw

importxlwt

f=xlwt.Workbook()

sheet1= f.add_sheet('学生',cell_overwrite_ok=True)

row0= ["姓名","年龄","出生日期","爱好"]

colum0= ["张三","李四","王五"]#写第一行

for i inrange(0,len(row0)):

sheet1.write(0,i,row0[i])#写第一列

for i inrange(0,len(colum0)):

sheet1.write(i+1,0,colum0[i])#写入一行数据

sheet1.write(1,1,"23")

sheet1.write(1,2,"1990")

sheet1.write(1,3,"女")

f.save('test.xls')

View Code

执行程序,查看excel文件

OpenPyXL

由于xlrd不能对已存在的xlsx文件,进行修改!所以必须使用OpenPyXL

OpenPyXL:较好的支持对xlsx文件的修改,功能比较强大,适用于需要处理XLSX文件,需要修改XLSX文件中的值,最后生成xlsx。openpyxl(可读写excel表)专门处理Excel2007及以上版本产生的xlsx文件,xls和xlsx之间转换容易

注意:如果文字编码是“gb2312” 读取后就会显示乱码,请先转成Unicode。

官网上最推荐的是openpyxl:

综上,所以选择使用OpenPyX来做一个修改excel的小程序。

OpenPyXL的官网参考:

https://openpyxl.readthedocs.io/en/latest/usage.html

https://openpyxl.readthedocs.io/en/stable/

1、OpenPyXL模块的安装

pip3 install openpyxl

2、快速实现xlsx文件的单元格修改

举例:增加一列地区,并增加相应的值

from openpyxl importload_workbook#excel文件绝对路径

file_home = r'C:\Users\xiao\Desktop\fruits.xlsx'wb= load_workbook(filename= file_home) #打开excel文件

sheet_ranges = wb['Sheet1']print(sheet_ranges['A1'].value) #打印A1单元格的值

ws = wb['Sheet1'] #根据Sheet1这个sheet名字来获取该sheet

ws["C1"] = '地区' #修改C1的值为LJK5679842

ws['C2'] = '湖北'ws['C3'] = '云南'ws['C4'] = '四川'wb.save(file_home)#保存修改后的excel

View Code

执行代码,查看excel文件

五、虚拟环境virtualenv

windows 安装

安装模块virtualenv

pip3 install virtualenv

安装纯净环境

–no-site-packages表示不包括系统全局的Python安装包,这样会更令环境更干净

E:\python_script>virtualenv --no-site-packages pure_venv

Using base prefix'c:\\python35'New python executableinE:\python_script\pure_venv\Scripts\python.exe

Installing setuptools, pip, wheel...done.

E:\python_script>cd pure_venv

E:\python_script\pure_venv>cd Scripts

激活虚拟环境

E:\python_script\pure_venv\Scripts>activate.bat

查看当前模块列表

(pure_venv) E:\python_script\pure_venv\Scripts>pip3 list

Package Version---------- -------pip10.0.1setuptools40.0.0

wheel0.31.1

安装指定版本的django

(pure_venv) E:\python_script\pure_venv\Scripts>pip3 install django==1.11

打开Pcharm,新建一个django项目

点击...

选择虚拟环境,点击...

选择虚拟目录的python.exe

选择刚才添加的虚拟环境

创建项目之后,发现url就是老版本的了!

pip安装包临时指定 从国内的清华pip源下载:

pip install django==1.11.11 -i https://pypi.tuna.tsinghua.edu.cn/simple

将虚拟环境的依赖包关系导出到requirements.txt

pip freeze > requirements.txt

注意:约定成熟使用requirements.txt,一些开源的django项目,里面一般使用这个名字!

查看requirements.txt文件,内容如下:

Django==1.11.11

pytz==2018.5

如果需要按照 requirements.txt 安装项目依赖的第三方包,使用命令:

pip install -r requirements.txt

新建一个虚拟环境,测试一下,就可以了!

linux安装

#安装virtualenv

/usr/local/python3.5/bin/pip3 install virtualenv#创建虚拟目录

mkdir /virtualenvs

cd/virtualenvs#创建虚拟环境#-p 指定python版本#–no-site-packages表示不包括系统全局的Python安装包,这样会更令环境更干净

/usr/local/python3.5/bin/virtualenv -p /usr/local/python3.5/bin/python3.5 --no-site-packages venv

指定豆瓣源

#创建目录

mkdir ~/.pip#编辑配置文件

vi ~/.pip/pip.conf

内容如下:

[global]

index-url = http://pypi.douban.com/simple

trusted-host = pypi.douban.com

安装相关模块

#django指定版本为1.11

/virtualenvs/venv/bin/pip3 install django==1.11

#rest-framework

/virtualenvs/venv/bin/pip3 install djangorestframework#监控内存模块

/virtualenvs/venv/bin/pip3 install memory_profiler

作业:

1.客户表,放到excel文件中。使用excel上传,将数据导入到数据中!

2.增加登录页面

答案:

1.excel文件上传

新建一个excel文件,比如客户表.xlsx,内容如下:

新建一个项目excel_upload

操作excel,需要安装2个模块。xlrd用来读取,xlwt用来写入!

pip3 install xlrd

pip3 install xlwt

修改settings.py,增加static路径

STATIC_URL = '/static/'STATICFILES_DIRS=(

os.path.join(BASE_DIR,'static'),

)

View Code

新建目录static,在里面创建2个目录,js和file。file用来存放上传的excel文件

将jquery.min.js放到js目录中!

修改models.py,增加客户表模型

from django.db importmodels#Create your models here.

classCustomer(models.Model):

name= models.CharField(max_length=32,verbose_name="姓名")

age= models.IntegerField(verbose_name="年龄")

email= models.CharField(max_length=32,verbose_name="邮箱")

company= models.CharField(max_length=32,verbose_name="公司")

View Code

使用2个命令,生成表

python manage.py makemigrations

python manage.py migrate

修改urls.py,增加2个路径

from app01 importviews

urlpatterns=[

path('admin/', admin.site.urls),

path('upload_file/', views.upload_file),

path('index/', views.index),

]

View Code

修改views.py,增加视图函数

importosimportuuidimportxlrdfrom app01 importmodelsfrom excel_upload importsettingsfrom django.shortcuts importrender, HttpResponse, redirectfrom django.core.paginator importPaginator, EmptyPage, PageNotAnInteger#Create your views here.

def upload_file(request): #上传文件

if request.method == "GET":return render(request, 'upload_file.html')

user= request.POST.get('user')

file_upload= request.FILES.get('customer_excel') #获取excel文件对象

#判断上传的文件后缀

if file_upload.name.rsplit('.', maxsplit=1)[1] not in ['xls','xlsx']:return HttpResponse('上传失败,只能上传xls格式')#生成唯一的文件名

file_name = str(uuid.uuid4()) + '.' + file_upload.name.rsplit('.', maxsplit=1)[1]#拼接路径

img_file_path = os.path.join('static', 'files', file_name)print(img_file_path)

with open(img_file_path,'wb') as f: #写入文件

for line infile_upload.chunks():

f.write(line)#拼接excel文件的绝对路径

file_path =os.path.join(settings.BASE_DIR, img_file_path)print(file_path)#打开excel表

data =xlrd.open_workbook(file_path)

table= data.sheet_by_index(0) #读取第一个sheet

nrows = table.nrows #获得总行数

date_list = [] #定义空列表,用来批量插入

try:for i in range(1, nrows): #读取每一行数据

rows = table.row_values(i) #行的数据放在数组里

#生成对象

obj_list = models.Customer(name=rows[0],

age=rows[1],

email=rows[2],

company=rows[3],

)#追加到列表中

date_list.append(obj_list)#使用bulk_create批量插入

models.Customer.objects.bulk_create(date_list)exceptException as e:return HttpResponse('批量添加失败{}'.format(e))return redirect('/index/') #跳转首页

def index(request): #首页展示数据

customer_list = models.Customer.objects.all() #读取表中的所有数据

#print()

paginator = Paginator(customer_list, 20) #每页显示2条

#异常判断

try:#当前页码,如果取不到page参数,默认为1

current_num = int(request.GET.get("page", 1)) #当前页码

customer_list = paginator.page(current_num) #获取当前页码的数据

except EmptyPage: #页码不存在时,报EmptyPage错误

customer_list = paginator.page(1) #强制更新为第一页

#如果页数十分多时,换另外一种显示方式

if paginator.num_pages > 9: #一般网页展示11页,左5页,右5页,加上当前页,共11页

if current_num - 4 < 1: #如果前5页小于1时

pageRange = range(1, 9) #页码的列表:范围是初始状态

elif current_num + 4 > paginator.num_pages: #如果后5页大于总页数时

#页码的列表:范围是(当前页-5,总页数+1)。因为range顾头不顾尾,需要加1

pageRange = range(current_num - 4, paginator.num_pages + 1)else:#页码的列表:后5页正常时,页码范围是(当前页-5,当前页+6)。注意不是+5,因为range顾头不顾尾!

pageRange = range(current_num - 4, current_num + 5)else:

pageRange= paginator.page_range #页码的列表

data= {"customer_list": customer_list, "paginator": paginator, "current_num": current_num, "pageRange": pageRange}return render(request, "index.html", data)

View Code

创建文件index.html

Title

编号姓名年龄邮箱公司

{% for customer in customer_list %}{{ forloop.counter }}{{ customer.name }}{{ customer.age }}{{ customer.email }}{{ customer.company }}{% endfor %}{#分页展示#}
  • 首页{#has_previous 判断是否有上一页#}

{% if customer_list.has_previous %}

{#previous_page_number 上一页的页码#}

aria-hidden="true">上一页

{% else %}

{#class="disabled" 禁止用户点击#}

上一页{% endif %}

{#遍历页码的列表#}

{% for i in pageRange %}

{#判断当前页码数等于底部页码时#}

{% if current_num == i %}

{#增加class,加深按钮#}

{{ i }}{% else %}

{#href参数为简写,它会自动获取当前路径,并拼接参数#}

{{ i }}{% endif %}

{% endfor %}

{#has_next 判断是否有下一页#}

{% if customer_list.has_next %}

{#next_page_number 下一页的页码#}

aria-hidden="true">下一页

{% else %}

{#class="disabled" 禁止用户点击#}

下一页{% endif %} 最后一页

View Code

创建文件upload_file.html

Title{% csrf_token %}

点击上传文件

$(function () {

$('#excelFile').change(function (e) {

var fileName=e.currentTarget.files[0].name;

$(this).prev().find('span').text(fileName);

})

})

View Code

启动django项目,访问页面

上传一个excel文件

成功后,会跳转首页

2.登录页面

创建超级用户

python manage.py createsuperuser

完整代码在github:

登录效果如下:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值