轉:django中excel匯入匯出
阿新 • • 發佈:2020-07-28
django匯入匯出excel實踐
目錄
正文
回到頂部一、xlrd和xlwt模組介紹
xlrd模組提供在任何平臺上從excel電子表格(.xls和.xlsx)中提取資料的功能,xlwt模組提供生成與Microsoft Excel 95 到2003版本相容的excel檔案的功能。
1、安裝方法
# 方法一: pip3 install xlrd pip3 install xlwt # 方法二: 在python官網http://pypi.python.org/pypi/xlrd/(xlwt)下載xlrd/xlwt的安裝包。 壓縮包放置在python安裝目錄下python/Lib/site-packages。 解壓壓縮包:tar zxvf xlrd-1.0.0.tar.gz 進入到解壓的資料夾:cd xlrd-1.0.0 執行命令:python setup,py install
2、xlrd使用詳解
(1)excel文件準備
準備excel文件:聯絡人.xls,內容如下所示:
(2)xlrd獲取sheet工作表名稱和物件
import xlrd # 開啟Excel檔案讀取器,加上utf-8編碼可防止遇到中文字元亂碼 data = xlrd.open_workbook('聯絡人.xls', encoding_override='utf-8') # 獲取所有sheet工作表名稱 sheetnames = data.sheet_names() print(sheetnames) """ ['銀行1', '銀行2'] """ # 通過索引獲取指定sheet工作表名稱 sheet_name = data.sheet_names()[1] print(sheet_name) """ 銀行2 """ # 通過工作表名稱獲取sheet物件 table_name = data.sheet_by_name(sheet_name) print(table_name) """ <xlrd.sheet.Sheet object at 0x10b657160> """ # 通過sheet索引獲取sheet工作表物件 table_index = data.sheet_by_index(0) print(table_index) """ <xlrd.sheet.Sheet object at 0x1073b3f28> """
(3)sheet工作表行/列操作
# 獲取行數和列數 nrows = table_name.nrows # 總行數 ncols = table_name.ncols # 總列數 print("銀行2表,總行數: %s,總列數: %s" % (nrows, ncols)) """ 銀行2表,總行數: 5,總列數: 7 """ # 根據sheet物件獲取整行和整列的值 sheet_row_val = table_name.row_values(3) sheet_col_val = table_name.col_values(3) print("整行的值:%s , \n整列的值: %s" % (sheet_row_val, sheet_col_val)) """ 整行的值:['', '李九', '開發', 'IOS開發', 87888.0, 13213123.0, '[email protected]'] , 整列的值: ['', '工作職責', 'UI設計', 'IOS開發', '硬體維護'] """ # 獲取當前行的有效單元格長度 print(table_name.row_len(3)) print(table_index.row_len(3)) """ 7 8 """
(4)sheet工作表單元格操作
單元格是組成表格的最小單位,可以拆分或合併。每個資料的輸入和修改都是在單元格中進行的。
# 獲取指定單元格內容 print(table_name.cell(1,0).value) # 第二行第一列 print(table_name.cell_value(2,1)) # 第三行第二列 print(table_name.row(1)[0].value) # 第二行第一列 """ 機構名稱 張八 機構名稱 """ # 獲取單元格內容的資料型別 # ctype說明:0 empty, 1 string, 2 number, 3 date, 4 boolean, 5 error print(table_index.cell(1,0).ctype) # 銀行1表,2行1列內容 機構名稱 print(table_index.cell(3,4).ctype) # 銀行1表,4行5列內容 888 print(table_index.cell(2,6).ctype) # 銀行1表,3行7列內容 2019/5/7 """ 1 2 3 """ # 日期單元格內容處理 from datetime import datetime, date if table_index.cell(2,6).ctype == 3: print(table_index.cell(2, 6).value) date_value = xlrd.xldate_as_tuple(table_index.cell(2, 6).value, data.datemode) print(date_value) print(date(*date_value[:3])) print(date(*date_value[:3]).strftime('%Y/%m/%d')) """ 43592.0 (2019, 5, 7, 0, 0, 0) 2019-05-07 2019/05/07 """ # 獲取number型別的單元格內容 if table_index.cell(3, 4).ctype == 2: print(table_index.cell(3, 4).value) num_value = int(table_index.cell(3, 4).value) # 轉為整型 print(num_value) """ 888.0 888 """
(5)獲取合併單元格內容
需要使用merged_cells屬性,獲取merged_cells返回的row和col低位的索引即可。
# 需要在讀取檔案時新增formatting_info引數,預設是False # 需要設定為True,才能呼叫merged_cells屬性獲取到值 xls_data = xlrd.open_workbook('聯絡人.xls', formatting_info=True) sheet_data = xls_data.sheet_by_name('銀行2') print(sheet_data.merged_cells) """ [(0, 1, 0, 7), (2, 5, 0, 1)] """
merged_cells返回的這四個引數的含義:(row,row_range,col,col_range)。
因此,(0,1,0,7)表示第1列~第7列合併;(2,5,0,1)表示第3行~第6行合併。
# 分別獲取合併兩個單元格內容 merge_value = [] for (row, row_range, col, col_range) in sheet_data.merged_cells: merge_value.append((row, col)) """ [(0, 0), (2, 0)] """ print(merge_value) for i in merge_value: print(sheet_data.cell(i[0], i[1]).value) """ 銀行2 銀行2 """
3、xlwt使用詳解
使用xlwt模組對Excel檔案進行建立、設定、儲存等操作。
import xlwt # 建立一個工作簿(workbook),並設定編碼 # workbook = xlwt.Workbook(encoding='ascii') workbook = xlwt.Workbook(encoding='utf-8') # 建立一個工作表(worksheet) worksheet = workbook.add_sheet("My Worksheet") # 樣式設定(可選) style = xlwt.XFStyle() # 初始化樣式 font = xlwt.Font() # 為樣式建立字型 font.name = "Times New Roman" font.bold = True # 加粗 font.underline = True # 下劃線 font.italic = True # 斜體字 style.font = font # 設定樣式 # 寫入excel,引數對應 行 列 值 # 不帶樣式的寫入 worksheet.write(1,0, 'Unformatted value') # 帶樣式的寫入 worksheet.write(2,0, 'Formatted value', style) # 儲存檔案 workbook.save("xlwt_test.xls")
開啟Excel檔案顯示效果如下:
(1)設定單元格寬度
import xlwt workbook = xlwt.Workbook() worksheet = workbook.add_sheet('My Sheet') worksheet.write(0, 0,'My Cell Contents') # 設定單元格寬度 worksheet.col(0).width = 30003 workbook.save('cell_width.xls')
顯示效果:
(2)輸入日期到單元格
import xlwt import datetime workbook = xlwt.Workbook() worksheet = workbook.add_sheet('My Sheet') style = xlwt.XFStyle() style.num_format_str = 'M/D/YY' # Other options: D-MMM-YY, D-MMM, MMM-YY, h:mm, h:mm:ss, h:mm, h:mm:ss, M/D/YY h:mm, mm:ss, [h]:mm:ss, mm:ss.0 worksheet.write(0, 0, datetime.datetime.now(), style) workbook.save('Excel_Workbook.xls')
顯示效果:
(3)新增公式到單元格
import xlwt workbook = xlwt.Workbook() worksheet = workbook.add_sheet('My Sheet') worksheet.write(0, 0, 5) # Outputs 5 worksheet.write(0, 1, 2) # Outputs 2 # 新增公式 worksheet.write(1, 0, xlwt.Formula('A1*B1')) # Should output "10" (A1[5] * A2[2]) worksheet.write(1, 1, xlwt.Formula('SUM(A1,B1)')) # Should output "7" (A1[5] + A2[2]) workbook.save('Excel_formula.xls')
顯示效果:
(4)新增超連結到單元格
import xlwt workbook = xlwt.Workbook() worksheet = workbook.add_sheet('My Sheet') worksheet.write(0, 0, xlwt.Formula('HYPERLINK("http://www.baidu.com";"Baidu")')) # Outputs the text "Baidu" linking to http://www.baidu.com workbook.save('Excel_hyperlink.xls')
顯示效果:
(5)合併列和行
import xlwt workbook = xlwt.Workbook() worksheet = workbook.add_sheet('My Sheet') worksheet.write_merge(0, 0, 0, 3, 'First Merge') # Merges row 0's columns 0 through 3. font = xlwt.Font() # Create Font font.bold = True # Set font to Bold style = xlwt.XFStyle() # Create Style style.font = font # Add Bold Font to Style worksheet.write_merge(1, 2, 0, 3, 'Second Merge', style) # Merges row 1 through 2's columns 0 through 3. workbook.save('Excel_merge.xls')
顯示效果:
(6)其他單元格設定
""" 設定單元格內容的對其方式: """ import xlwt workbook = xlwt.Workbook() worksheet = workbook.add_sheet('My Sheet') alignment = xlwt.Alignment() # Create Alignment alignment.horz = xlwt.Alignment.HORZ_CENTER # May be: HORZ_GENERAL, HORZ_LEFT, HORZ_CENTER, HORZ_RIGHT, HORZ_FILLED, HORZ_JUSTIFIED, HORZ_CENTER_ACROSS_SEL, HORZ_DISTRIBUTED alignment.vert = xlwt.Alignment.VERT_CENTER # May be: VERT_TOP, VERT_CENTER, VERT_BOTTOM, VERT_JUSTIFIED, VERT_DISTRIBUTED style = xlwt.XFStyle() # Create Style style.alignment = alignment # Add Alignment to Style worksheet.write(0, 0, 'Cell Contents', style) workbook.save('Excel_Workbook.xls') """ 為單元格議新增邊框: """ # Please note: While I was able to find these constants within the source code, on my system (using LibreOffice,) I was only presented with a solid line, varying from thin to thick; no dotted or dashed lines. import xlwt workbook = xlwt.Workbook() worksheet = workbook.add_sheet('My Sheet') borders = xlwt.Borders() # Create Borders borders.left = xlwt.Borders.DASHED DASHED虛線 NO_LINE沒有 THIN實線 # May be: NO_LINE, THIN, MEDIUM, DASHED, DOTTED, THICK, DOUBLE, HAIR, MEDIUM_DASHED, THIN_DASH_DOTTED, MEDIUM_DASH_DOTTED, THIN_DASH_DOT_DOTTED, MEDIUM_DASH_DOT_DOTTED, SLANTED_MEDIUM_DASH_DOTTED, or 0x00 through 0x0D. borders.right = xlwt.Borders.DASHED borders.top = xlwt.Borders.DASHED borders.bottom = xlwt.Borders.DASHED borders.left_colour = 0x40 borders.right_colour = 0x40 borders.top_colour = 0x40 borders.bottom_colour = 0x40 style = xlwt.XFStyle() # Create Style style.borders = borders # Add Borders to Style worksheet.write(0, 0, 'Cell Contents', style) workbook.save('Excel_Workbook.xls') """ 為單元格設定背景色: """ import xlwt workbook = xlwt.Workbook() worksheet = workbook.add_sheet('My Sheet') pattern = xlwt.Pattern() # Create the Pattern pattern.pattern = xlwt.Pattern.SOLID_PATTERN # May be: NO_PATTERN, SOLID_PATTERN, or 0x00 through 0x12 pattern.pattern_fore_colour = 5 # May be: 8 through 63. 0 = Black, 1 = White, 2 = Red, 3 = Green, 4 = Blue, 5 = Yellow, 6 = Magenta, 7 = Cyan, 16 = Maroon, 17 = Dark Green, 18 = Dark Blue, 19 = Dark Yellow , almost brown), 20 = Dark Magenta, 21 = Teal, 22 = Light Gray, 23 = Dark Gray, the list goes on... style = xlwt.XFStyle() # Create the Pattern style.pattern = pattern # Add Pattern to Style worksheet.write(0, 0, 'Cell Contents', style) workbook.save('Excel_Workbook.xls')回到頂部
二、匯出excel表(讀django欄位資料)
在django專案中實現用excel匯出資料庫中資料。
1、新增匯出excel路由
這裡是基於crm專案實現,在customer配置類中新增excel路由:
class CustomerConfig(ModelStark): """程式碼省略""" def extra_url(self): """擴充套件路由""" temp = [] temp.append(url(r"mycustomer/", self.mycustomer)) temp.append(url(r'export/', self.excel_export)) return temp
2、匯出excel檢視函式
# 註冊客戶(學生)到stark class CustomerConfig(ModelStark): """程式碼省略""" def excel_export(self, request): """匯出excel表格""" list_obj = models.Customer.objects.all().order_by("create_time") if list_obj: # 建立工作薄 ws = Workbook(encoding="UTF-8") w = ws.add_sheet(u'資料報表第一頁') w.write(0, 0, 'id') w.write(0, 1, u'姓名') w.write(0, 2, u'性別') w.write(0, 3, u'民族') w.write(0, 4, u'籍貫') w.write(0, 5, u'身份證號') w.write(0, 6, u'通知書郵寄地址') w.write(0, 7, u'郵編') w.write(0, 8, u'聯絡電話') w.write(0, 9, u'聯絡電話2') w.write(0, 10, u'院校') w.write(0, 11, u'專業') w.write(0, 12, u'建立日期') w.write(0, 13, u'生源人') w.write(0, 14, u'備註') # 寫入資料 excel_row = 1 for obj in list_obj: data_id = obj.id data_name = obj.name # data_gender = obj.gender_choices # 只顯示數字 data_gender = obj.get_gender_display() data_nation = obj.nation data_birth = obj.birth_place data_identity_num = obj.identity_num data_address = obj.address data_postcode = obj.postcode data_tel = obj.tel data_tel2 = obj.tel_2 data_school = obj.stu_school.title data_course = obj.course.first().name data_time = obj.create_time.strftime('%Y-%m-%d %H:%M:%S') data_consultant = obj.consultant.name data_memo = obj.memo w.write(excel_row, 0, data_id) w.write(excel_row, 1, data_name) w.write(excel_row, 2, data_gender) w.write(excel_row, 3, data_nation) w.write(excel_row, 4, data_birth) w.write(excel_row, 5, data_identity_num) w.write(excel_row, 6, data_address) w.write(excel_row, 7, data_postcode) w.write(excel_row, 8, data_tel) w.write(excel_row, 9, data_tel2) w.write(excel_row, 10, data_school) w.write(excel_row, 11, data_course) w.write(excel_row, 12, data_time) w.write(excel_row, 13, data_consultant) w.write(excel_row, 14, data_memo) excel_row += 1 # 檢測檔案是否存在 # 方框中程式碼是儲存本地檔案使用,如不需要請刪除該程式碼 ########################### exist_file = os.path.exists("stu_info.xls") if exist_file: os.remove(r"stu_info.xls") ws.save("customer_info.xls") ############################ sio = BytesIO() ws.save(sio) sio.seek(0) response = HttpResponse(sio.getvalue(), content_type='application/vnd.ms-excel') response['Content-Disposition'] = 'attachment; filename=stu_info.xls' response.write(sio.getvalue()) return response
(1)獲取日期並轉化格式
data_time = obj.create_time.strftime('%Y-%m-%d %H:%M:%S')
(2)獲取一對多物件名稱
data_consultant = obj.consultant.name
(3)獲取多對多物件名稱
data_course = obj.course.first().name
3、將註冊的模型類新增到字典_registry中
site.register(models.Customer, CustomerConfig)回到頂部
三、匯入excel表(插入django欄位資料)
匯入時,一對多欄位和多對多欄位處理需要特別注意。
1、新增匯入Excel路由
# 註冊客戶(學生)到stark class CustomerConfig(ModelStark): def extra_url(self): """擴充套件路由""" temp = [] temp.append(url(r"mycustomer/", self.mycustomer)) temp.append(url(r'export/', self.excel_export)) temp.append(url(r'import/', self.excel_import)) return temp
2、匯入Excel檢視函式
# 註冊客戶(學生)到stark class CustomerConfig(ModelStark): """省略程式碼""" def excel_import(self, request): """批量匯入資料""" if request.method == 'GET': return render(request, 'excel_import.html', locals()) # return JsonResponse({'msg': '不是post請求'}) else: user_id = request.session.get("user_id") file_obj = request.FILES.get('my_file') type_excel = file_obj.name.split('.')[1] if 'xls' == type_excel: # 開始解析上傳的excel表格 wb = xlrd.open_workbook(filename=None, file_contents=file_obj.read()) table = wb.sheets()[0] nrows = table.nrows # 行數 # ncole = table.ncols # 列數 try: # 正常的資料庫操作應該是原子性操作 with transaction.atomic(): for i in range(1, nrows): # i/o row_value = table.row_values(i) # 一行的資料 # 新增多對多欄位 # 主要這裡不能使用get,否則報錯:'Course' object is not iterable course_obj = models.Course.objects.filter(name=row_value[9]) print(row_value[10], type(row_value[10])) # 1002.0 <class 'float'> consultant_obj = models.UserInfo.objects.get(code=str(int(row_value[10]))) # 生成學生物件,新增 customer_obj = models.Customer.objects.create( name=row_value[0], gender=row_value[1], nation=row_value[2], birth_place=row_value[3], identity_num=row_value[4], address=row_value[5], postcode=row_value[6], tel=row_value[7], tel_2=row_value[8], stu_school_id=1, create_time=datetime.datetime.now(), consultant=consultant_obj, # 一對多欄位 memo=row_value[11] ) # create的時候不寫多對多欄位,寫完後單獨設定即可 customer_obj.course.set(course_obj) except Exception as e: return HttpResponse('出現錯誤...%s' % e) return HttpResponse("上傳成功") return HttpResponse('上傳檔案格式不是xls')
(1)一對多欄位
consultant欄位是一對多欄位,使用如下方法新增:
consultant_obj = models.UserInfo.objects.get(code=str(int(row_value[10]))) # 生成學生物件,新增 customer_obj = models.Customer.objects.create( """程式碼省略""" consultant=consultant_obj, # 一對多欄位 )
(2)多對多欄位
course欄位是多對多欄位,使用如下方法新增:
# 新增多對多欄位 # 主要這裡不能使用get,否則報錯:'Course' object is not iterable course_obj = models.Course.objects.filter(name=row_value[9]) print(row_value[10], type(row_value[10])) # 1002.0 <class 'float'> # 生成學生物件,新增 customer_obj = models.Customer.objects.create("""程式碼省略""") # create的時候不寫多對多欄位,寫完後單獨設定即可 customer_obj.course.set(course_obj)