最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

 更新時間:2020年03月13日 10:41:11   作者:matrix_theOne  
這篇文章主要介紹了在django項目中導出數(shù)據(jù)到excel文件并實現(xiàn)下載的功能,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧

依賴模塊

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)
  # 設(shè)置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'經(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 id="export_excel" type="button" class="btn btn-primary col-sm-5" style="margin-left: 10px" >導出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);
}

補充知識: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超時或者內(nèi)存不足),關(guān)于這三者,DJango的官網(wǎng)也是寫的非常清楚,連接如下:https://docs.djangoproject.com/en/1.11/ref/request-response/

那正常我們使用的是FileResponse和StreamingHttpResponse,因為它們流式傳輸(迭代器)的特點,可以使得數(shù)據(jù)一條條的返回給客戶端,文件隨時中斷和復傳,并且保持文件的一致性。

FileResponse和StreamingHttpResponse

FileResponse顧名思義,就是打開文件然后進行傳輸,并且可以指定一次能夠傳輸?shù)臄?shù)據(jù)chunk。所以適用場景:從服務(wù)端返回大文件。缺點是無法實時獲取數(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,隨后指定傳輸頭即可,但是很明顯用這個來傳輸數(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ù),那就比較困難了,我這邊的剩余內(nèi)存大概是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取出內(nèi)存不足報錯,又或者取得過久導致nginx超時!

總結(jié)

關(guān)于下載就分享到這了,還是比較簡單的,謝謝觀看~希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • matplotlib.pyplot畫圖并導出保存的實例

    matplotlib.pyplot畫圖并導出保存的實例

    今天小編就為大家分享一篇matplotlib.pyplot畫圖并導出保存的實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-12-12
  • Python實現(xiàn)爬取騰訊招聘網(wǎng)崗位信息

    Python實現(xiàn)爬取騰訊招聘網(wǎng)崗位信息

    這篇文章主要介紹了如何用python爬取騰訊招聘網(wǎng)崗位信息保存到表格,并做成簡單可視化。文中的示例代碼對學習Python有一定的幫助,感興趣的可以了解一下
    2022-01-01
  • Python能做什么

    Python能做什么

    在本篇文章里小編給大家整理的是關(guān)于Python作用領(lǐng)域等相關(guān)知識點,需要的朋友們可以參考下。
    2020-06-06
  • 老生常談Python之裝飾器、迭代器和生成器

    老生常談Python之裝飾器、迭代器和生成器

    下面小編就為大家?guī)硪黄仙U凱ython之裝飾器、迭代器和生成器。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-07-07
  • 基于Python的接口測試框架實例

    基于Python的接口測試框架實例

    下面小編就為大家?guī)硪黄赑ython的接口測試框架實例。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-11-11
  • python中判斷文件結(jié)束符的具體方法

    python中判斷文件結(jié)束符的具體方法

    在本篇文章里小編給大家分享的是一篇關(guān)于python中判斷文件結(jié)束符的具體方法,有興趣的朋友們可以參考學習下。
    2020-08-08
  • python實現(xiàn)猜數(shù)游戲(保存游戲記錄)

    python實現(xiàn)猜數(shù)游戲(保存游戲記錄)

    這篇文章主要為大家詳細介紹了python實現(xiàn)猜數(shù)游戲,保存游戲記錄,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-06-06
  • Python協(xié)程 yield與協(xié)程greenlet簡單用法示例

    Python協(xié)程 yield與協(xié)程greenlet簡單用法示例

    這篇文章主要介紹了Python協(xié)程 yield與協(xié)程greenlet簡單用法,簡要講述了協(xié)程的概念、原理,并結(jié)合實例形式分析了Python協(xié)程 yield與協(xié)程greenlet基本使用方法,需要的朋友可以參考下
    2019-11-11
  • Python中利用aiohttp制作異步爬蟲及簡單應(yīng)用

    Python中利用aiohttp制作異步爬蟲及簡單應(yīng)用

    asyncio可以實現(xiàn)單線程并發(fā)IO操作,是Python中常用的異步處理模塊。這篇文章主要介紹了Python中利用aiohttp制作異步爬蟲的相關(guān)知識,需要的朋友可以參考下
    2018-11-11
  • Python 爬蟲圖片簡單實現(xiàn)

    Python 爬蟲圖片簡單實現(xiàn)

    這篇文章主要介紹了Python 爬蟲圖片簡單實現(xiàn)的相關(guān)資料,需要的朋友可以參考下
    2017-06-06

最新評論

绩溪县| 鄂伦春自治旗| 昌吉市| 哈密市| 曲阳县| 景德镇市| 潍坊市| 类乌齐县| 新绛县| 黔西县| 商水县| 左云县| 深水埗区| 万安县| 榆树市| 夹江县| 凤山县| 南郑县| 开阳县| 祁连县| 颍上县| 阳泉市| 枝江市| 郯城县| 乐业县| 新竹县| 维西| 渭南市| 漳州市| 昂仁县| 博乐市| 桃源县| 眉山市| 泰来县| 永德县| 库车县| 犍为县| 辉南县| 萝北县| 翼城县| 平和县|