亚洲精品久久久中文字幕-亚洲精品久久片久久-亚洲精品久久青草-亚洲精品久久婷婷爱久久婷婷-亚洲精品久久午夜香蕉

您的位置:首頁技術(shù)文章
文章詳情頁

在django項(xiàng)目中導(dǎo)出數(shù)據(jù)到excel文件并實(shí)現(xiàn)下載的功能

瀏覽:71日期:2022-07-06 16:05:46

依賴模塊

xlwt下載:pip install xlwt

后臺模塊

view.py

# 導(dǎo)出Excel文件def export_excel(request): city = request.POST.get(’city’) print(city) list_obj=place.objects.filter(city=city) # 設(shè)置HTTPResponse的類型 response = HttpResponse(content_type=’application/vnd.ms-excel’) response[’Content-Disposition’] = ’attachment;filename=’+city+’.xls’ '''導(dǎo)出excel表''' if list_obj: # 創(chuàng)建工作簿 ws = xlwt.Workbook(encoding=’utf-8’) # 添加第一頁數(shù)據(jù)表 w = ws.add_sheet(’sheet1’) # 新建sheet(sheet的名稱為'sheet1') # 寫入表頭 w.write(0, 0, u’地名’) w.write(0, 1, u’次數(shù)’) w.write(0, 2, u’經(jīng)度’) w.write(0, 3, u’緯度’) # 寫入數(shù)據(jù) excel_row = 1 for obj in list_obj: name = obj.place sum = obj.sum lng = obj.lng lat = obj.lat # 寫入每一行對應(yīng)的數(shù)據(jù) w.write(excel_row, 0, name) w.write(excel_row, 1, sum) w.write(excel_row, 2, lng) w.write(excel_row, 3, lat) excel_row += 1 # 寫出到IO output = BytesIO() ws.save(output) # 重新定位到開始 output.seek(0) response.write(output.getvalue()) return response

前端模塊

<button type='button' >導(dǎo)出excel</button>

$('#export_excel').click(function () { var csrf=$(’input[name='csrfmiddlewaretoken']’).val(); const req = new XMLHttpRequest(); req.open(’POST’, ’/export_excel/’, true); req.responseType = ’blob’; req.setRequestHeader(’Content-Type’, ’application/x-www-form-urlencoded’); //設(shè)置請求頭 req.send(’city=’+$(’#city’).val()+'&&csrfmiddlewaretoken='+csrf); //輸入?yún)?shù) req.onload = function() { const data = req.response; const a = document.createElement(’a’); const blob = new Blob([data]); const blobUrl = window.URL.createObjectURL(blob); download(blobUrl) ; }; });

function download(blobUrl) { var city = $('input[name=’city’]').val(); const a = document.createElement(’a’); a.style.display = ’none’; a.download = ’<文件命名>’; a.href = blobUrl; a.click(); document.body.removeChild(a);}

補(bǔ)充知識:Python Django實(shí)現(xiàn)MySQL百萬、千萬級的數(shù)據(jù)量下載:解決memoryerror、nginx time out

前文

在用Django寫項(xiàng)目的時(shí)候時(shí)常需要提供文件下載的功能,而Django也是貼心提供了幾種方法:FileResponse、StreamingHttpResponse、HttpResponse,其中FileResponse和StreamingHttpResponse都是使用迭代器迭代生成數(shù)據(jù)的方法,所以適合傳輸文件比較大的情況;而HttpResponse則是直接取得數(shù)據(jù)返回給用戶,所以容易造成memoryerror和nginx time out(一次性取得數(shù)據(jù)和返回的數(shù)據(jù)過多,導(dǎo)致nginx超時(shí)或者內(nèi)存不足),關(guān)于這三者,DJango的官網(wǎng)也是寫的非常清楚,連接如下:https://docs.djangoproject.com/en/1.11/ref/request-response/

那正常我們使用的是FileResponse和StreamingHttpResponse,因?yàn)樗鼈兞魇絺鬏?迭代器)的特點(diǎn),可以使得數(shù)據(jù)一條條的返回給客戶端,文件隨時(shí)中斷和復(fù)傳,并且保持文件的一致性。

FileResponse和StreamingHttpResponse

FileResponse顧名思義,就是打開文件然后進(jìn)行傳輸,并且可以指定一次能夠傳輸?shù)臄?shù)據(jù)chunk。所以適用場景:從服務(wù)端返回大文件。缺點(diǎn)是無法實(shí)時(shí)獲取數(shù)據(jù)庫的內(nèi)容并傳輸給客戶端。舉例如下:

def download(request): file=open(’path/demo.py’,’rb’) response =FileResponse(file) response[’Content-Type’]=’application/octet-stream’ response[’Content-Disposition’]=’attachment;filename='demo.py'’ return response

從上可以發(fā)現(xiàn),文件打開后作為參數(shù)傳入FileResponse,隨后指定傳輸頭即可,但是很明顯用這個(gè)來傳輸數(shù)據(jù)庫就不太方便了,所以這邊推介用StreamingHttpResponse的方式來傳輸。

這里就用PyMysql來取得數(shù)據(jù),然后指定為csv的格式返回,具體代碼如下:

# 通過pymysql取得數(shù)據(jù)import pymysqlfield_types = { 1: ’tinyint’, 2: ’smallint’, 3: ’int’} #用于后面的字段名匹配,這里省略了大多數(shù)conn = pymysql.connect(host=’127.0.0.1’,port=3306,database=’demo’,user=’root’,password=’root’)cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)cursor.execute(sql)#獲取所有數(shù)據(jù)data = cursor.fetchall()cols = {}#獲取所有字段for i,row in enumerate(self.cursor.description): if row[0] in cols: cols[str(i)+row[0]] = field_types.get(row[1], str(row[1])) #這里的field_type是類型和數(shù)字的匹配 cols[row[0]] = field_types.get(row[1], str(row[1]))cursor.close()conn.close()#通過StreamingHttpResponse指定返回格式為csvresponse = StreamingHttpResponse(get_result_fromat(data, cols))response[’Content-Type’] = ’application/octet-stream’response[’Content-Disposition’] = ’attachment;filename='{0}'’.format(out_file_name)return response#循環(huán)所有數(shù)據(jù),然后加到字段上返回,注意的是要用迭代器來控制def get_result_fromat(data, cols): tmp_str = '' # 返回文件的每一列列名 for col in cols: tmp_str += ’'%s',’ % (col) yield tmp_str.strip(',') + 'n' for row in data: tmp_str = '' for col in cols: tmp_str += ’'%s',’ % (str(row[col])) yield tmp_str.strip(’,’) + 'n'

整個(gè)代碼如上,大致分為三部分:從mysql取數(shù)據(jù),格式化成我們想要的格式:excel、csv、txt等等,這邊指定的是csv,如果對其他格式也有興趣的可以留言,最后就是用StreamingHttpResponse指定返回的格式返回。

實(shí)現(xiàn)百萬級數(shù)據(jù)量下載

上面的代碼下載可以支持幾萬行甚至十幾萬行的數(shù)據(jù),但是如果超過20萬行以上的數(shù)據(jù),那就比較困難了,我這邊的剩余內(nèi)存大概是1G的樣子,當(dāng)超過15萬行數(shù)據(jù)(大概)的時(shí)候,就報(bào)memoryerror了,問題就是因?yàn)閒etchall,雖然我們StreamingHttpResponse是一條條的返回,但是我們的數(shù)據(jù)時(shí)一次性批量的取得!

如何解決?以下是我的解決方法和思路:

用fetchone來代替fetchall,迭代生成fetchone

發(fā)現(xiàn)還是memoryerror,因?yàn)閑xecute是一次性執(zhí)行,后來發(fā)現(xiàn)可以用流式游標(biāo)來代替原來的普通游標(biāo),即SSDictCursor代替DictCursor

于是整個(gè)代碼需要修改的地方如下:

cursor = conn.cursor(cursor=pymysql.cursors.DictCursor) ===>cursor = conn.cursor(cursor=pymysql.cursors.SSDictCursor)

data = cursor.fetchall() ===>row = cursor.fetchone()

def get_result_fromat(data, cols): tmp_str = '' # 返回文件的每一列列名 for col in cols: tmp_str += ’'%s',’ % (col) yield tmp_str.strip(',') + 'n' for row in data: tmp_str = '' for col in cols: tmp_str += ’'%s',’ % (str(row[col])) yield tmp_str.strip(’,’) + 'n' =====> def get_result_fromat(data, cols): tmp_str = '' for col in cols: tmp_str += ’'%s',’ % (col) yield tmp_str.strip(',') + 'n' while True: tmp_str = '' for col in cols: tmp_str += ’'%s',’ % (str(row[col])) yield tmp_str.strip(’,’) + 'n' row = db.cursor.fetchone() if row is None: break

可以看到就是通過while True來實(shí)現(xiàn)不斷地取數(shù)據(jù)下載,有效避免一次性從MySQL取出內(nèi)存不足報(bào)錯(cuò),又或者取得過久導(dǎo)致nginx超時(shí)!

總結(jié)

關(guān)于下載就分享到這了,還是比較簡單的,謝謝觀看~希望能給大家一個(gè)參考,也希望大家多多支持好吧啦網(wǎng)。

標(biāo)簽: excel
相關(guān)文章:
主站蜘蛛池模板: 日韩高清特级特黄毛片 | 国产大片免费观看中文字幕 | 一级毛片完整免费版 | 手机看片亚洲 | 亚洲一区二区三区高清视频 | 亚洲欧美在线观看首页 | 三级 在线播放 | 成人精品一区二区三区校园激情 | 欧美日韩国产亚洲一区二区三区 | 深夜做爰性大片中文 | 特级aaa毛片| 欧美在线观看一区二区三 | 色综合手机在线 | 国产在线91观看免费观看 | 香蕉视频网站在线 | 91最新免费地址入口 | 国产精品成人免费福利 | 亚洲国产综合专区在线播一一 | 亚洲国产精品看片在线观看 | 91在线免费公开视频 | 一级做a爰片久久毛片16 | 一级在线观看视频 | 国产第一页久久亚洲欧美国产 | 精品国产人成亚洲区 | 三级视频中文字幕 | 亚洲网视频 | 国产特黄一级片 | 国内精品一区视频在线播放 | 日本亚洲黄色 | 日韩毛片在线观看 | 国产福利足控交在线观看 | 欧美日韩一区二区三区久久 | 欧美综合图区亚欧综合图区 | 99热99re8国产在线播放 | 国产在线观看福利一区二区 | 欧美日韩综合在线视频免费看 | 91在线 | 亚洲 | 国产成人黄色 | 日韩欧免费一区二区三区 | 国产精品亚洲精品日韩动图 | 精品国产欧美一区二区 |