feat: excel

This commit is contained in:
han0
2020-11-18 11:27:30 +08:00
parent e2f463dc98
commit 1743bb6301
7 changed files with 223 additions and 0 deletions

View File

View File

@@ -0,0 +1,9 @@
EXCEL_MIME_TYPE = [
'application/excel',
'application/vnd.ms-excel',
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
]
EXCEL_SUFFIX = [
'.xls',
'.xlsx',
]

View File

@@ -0,0 +1,25 @@
class ExcelFormat:
title = {
'font': '黑体', 'font_size': 18, 'bold': True, 'align': 'center', 'valign': 'vcenter',
}
remark = {
'font': '黑体', 'font_size': 8, 'bold': False, 'align': 'right', 'valign': 'vcenter',
'bottom': 1, 'top_color': 'white', 'top': 1,
}
header = {
'font': '宋体', 'font_size': 8, 'bold': True, 'align': 'center', 'valign': 'vcenter',
'border': 1, 'text_wrap': True,
}
body = {
'font': '宋体', 'font_size': 6, 'bold': False, 'align': 'center', 'valign': 'vcenter',
'border': 1, 'text_wrap': True,
}
big_header = {
'font': '宋体', 'font_size': 10, 'bold': False, 'align': 'left', 'valign': 'vcenter',
'border': True, 'text_wrap': False,
}
big_body = {
'font': '宋体', 'font_size': 10, 'bold': False, 'align': 'left', 'valign': 'vcenter',
'border': False, 'text_wrap': False,
}

View File

@@ -0,0 +1,55 @@
import os
import xlrd
from werkzeug.datastructures import FileStorage
from nc_http.core.excel.constants import EXCEL_SUFFIX
from nc_http.core.excel.exceptions import InvalidSuffixError
class ExcelReader(object):
@staticmethod
def read_excel(file_src=None, row_index=0, file_contents=None, sheet_name=None):
if file_src:
data = xlrd.open_workbook(file_src)
elif file_contents:
data = xlrd.open_workbook(file_contents=file_contents)
else:
return []
sheets = data.sheets()
table = sheets[0]
# 根据 sheet 名来选择 sheet可选
if sheet_name:
for sheet in sheets:
if sheet.name == sheet_name:
table = sheet
nrows = table.nrows
rows = []
for rownum in range(row_index, nrows):
row = table.row_values(rownum)
rows.append(row)
return rows
@staticmethod
def read(file_handler):
if isinstance(file_handler, FileStorage):
filename = file_handler.filename.strip(r'"')
suffix = os.path.splitext(filename)[-1]
if suffix not in EXCEL_SUFFIX:
raise InvalidSuffixError
result = ExcelReader.read_excel(file_contents=file_handler.read())
else:
filename = str(file_handler) if not hasattr(file_handler, 'name') else file_handler.name
suffix = os.path.splitext(filename)[-1]
if suffix not in EXCEL_SUFFIX:
raise InvalidSuffixError
result = ExcelReader.read_excel(filename)
return result
if __name__ == '__main__':
s = ExcelReader.read(open(r'D:\test.xlsx'))
print(s)

View File

@@ -0,0 +1,109 @@
from io import BytesIO
from xlsxwriter import Workbook
from nc_http.core.excel.excel_format import ExcelFormat
class ExcelWriter(object):
title_format_setting = ExcelFormat.title
remark_format_setting = ExcelFormat.remark
header_format_setting = ExcelFormat.big_header
body_format_setting = ExcelFormat.big_body
@classmethod
def pack_excel(cls, data=None, **options):
output = BytesIO()
workbook = Workbook(output, {'in_memory': True})
cls.write(workbook, data, **options)
workbook.close()
output.seek(0)
return output
@classmethod
def create_excel(cls, file, data=None, **options):
data = data or []
workbook = Workbook(file)
cls.write(workbook, data, **options)
workbook.close()
return file
@classmethod
def write(cls, workbook, data, headers=None, merges=None, row_stretches=None, col_stretches=None,
paper=None, style_formats=None):
data = data or []
headers = headers or []
if headers:
data = headers + data
if not data:
return
worksheet = workbook.add_worksheet()
worksheet.center_horizontally()
worksheet.set_margins(left=0.2, right=0.2, top=0.4, bottom=0.2)
# worksheet.set_column('A:Z', 20)
# worksheet.set_default_row(16)
if paper:
worksheet.set_paper(paper)
style_formats = style_formats or {}
header_format = style_formats.get('header') or cls.header_format_setting
body_format = style_formats.get('body') or cls.body_format_setting
col_style = {}
if col_stretches:
'''
col_stretches = [
[0, 0, 25, {'text_wrap': True}],
[1, 1, 10],
]
'''
for stretch in col_stretches:
if len(stretch) != 4:
continue
if stretch[0] == stretch[1]:
col_style[stretch[0]] = stretch[3]
elif stretch[0] < stretch[1]:
for col in range(stretch[0], stretch[1] + 1):
col_style[col] = stretch[3]
for row_num in range(len(data)):
row = data[row_num]
if isinstance(row, list):
for col_num in range(len(row)):
column = row[col_num]
if headers and row_num < len(headers):
worksheet.write(row_num, col_num, column, workbook.add_format(header_format.copy()))
else:
# 单元格样式与列样式合并
_body_format = body_format.copy()
if col_style:
_col_style = col_style.get(col_num, {})
_body_format.update(_col_style)
worksheet.write(row_num, col_num, column, workbook.add_format(_body_format))
# 单元格合并
if merges:
for merge in merges:
if len(merge) > 5:
format_item = workbook.add_format(merge[5])
else:
format_item = workbook.add_format(header_format)
worksheet.merge_range(*merge[:5], cell_format=format_item)
# 行高指定
if row_stretches:
for stretch in row_stretches:
worksheet.set_row(*stretch)
# 列宽指定
if col_stretches:
for stretch in col_stretches:
stretch = stretch.copy()
if len(stretch) >= 4:
stretch[3] = workbook.add_format(stretch[3])
worksheet.set_column(*stretch)
if __name__ == '__main__':
ExcelWriter.create_excel(r'E:\test.xlsx', [[1, 2, 2, 2], [1, 2, 2, 2], [1, 2, 2, 2], [1, 2, 2, 2]])
ExcelWriter.pack_excel([[1, 2, 2, 2], [1, 2, 2, 2], [1, 2, 2, 2], [1, 2, 2, 2]])

View File

@@ -0,0 +1,6 @@
class InvalidFileError(Exception):
"""无效的 excel 文件"""
class InvalidSuffixError(InvalidFileError):
"""无效的后缀名"""

19
nc_http/tests/excel.py Normal file
View File

@@ -0,0 +1,19 @@
import unittest
from nc_http.core.excel.excel_reader import ExcelReader
from nc_http.core.excel.excel_writer import ExcelWriter
class ExcelTestCase(unittest.TestCase):
filename = r'D:\test.xlsx'
def test_writer(self):
ExcelWriter.create_excel(self.filename, [[1, 2, 2, 2], [1, 2, 2, 2], [1, 2, 2, 2], [1, 2, 2, 2]])
ExcelWriter.pack_excel([[1, 2, 2, 2], [1, 2, 2, 2], [1, 2, 2, 2], [1, 2, 2, 2]])
def test_reader(self):
ExcelReader.read(open(self.filename))
if __name__ == '__main__':
unittest.main()