這期內容當中小編將會給大家?guī)碛嘘P怎么在django項目中將數(shù)據(jù)導出到excel文件,文章內容豐富且以專業(yè)的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。
依賴模塊
xlwt下載:pip install xlwt
后臺模塊
view.py
# 導出Excel文件 def export_excel(request): city = request.POST.get('city') print(city) list_obj=place.objects.filter(city=city) # 設置HTTPResponse的類型 response = HttpResponse(content_type='application/vnd.ms-excel') response['Content-Disposition'] = 'attachment;filename='+city+'.xls' """導出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'經度') 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 # 寫入每一行對應的數(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 id="export_excel" type="button" class="btn btn-primary col-sm-5" >導出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'); //設置請求頭 req.send('city='+$('#city').val()+"&&csrfmiddlewaretoken="+csrf); //輸入參數(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); }
補充知識:Python Django實現(xiàn)MySQL百萬、千萬級的數(shù)據(jù)量下載:解決memoryerror、nginx time out
前文
在用Django寫項目的時候時常需要提供文件下載的功能,而Django也是貼心提供了幾種方法:FileResponse、StreamingHttpResponse、HttpResponse,其中FileResponse和StreamingHttpResponse都是使用迭代器迭代生成數(shù)據(jù)的方法,所以適合傳輸文件比較大的情況;而HttpResponse則是直接取得數(shù)據(jù)返回給用戶,所以容易造成memoryerror和nginx time out(一次性取得數(shù)據(jù)和返回的數(shù)據(jù)過多,導致nginx超時或者內存不足),關于這三者,DJango的官網也是寫的非常清楚,連接如下:https://docs.djangoproject.com/en/1.11/ref/request-response/
那正常我們使用的是FileResponse和StreamingHttpResponse,因為它們流式傳輸(迭代器)的特點,可以使得數(shù)據(jù)一條條的返回給客戶端,文件隨時中斷和復傳,并且保持文件的一致性。
FileResponse和StreamingHttpResponse
FileResponse顧名思義,就是打開文件然后進行傳輸,并且可以指定一次能夠傳輸?shù)臄?shù)據(jù)chunk。所以適用場景:從服務端返回大文件。缺點是無法實時獲取數(shù)據(jù)庫的內容并傳輸給客戶端。舉例如下:
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,隨后指定傳輸頭即可,但是很明顯用這個來傳輸數(shù)據(jù)庫就不太方便了,所以這邊推介用StreamingHttpResponse的方式來傳輸。
這里就用PyMysql來取得數(shù)據(jù),然后指定為csv的格式返回,具體代碼如下:
# 通過pymysql取得數(shù)據(jù) import pymysql field_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指定返回格式為csv response = 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"
整個代碼如上,大致分為三部分:從mysql取數(shù)據(jù),格式化成我們想要的格式:excel、csv、txt等等,這邊指定的是csv,如果對其他格式也有興趣的可以留言,最后就是用StreamingHttpResponse指定返回的格式返回。
實現(xiàn)百萬級數(shù)據(jù)量下載
上面的代碼下載可以支持幾萬行甚至十幾萬行的數(shù)據(jù),但是如果超過20萬行以上的數(shù)據(jù),那就比較困難了,我這邊的剩余內存大概是1G的樣子,當超過15萬行數(shù)據(jù)(大概)的時候,就報memoryerror了,問題就是因為fetchall,雖然我們StreamingHttpResponse是一條條的返回,但是我們的數(shù)據(jù)時一次性批量的取得!
如何解決?以下是我的解決方法和思路:
用fetchone來代替fetchall,迭代生成fetchone
發(fā)現(xiàn)還是memoryerror,因為execute是一次性執(zhí)行,后來發(fā)現(xiàn)可以用流式游標來代替原來的普通游標,即SSDictCursor代替DictCursor
于是整個代碼需要修改的地方如下:
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來實現(xiàn)不斷地取數(shù)據(jù)下載,有效避免一次性從MySQL取出內存不足報錯,又或者取得過久導致nginx超時!
上述就是小編為大家分享的怎么在django項目中將數(shù)據(jù)導出到excel文件了,如果剛好有類似的疑惑,不妨參照上述分析進行理解。如果想知道更多相關知識,歡迎關注創(chuàng)新互聯(lián)行業(yè)資訊頻道。
文章標題:怎么在django項目中將數(shù)據(jù)導出到excel文件-創(chuàng)新互聯(lián)
URL分享:http://www.rwnh.cn/article20/dohsjo.html
成都網站建設公司_創(chuàng)新互聯(lián),為您提供網站建設、品牌網站設計、網站設計公司、網站排名、面包屑導航、ChatGPT
聲明:本網站發(fā)布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內容