這篇文章主要介紹“怎么使用Python報(bào)表和日志”,在日常操作中,相信很多人在怎么使用Python報(bào)表和日志問(wèn)題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”怎么使用Python報(bào)表和日志”的疑惑有所幫助!接下來(lái),請(qǐng)跟著小編一起來(lái)學(xué)習(xí)吧!
目前累計(jì)服務(wù)客戶(hù)上1000家,積累了豐富的產(chǎn)品開(kāi)發(fā)及服務(wù)經(jīng)驗(yàn)。以網(wǎng)站設(shè)計(jì)水平和技術(shù)實(shí)力,樹(shù)立企業(yè)形象,為客戶(hù)提供成都做網(wǎng)站、成都網(wǎng)站建設(shè)、網(wǎng)站策劃、網(wǎng)頁(yè)設(shè)計(jì)、網(wǎng)絡(luò)營(yíng)銷(xiāo)、VI設(shè)計(jì)、網(wǎng)站改版、漏洞修補(bǔ)等服務(wù)。成都創(chuàng)新互聯(lián)公司始終以務(wù)實(shí)、誠(chéng)信為根本,不斷創(chuàng)新和提高建站品質(zhì),通過(guò)對(duì)領(lǐng)先技術(shù)的掌握、對(duì)創(chuàng)意設(shè)計(jì)的研究、對(duì)客戶(hù)形象的視覺(jué)傳遞、對(duì)應(yīng)用系統(tǒng)的結(jié)合,為客戶(hù)提供更好的一站式互聯(lián)網(wǎng)解決方案,攜手廣大客戶(hù),共同發(fā)展進(jìn)步。
報(bào)表就是用表格、圖表等格式來(lái)動(dòng)態(tài)顯示數(shù)據(jù),所以有人用這樣的公式來(lái)描述報(bào)表:
報(bào)表 = 多樣的格式 + 動(dòng)態(tài)的數(shù)據(jù)
有很多的三方庫(kù)支持在Python程序中寫(xiě)Excel文件,包括xlwt、xlwings、openpyxl、xlswriter、pandas等,其中的xlwt雖然只支持寫(xiě)xls格式的Excel文件,但在性能方面的表現(xiàn)還是不錯(cuò)的。下面我們就以xlwt為例,來(lái)演示如何在Django項(xiàng)目中導(dǎo)出Excel報(bào)表,例如導(dǎo)出一個(gè)包含所有老師信息的Excel表格。
def export_teachers_excel(request): # 創(chuàng)建工作簿 wb = xlwt.Workbook() # 添加工作表 sheet = wb.add_sheet('老師信息表') # 查詢(xún)所有老師的信息(注意:這個(gè)地方稍后需要優(yōu)化) queryset = Teacher.objects.all() # 向Excel表單中寫(xiě)入表頭 colnames = ('姓名', '介紹', '好評(píng)數(shù)', '差評(píng)數(shù)', '學(xué)科') for index, name in enumerate(colnames): sheet.write(0, index, name) # 向單元格中寫(xiě)入老師的數(shù)據(jù) props = ('name', 'detail', 'good_count', 'bad_count', 'subject') for row, teacher in enumerate(queryset): for col, prop in enumerate(props): value = getattr(teacher, prop, '') if isinstance(value, Subject): value = value.name sheet.write(row + 1, col, value) # 保存Excel buffer = BytesIO() wb.save(buffer) # 將二進(jìn)制數(shù)據(jù)寫(xiě)入響應(yīng)的消息體中并設(shè)置MIME類(lèi)型 resp = HttpResponse(buffer.getvalue(), content_type='application/vnd.ms-excel') # 中文文件名需要處理成百分號(hào)編碼 filename = quote('老師.xls') # 通過(guò)響應(yīng)頭告知瀏覽器下載該文件以及對(duì)應(yīng)的文件名 resp['content-disposition'] = f'attachment; filename="{filename}"' return resp
映射URL。
urlpatterns = [ # 此處省略上面的代碼 path('excel/', views.export_teachers_excel), # 此處省略下面的代碼 ]
如果項(xiàng)目中需要生成前端統(tǒng)計(jì)圖表,可以使用百度的ECharts。具體的做法是后端通過(guò)提供數(shù)據(jù)接口返回統(tǒng)計(jì)圖表所需的數(shù)據(jù),前端使用ECharts來(lái)渲染出柱狀圖、折線(xiàn)圖、餅圖、散點(diǎn)圖等圖表。例如我們要生成一個(gè)統(tǒng)計(jì)所有老師好評(píng)數(shù)和差評(píng)數(shù)的報(bào)表,可以按照下面的方式來(lái)做。
def get_teachers_data(request): # 查詢(xún)所有老師的信息(注意:這個(gè)地方稍后也需要優(yōu)化) queryset = Teacher.objects.all() # 用生成式將老師的名字放在一個(gè)列表中 names = [teacher.name for teacher in queryset] # 用生成式將老師的好評(píng)數(shù)放在一個(gè)列表中 good = [teacher.good_count for teacher in queryset] # 用生成式將老師的差評(píng)數(shù)放在一個(gè)列表中 bad = [teacher.bad_count for teacher in queryset] # 返回JSON格式的數(shù)據(jù) return JsonResponse({'names': names, 'good': good, 'bad': bad})
映射URL。
urlpatterns = [ # 此處省略上面的代碼 path('teachers_data/', views.export_teachers_excel), # 此處省略下面的代碼 ]
使用ECharts生成柱狀圖。
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>老師評(píng)價(jià)統(tǒng)計(jì)</title> </head> <body> <div id="main" style="width: 600px; height: 400px"></div> <p> <a href="/">返回首頁(yè)</a> </p> <script src="https://cdn.bootcss.com/echarts/4.2.1-rc1/echarts.min.js"></script> <script> var myChart = echarts.init(document.querySelector('#main')) fetch('/teachers_data/') .then(resp => resp.json()) .then(json => { var option = { color: ['#f00', '#00f'], title: { text: '老師評(píng)價(jià)統(tǒng)計(jì)圖' }, tooltip: {}, legend: { data:['好評(píng)', '差評(píng)'] }, xAxis: { data: json.names }, yAxis: {}, series: [ { name: '好評(píng)', type: 'bar', data: json.good }, { name: '差評(píng)', type: 'bar', data: json.bad } ] } myChart.setOption(option) }) </script> </body> </html>
運(yùn)行效果如下圖所示。
項(xiàng)目開(kāi)發(fā)階段,顯示足夠的調(diào)試信息以輔助開(kāi)發(fā)人員調(diào)試代碼還是非常必要的;項(xiàng)目上線(xiàn)以后,將系統(tǒng)運(yùn)行時(shí)出現(xiàn)的警告、錯(cuò)誤等信息記錄下來(lái)以備相關(guān)人員了解系統(tǒng)運(yùn)行狀況并維護(hù)代碼也是很有必要的。要做好這兩件事件,我們需要為Django項(xiàng)目配置日志。
Django的日志配置基本可以參照官方文檔再結(jié)合項(xiàng)目實(shí)際需求來(lái)進(jìn)行,這些內(nèi)容基本上可以從官方文檔上復(fù)制下來(lái),然后進(jìn)行局部的調(diào)整即可,下面給出一些參考配置。
LOGGING = { 'version': 1, # 是否禁用已經(jīng)存在的日志器 'disable_existing_loggers': False, # 日志格式化器 'formatters': { 'simple': { 'format': '%(asctime)s %(module)s.%(funcName)s: %(message)s', 'datefmt': '%Y-%m-%d %H:%M:%S', }, 'verbose': { 'format': '%(asctime)s %(levelname)s [%(process)d-%(threadName)s] ' '%(module)s.%(funcName)s line %(lineno)d: %(message)s', 'datefmt': '%Y-%m-%d %H:%M:%S', } }, # 日志過(guò)濾器 'filters': { # 只有在Django配置文件中DEBUG值為T(mén)rue時(shí)才起作用 'require_debug_true': { '()': 'django.utils.log.RequireDebugTrue', }, }, # 日志處理器 'handlers': { # 輸出到控制臺(tái) 'console': { 'class': 'logging.StreamHandler', 'level': 'DEBUG', 'filters': ['require_debug_true'], 'formatter': 'simple', }, # 輸出到文件(每周切割一次) 'file1': { 'class': 'logging.handlers.TimedRotatingFileHandler', 'filename': 'access.log', 'when': 'W0', 'backupCount': 12, 'formatter': 'simple', 'level': 'INFO', }, # 輸出到文件(每天切割一次) 'file2': { 'class': 'logging.handlers.TimedRotatingFileHandler', 'filename': 'error.log', 'when': 'D', 'backupCount': 31, 'formatter': 'verbose', 'level': 'WARNING', }, }, # 日志器記錄器 'loggers': { 'django': { # 需要使用的日志處理器 'handlers': ['console', 'file1', 'file2'], # 是否向上傳播日志信息 'propagate': True, # 日志級(jí)別(不一定是最終的日志級(jí)別) 'level': 'DEBUG', }, } }
大家可能已經(jīng)注意到了,上面日志配置中的formatters是日志格式化器,它代表了如何格式化輸出日志,其中格式占位符分別表示:
%(name)s - 記錄器的名稱(chēng)
%(levelno)s - 數(shù)字形式的日志記錄級(jí)別
%(levelname)s - 日志記錄級(jí)別的文本名稱(chēng)
%(filename)s - 執(zhí)行日志記錄調(diào)用的源文件的文件名稱(chēng)
%(pathname)s - 執(zhí)行日志記錄調(diào)用的源文件的路徑名稱(chēng)
%(funcName)s - 執(zhí)行日志記錄調(diào)用的函數(shù)名稱(chēng)
%(module)s - 執(zhí)行日志記錄調(diào)用的模塊名稱(chēng)
%(lineno)s - 執(zhí)行日志記錄調(diào)用的行號(hào)
%(created)s - 執(zhí)行日志記錄的時(shí)間
%(asctime)s - 日期和時(shí)間
%(msecs)s - 毫秒部分
%(thread)d - 線(xiàn)程ID(整數(shù))
%(threadName)s - 線(xiàn)程名稱(chēng)
%(process)d - 進(jìn)程ID (整數(shù))
日志配置中的handlers用來(lái)指定日志處理器,簡(jiǎn)單的說(shuō)就是指定將日志輸出到控制臺(tái)還是文件又或者是網(wǎng)絡(luò)上的服務(wù)器,可用的處理器包括:
logging.StreamHandler(stream=None) - 可以向類(lèi)似與sys.stdout或者sys.stderr的任何文件對(duì)象輸出信息
logging.FileHandler(filename, mode='a', encoding=None, delay=False) - 將日志消息寫(xiě)入文件
logging.handlers.DatagramHandler(host, port) - 使用UDP協(xié)議,將日志信息發(fā)送到指定主機(jī)和端口的網(wǎng)絡(luò)主機(jī)上
logging.handlers.HTTPHandler(host, url) - 使用HTTP的GET或POST方法將日志消息上傳到一臺(tái)HTTP 服務(wù)器
logging.handlers.RotatingFileHandler(filename, mode='a', maxBytes=0, backupCount=0, encoding=None, delay=False) - 將日志消息寫(xiě)入文件,如果文件的大小超出maxBytes指定的值,那么將重新生成一個(gè)文件來(lái)記錄日志
logging.handlers.SocketHandler(host, port) - 使用TCP協(xié)議,將日志信息發(fā)送到指定主機(jī)和端口的網(wǎng)絡(luò)主機(jī)上
logging.handlers.SMTPHandler(mailhost, fromaddr, toaddrs, subject, credentials=None, secure=None, timeout=1.0) - 將日志輸出到指定的郵件地址
logging.MemoryHandler(capacity, flushLevel=ERROR, target=None, flushOnClose=True) - 將日志輸出到內(nèi)存指定的緩沖區(qū)中
上面每個(gè)日志處理器都指定了一個(gè)名為“l(fā)evel”的屬性,它代表了日志的級(jí)別,不同的日志級(jí)別反映出日志中記錄信息的嚴(yán)重性。Python中定義了六個(gè)級(jí)別的日志,按照從低到高的順序依次是:NOTSET、DEBUG、INFO、WARNING、ERROR、CRITICAL。
最后配置的日志記錄器是用來(lái)真正輸出日志的,Django框架提供了如下所示的內(nèi)置記錄器:
django - 在Django層次結(jié)構(gòu)中的所有消息記錄器
django.request - 與請(qǐng)求處理相關(guān)的日志消息。5xx響應(yīng)被視為錯(cuò)誤消息;4xx響應(yīng)被視為為警告消息
django.server - 與通過(guò)runserver調(diào)用的服務(wù)器所接收的請(qǐng)求相關(guān)的日志消息。5xx響應(yīng)被視為錯(cuò)誤消息;4xx響應(yīng)被記錄為警告消息;其他一切都被記錄為INFO
django.template - 與模板渲染相關(guān)的日志消息
django.db.backends - 有與數(shù)據(jù)庫(kù)交互產(chǎn)生的日志消息,如果希望顯示ORM框架執(zhí)行的SQL語(yǔ)句,就可以使用該日志記錄器。
日志記錄器中配置的日志級(jí)別有可能不是最終的日志級(jí)別,因?yàn)檫€要參考日志處理器中配置的日志級(jí)別,取二者中級(jí)別較高者作為最終的日志級(jí)別。
Django-Debug-Toolbar是項(xiàng)目開(kāi)發(fā)階段輔助調(diào)試和優(yōu)化的神器,只要配置了它,就可以很方便的查看到如下表所示的項(xiàng)目運(yùn)行信息,這些信息對(duì)調(diào)試項(xiàng)目和優(yōu)化Web應(yīng)用性能都是至關(guān)重要的。
1 . 安裝Django-Debug-Toolbar。
pip install django-debug-toolbar
2 . 配置 - 修改settings.py。
INSTALLED_APPS = [ 'debug_toolbar', ] MIDDLEWARE = [ 'debug_toolbar.middleware.DebugToolbarMiddleware', ] DEBUG_TOOLBAR_CONFIG = { # 引入jQuery庫(kù) 'JQUERY_URL': 'https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js', # 工具欄是否折疊 'SHOW_COLLAPSED': True, # 是否顯示工具欄 'SHOW_TOOLBAR_CALLBACK': lambda x: True, }
3 . 配置 - 修改urls.py。
if settings.DEBUG: import debug_toolbar urlpatterns.insert(0, path('__debug__/', include(debug_toolbar.urls)))
4 . 使用 - 如下圖所示,在配置好Django-Debug-Toolbar之后,頁(yè)面右側(cè)會(huì)看到一個(gè)調(diào)試工具欄,上面包括了如前所述的各種調(diào)試信息,包括執(zhí)行時(shí)間、項(xiàng)目設(shè)置、請(qǐng)求頭、SQL、靜態(tài)資源、模板、緩存、信號(hào)等,查看起來(lái)非常的方便。
在配置了日志或Django-Debug-Toolbar之后,我們可以查看一下之前將老師數(shù)據(jù)導(dǎo)出成Excel報(bào)表的視圖函數(shù)執(zhí)行情況,這里我們關(guān)注的是ORM框架生成的SQL查詢(xún)到底是什么樣子的,相信這里的結(jié)果會(huì)讓你感到有一些意外。執(zhí)行Teacher.objects.all()之后我們可以注意到,在控制臺(tái)看到的或者通過(guò)Django-Debug-Toolbar輸出的SQL是下面這樣的:
SELECT `tb_teacher`.`no`, `tb_teacher`.`name`, `tb_teacher`.`detail`, `tb_teacher`.`photo`, `tb_teacher`.`good_count`, `tb_teacher`.`bad_count`, `tb_teacher`.`sno` FROM `tb_teacher`; args=() SELECT `tb_subject`.`no`, `tb_subject`.`name`, `tb_subject`.`intro`, `tb_subject`.`create_date`, `tb_subject`.`is_hot` FROM `tb_subject` WHERE `tb_subject`.`no` = 101; args=(101,) SELECT `tb_subject`.`no`, `tb_subject`.`name`, `tb_subject`.`intro`, `tb_subject`.`create_date`, `tb_subject`.`is_hot` FROM `tb_subject` WHERE `tb_subject`.`no` = 101; args=(101,) SELECT `tb_subject`.`no`, `tb_subject`.`name`, `tb_subject`.`intro`, `tb_subject`.`create_date`, `tb_subject`.`is_hot` FROM `tb_subject` WHERE `tb_subject`.`no` = 101; args=(101,) SELECT `tb_subject`.`no`, `tb_subject`.`name`, `tb_subject`.`intro`, `tb_subject`.`create_date`, `tb_subject`.`is_hot` FROM `tb_subject` WHERE `tb_subject`.`no` = 101; args=(101,) SELECT `tb_subject`.`no`, `tb_subject`.`name`, `tb_subject`.`intro`, `tb_subject`.`create_date`, `tb_subject`.`is_hot` FROM `tb_subject` WHERE `tb_subject`.`no` = 103; args=(103,) SELECT `tb_subject`.`no`, `tb_subject`.`name`, `tb_subject`.`intro`, `tb_subject`.`create_date`, `tb_subject`.`is_hot` FROM `tb_subject` WHERE `tb_subject`.`no` = 103; args=(103,)
這里的問(wèn)題通常被稱(chēng)為“1+N查詢(xún)”(或“N+1查詢(xún)”),原本獲取老師的數(shù)據(jù)只需要一條SQL,但是由于老師關(guān)聯(lián)了學(xué)科,當(dāng)我們查詢(xún)到N條老師的數(shù)據(jù)時(shí),Django的ORM框架又向數(shù)據(jù)庫(kù)發(fā)出了N條SQL去查詢(xún)老師所屬學(xué)科的信息。每條SQL執(zhí)行都會(huì)有較大的開(kāi)銷(xiāo)而且會(huì)給數(shù)據(jù)庫(kù)服務(wù)器帶來(lái)壓力,如果能夠在一條SQL中完成老師和學(xué)科的查詢(xún)肯定是更好的做法,這一點(diǎn)也很容易做到,相信大家已經(jīng)想到怎么做了。是的,我們可以使用連接查詢(xún),但是在使用Django的ORM框架時(shí)如何做到這一點(diǎn)呢?對(duì)于多對(duì)一關(guān)聯(lián)(如投票應(yīng)用中的老師和學(xué)科),我們可以使用QuerySet的用select_related()方法來(lái)加載關(guān)聯(lián)對(duì)象;而對(duì)于多對(duì)多關(guān)聯(lián)(如電商網(wǎng)站中的訂單和商品),我們可以使用prefetch_related()方法來(lái)加載關(guān)聯(lián)對(duì)象。
在導(dǎo)出老師Excel報(bào)表的視圖函數(shù)中,我們可以按照下面的方式優(yōu)化代碼。
queryset = Teacher.objects.all().select_related('subject')
事實(shí)上,用ECharts生成前端報(bào)表的視圖函數(shù)中,查詢(xún)老師好評(píng)和差評(píng)數(shù)據(jù)的操作也能夠優(yōu)化,因?yàn)樵谶@個(gè)例子中,我們只需要獲取老師的姓名、好評(píng)數(shù)和差評(píng)數(shù)這三項(xiàng)數(shù)據(jù),但是在默認(rèn)的情況生成的SQL會(huì)查詢(xún)老師表的所有字段??梢杂肣uerySet的only()方法來(lái)指定需要查詢(xún)的屬性,也可以用QuerySet的defer()方法來(lái)指定暫時(shí)不需要查詢(xún)的屬性,這樣生成的SQL會(huì)通過(guò)投影操作來(lái)指定需要查詢(xún)的列,從而改善查詢(xún)性能,代碼如下所示:
queryset = Teacher.objects.all().only('name', 'good_count', 'bad_count')
當(dāng)然,如果要統(tǒng)計(jì)出每個(gè)學(xué)科的老師好評(píng)和差評(píng)的平均數(shù),利用Django的ORM框架也能夠做到,代碼如下所示:
queryset = Teacher.objects.values('subject').annotate( good=Avg('good_count'), bad=Avg('bad_count'))
這里獲得的QuerySet中的元素是字典對(duì)象,每個(gè)字典中有三組鍵值對(duì),分別是代表學(xué)科編號(hào)的subject、代表好評(píng)數(shù)的good和代表差評(píng)數(shù)的bad。如果想要獲得學(xué)科的名稱(chēng)而不是編號(hào),可以按照如下所示的方式調(diào)整代碼:
queryset = Teacher.objects.values('subject__name').annotate( good=Avg('good_count'), bad=Avg('bad_count'))
可見(jiàn),Django的ORM框架允許我們用面向?qū)ο蟮姆绞酵瓿申P(guān)系數(shù)據(jù)庫(kù)中的分組和聚合查詢(xún)。
到此,關(guān)于“怎么使用Python報(bào)表和日志”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)?lái)更多實(shí)用的文章!
當(dāng)前標(biāo)題:怎么使用Python報(bào)表和日志
本文URL:http://jinyejixie.com/article12/gpijdc.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供面包屑導(dǎo)航、網(wǎng)站制作、網(wǎng)站建設(shè)、商城網(wǎng)站、ChatGPT、企業(yè)建站
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶(hù)投稿、用戶(hù)轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話(huà):028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)