Django实践-07日志调试,Django-Debug-Toolbar配置与sql优化

简介: Django实践-07日志调试,Django-Debug-Toolbar配置与sql优化

image.png


Django实践-07日志调试与sql优化


官网:https://www.djangoproject.com/

博客:https://www.liujiangblog.com/

本博客内容参考git:https://gitcode.net/mirrors/jackfrued/Python-100-Days 一些细节问题,大家可以查看git连接。本文主要的改变为把代码升级为django4.1版本。


Django静态文件问题备注:

参考:

Django测试开发-20-settings.py中templates配置,使得APP下的模板以及根目录下的模板均可生效

解决django 多个APP时 static文件的问题


django配置app中的静态文件步骤

Django多APP加载静态文件


django.short包参考:https://docs.djangoproject.com/en/4.1/topics/http/shortcuts/


配置日志


参考:

https://docs.djangoproject.com/zh-hans/4.1/topics/logging/#configuring-logging

https://docs.python.org/3/library/logging.config.html#logging-config-dictschema


项目开发阶段,显示足够的调试信息以辅助开发人员调试代码还是非常必要的;

项目上线以后,将系统运行时出现的警告、错误等信息记录下来以备相关人员了解系统运行状况并维护代码也是很有必要的。

与此同时,采集日志数据也是为网站做数字化运营奠定一个基础,通过对系统运行日志的分析,我们可以监测网站的流量以及流量分布,同时还可以挖掘出用户的使用习惯和行为模式。


Although Django’s logging configuration works out of the box, you can control exactly how your logs are sent to various destinations - to log files, external services, email and so on - with some additional configuration.

虽然Django的日志配置是开箱即用的,但是你可以通过一些额外的配置来控制你的日志如何被发送到不同的目的地——日志文件、外部服务、电子邮件等等。


你可以配置:


logger mappings, to determine which records are sent to which handlers

记录器映射,以确定将哪些记录发送到哪些处理程序

handlers, to determine what they do with the records they receive

处理程序,以确定如何处理接收到的记录

filters, to provide additional control over the transfer of records, and even modify records in-place

过滤器,以提供对记录传输的额外控制,甚至就地修改记录

formatters, to convert LogRecord objects to a string or other form for consumption by human beings or another system

格式化程序,用于将LogRecord对象转换为字符串或其他形式以供人类或其他系统使用


日志配置说明1

在settings.py中配置:


LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'verbose': {
            'format': '{levelname} {asctime} {module} {process:d} {thread:d} {message}',
            'style': '{',
        },
        'simple': {
            'format': '{levelname} {message}',
            'style': '{',
        },
    },
    'filters': {
        'special': {
            '()': 'project.logging.SpecialFilter',
            'foo': 'bar',
        },
        'require_debug_true': {
            '()': 'django.utils.log.RequireDebugTrue',
        },
    },
    'handlers': {
        'console': {
            'level': 'INFO',
            'filters': ['require_debug_true'],
            'class': 'logging.StreamHandler',
            'formatter': 'simple'
        },
        'mail_admins': {
            'level': 'ERROR',
            'class': 'django.utils.log.AdminEmailHandler',
            'filters': ['special']
        },
        'file': {
            'level': 'DEBUG',
            'class': 'logging.FileHandler',
            'filename': '/path/to/django/debug.log',
        },
    },
    'loggers': {
        'django': {
            'handlers': ['console'],
            'propagate': True,
        },
        'django.request': {
            'handlers': ['mail_admins'],
            'level': 'ERROR',
            'propagate': False,
        },
        'myproject.custom': {
            'handlers': ['console', 'mail_admins'],
            'level': 'INFO',
            'filters': ['special']
        }
    }
}

该日志配置做了以下事情:


识别配置为 ‘dictConfig 版本 1’ 格式。目前,这是唯一的 dictConfig 格式版本。


定义两个格式化程序:

simple,输出日志级别名称(如 DEBUG)和日志信息。

format 字符串是一个普通的 Python 格式化字符串,它描述了每个日志行要输出的细节。可以输出的完整细节列表可以在 Formatter Objects 中找到。

verbose,输出日志级别名称、日志信息,以及生成日志信息的时间、进程、线程和模块。


定义两个过滤器:

project.logging.SpecialFilter,使用别名 special。如果这个过滤器需要额外的参数,它们可以作为过滤器配置字典中的附加键提供。在这种情况下,当实例化 SpecialFilter 时,参数 foo 将被赋予一个 bar 的值。

django.utils.log.RequireDebugTrue,当 DEBUG 为 True 时,传递记录。


定义两个处理程序:

console,一个 StreamHandler,它将任何 INFO (或更高)消息打印到 sys.stderr。该处理程序使用 simple 输出格式。

mail_admins, an AdminEmailHandler, which emails any ERROR (or higher) message to the site ADMINS. This handler uses the special filter.

‘filename’ 指向的路径改为当前运行 Django 应用的用户可写的路径


配置三个记录器。

django,将所有信息传递给 console 处理程序。

django.request,它将所有 ERROR 消息传递给 mail_admins 处理程序。此外,这个记录器被标记为 不 传播消息。这意味着写给 django.request 的日志信息不会被 django 日志处理程序处理。

myproject.custom,它将所有 INFO 或更高等级的消息传递给两个处理程序——console 和 mail_admins。这意味着所有 INFO 级别(或更高)的消息将被打印到控制台;ERROR 和 CRITICAL 消息也将通过电子邮件输出。


日志配置说明2

在settings.py中配置:


LOGGING = {
    'version': 1,
    # 是否禁用已经存在的日志器
    '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',
        }
    },
    # 日志过滤器
    'filters': {
        # 只有在Django配置文件中DEBUG值为True时才起作用
        'require_debug_true': {
            '()': 'django.utils.log.RequireDebugTrue',
        },
    },
    # 日志处理器
    'handlers': {
        # 输出到控制台
        '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,
            # 日志级别(不一定是最终的日志级别)
            'level': 'DEBUG',
        },
    }
}

大家可能已经注意到了,上面日志配置中的formatters是日志格式化器,它代表了如何格式化输出日志,其中格式占位符分别表示:


  1. %(name)s - 记录器的名称
  2. %(levelno)s - 数字形式的日志记录级别
  3. %(levelname)s - 日志记录级别的文本名称
  4. %(filename)s - 执行日志记录调用的源文件的文件名称
  5. %(pathname)s - 执行日志记录调用的源文件的路径名称
  6. %(funcName)s - 执行日志记录调用的函数名称
  7. %(module)s - 执行日志记录调用的模块名称
  8. %(lineno)s - 执行日志记录调用的行号
  9. %(created)s - 执行日志记录的时间
  10. %(asctime)s - 日期和时间
  11. %(msecs)s - 毫秒部分
  12. %(thread)d - 线程ID(整数)
  13. %(threadName)s - 线程名称
  14. %(process)d - 进程ID (整数)


日志配置中的handlers用来指定日志处理器,简单的说就是指定将日志输出到控制台还是文件又或者是网络上的服务器,可用的处理器包括:


  1. logging.StreamHandler(stream=None) - 可以向类似与sys.stdout或者sys.stderr的任何文件对象输出信息
  2. logging.FileHandler(filename, mode='a', encoding=None, delay=False) - 将日志消息写入文件
  3. logging.handlers.DatagramHandler(host, port) - 使用UDP协议,将日志信息发送到指定主机和端口的网络主机上
  4. logging.handlers.HTTPHandler(host, url) - 使用HTTP的GET或POST方法将日志消息上传到一台HTTP 服务器
  5. logging.handlers.RotatingFileHandler(filename, mode='a', maxBytes=0, backupCount=0, encoding=None, delay=False) - 将日志消息写入文件,如果文件的大小超出maxBytes指定的值,那么将重新生成一个文件来记录日志
  6. logging.handlers.SocketHandler(host, port) - 使用TCP协议,将日志信息发送到指定主机和端口的网络主机上
  7. logging.handlers.SMTPHandler(mailhost, fromaddr, toaddrs, subject, credentials=None, secure=None, timeout=1.0) - 将日志输出到指定的邮件地址
  8. logging.MemoryHandler(capacity, flushLevel=ERROR, target=None, flushOnClose=True) - 将日志输出到内存指定的缓冲区中


上面每个日志处理器都指定了一个名为level的属性,它代表了日志的级别,不同的日志级别反映出日志中记录信息的严重性。Python中定义了六个级别的日志,按照从低到高的顺序依次是:NOTSET、DEBUG、INFO、WARNING、ERROR、CRITICAL。


最后配置的日志记录器是用来真正输出日志的,Django框架提供了如下所示的内置记录器:


  1. django - 在Django层次结构中的所有消息记录器
  2. django.request - 与请求处理相关的日志消息。5xx响应被视为错误消息;4xx响应被视为为警告消息
  3. django.server - 与通过runserver调用的服务器所接收的请求相关的日志消息。5xx响应被视为错误消息;4xx响应被记录为警告消息;其他一切都被记录为INFO
  4. django.template - 与模板渲染相关的日志消息
  5. django.db.backends - 有与数据库交互产生的日志消息,如果希望显示ORM框架执行的SQL语句,就可以使用该日志记录器。


日志记录器中配置的日志级别有可能不是最终的日志级别,因为还要参考日志处理器中配置的日志级别,取二者中级别较高者作为最终的日志级别。


配置Django-Debug-Toolbar


参考:

https://github.com/jazzband/django-debug-toolbar

https://blog.csdn.net/cn_1937/article/details/82715983

Django-Debug-Toolbar是项目开发阶段辅助调试和优化的必备工具,只要配置了它,就可以很方便的查看到如下表所示的项目运行信息,这些信息对调试项目和优化Web应用性能都是至关重要的。


项目 说明
Versions Django的版本
Time 显示视图耗费的时间
Settings 配置文件中设置的值
Headers HTTP请求头和响应头的信息
Request 和请求相关的各种变量及其信息
StaticFiles 静态文件加载情况
Templates 模板的相关信息
Cache 缓存的使用情况
Signals Django内置的信号信息
Logging 被记录的日志信息
SQL 向数据库发送的SQL语句及其执行时间


配置方法

  1. 安装Django-Debug-Toolbar。
 pip install django-debug-toolbar
  1. 配置 - 修改settings.py。
if DEBUG:
    MIDDLEWARE += [
        'debug_toolbar.middleware.DebugToolbarMiddleware',
    ]
    INSTALLED_APPS += [
        'debug_toolbar',
    ]
    INTERNAL_IPS = ['127.0.0.1', ]
    # this is the main reason for not showing up the toolbar
    import mimetypes
    mimetypes.add_type("application/javascript", ".js", True)
    DEBUG_TOOLBAR_CONFIG = {
        # 'INTERCEPT_REDIRECTS': False,
        # 引入jQuery库 如果项目组包含jquery,这里可以为 ""
        'JQUERY_URL': 'https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js',
        # 工具栏是否折叠
        'SHOW_COLLAPSED': True,
        # 是否显示工具栏
        'SHOW_TOOLBAR_CALLBACK': lambda x: True,
    }
  1. 配置 - 修改urls.py。
# 在urls.py文件最后面添加
from django.conf import settings
if settings.DEBUG:
    import debug_toolbar
    urlpatterns.insert(0, path('__debug__/', include(debug_toolbar.urls)))

4.在配置好Django-Debug-Toolbar之后,页面右侧会看到一个调试工具栏,如下图所示,上面包括了如前所述的各种调试信息,包括执行时间、项目设置、请求、SQL、静态资源、模板、缓存、信号等,查看起来非常的方便。

9d5592bf1aae64fce8adbfd74aba76ee_149b3f0cfd074b678e306beb2a08c213.png

优化ORM-excel导出函数export_teachers_excel(request):

在配置了日志或Django-Debug-Toolbar之后,我们可以查看一下之前将老师数据导出成Excel报表的视图函数执行情况,这里我们关注的是ORM框架生成的SQL查询到底是什么样子的,


0959e83958f01b5c7542073db097e0e9_6484298e766e4309b1e3c3dea9b2e4d4.png

相信这里的结果会让你感到有一些意外。执行Teacher.objects.all()之后我们可以注意到,在控制台看到的或者通过Django-Debug-Toolbar输出的SQL是下面这样的:

fd461faa022a92601706fef8e02f68e6_e4a6d0d2e3a246ea8f58f72c86ff4c5e.png


这里的问题通常被称为“1+N查询”(有的地方也将其称之为“N+1查询”),原本获取老师的数据只需要一条SQL,但是由于老师关联了学科,当我们查询到N条老师的数据时,Django的ORM框架又向数据库发出了N条SQL去查询老师所属学科的信息。

在一条SQL中可以基于连接查询完成老师和学科的查询。

在使用Django的ORM框架时可以基于如下方法:


对于多对一关联(如投票应用中的老师和学科),我们可以使用QuerySet的用select_related()方法来加载关联对象;

而对于多对多关联(如电商网站中的订单和商品),我们可以使用prefetch_related()方法来加载关联对象。


在导出老师Excel报表的视图函数

def export_teachers_excel(request):

中,我们可以按照下面的方式优化代码。

    # 查询所有老师的信息
    # queryset = Teacher.objects.all() # 注释掉这句话,
    queryset = Teacher.objects.all().select_related('subject') # 修改为这句话

优化ORM-excel生成报表函数def get_teachers_data(request):

事实上,用ECharts生成前端报表的视图函数中,查询老师好评和差评数据的操作也能够优化,因为在这个例子中,我们只需要获取老师的姓名、好评数和差评数这三项数据,但是在默认的情况生成的SQL会查询老师表的所有字段。可以用QuerySet的only()方法来指定需要查询的属性,也可以用QuerySet的defer()方法来指定暂时不需要查询的属性,这样生成的SQL会通过投影操作来指定需要查询的列,从而改善查询性能,

函数中:def get_teachers_data(request):

代码如下所示:


# queryset = Teacher.objects.all()
queryset = Teacher.objects.all().only('name', 'good_count', 'bad_count')

当然,如果要统计出每个学科的老师好评和差评的平均数,利用Django的ORM框架也能够做到,代码如下所示:


queryset = Teacher.objects.values('subject').annotate(good=Avg('good_count'), bad=Avg('bad_count'))

这里获得的QuerySet中的元素是字典对象,每个字典中有三组键值对,分别是代表学科编号的subject、代表好评数的good和代表差评数的bad。如果想要获得学科的名称而不是编号,可以按照如下所示的方式调整代码:


queryset = Teacher.objects.values('subject__name').annotate(good=Avg('good_count'), bad=Avg('bad_count'))

可见,Django的ORM框架允许我们用面向对象的方式完成关系数据库中的分组和聚合查询。


总结


本文主要是Django系列博客。本文是Django日志配置与Django-Debug-Toolbar配置。

日志配置:


1.配置settings.py中的LOGGING


Django-Debug-Toolbar配置:


1.安装依赖库

2.修改settings.py文件

3.修改urls.py文件

4.测试运行

相关实践学习
【涂鸦即艺术】基于云应用开发平台CAP部署AI实时生图绘板
【涂鸦即艺术】基于云应用开发平台CAP部署AI实时生图绘板
相关文章
|
8月前
|
SQL 传感器 人工智能
生成更智能,调试更轻松,SLS SQL Copilot 焕新登场!
阿里云日志服务(SLS)推出智能分析助手 SLS SQL Copilot,融合 AI 技术与日志分析最佳实践,将自然语言转换为 SQL 查询,降低使用门槛,提升查询效率。其具备原生集成、智能语义理解与高效执行能力,助力用户快速洞察日志数据价值,实现智能化日志分析新体验。
529 1
|
8月前
|
SQL 传感器 人工智能
生成更智能,调试更轻松,SLS SQL Copilot 焕新登场!
本文是阿里云日志服务(SLS)首次对外系统性地揭秘 SLS SQL Copilot 背后的产品理念、架构设计与核心技术积淀。我们将带你深入了解,这一智能分析助手如何从用户真实需求出发,融合前沿 AI 能力与 SLS 十余年日志分析最佳实践,打造出面向未来的智能化日志分析体验。
702 56
|
10月前
|
SQL Java 关系型数据库
在 RDB 上跑 SQL------SPL 轻量级多源混算实践 1
SPL 支持通过 JDBC 连接 RDB,可动态生成 SQL 并传参,适用于 Java 与 SQL 结合的各类场景。本文以 MySQL 为例,演示如何配置数据库连接、编写 SPL 脚本查询 2024 年订单数据,并支持参数过滤和 SQL 混合计算。脚本可在 IDE 直接执行或集成至 Java 应用调用。
|
SQL 存储 关系型数据库
SQL优化策略与实践:组合索引与最左前缀原则详解
本文介绍了SQL优化的多种方式,包括优化查询语句(避免使用SELECT *、减少数据处理量)、使用索引(创建合适索引类型)、查询缓存、优化表结构、使用存储过程和触发器、批量处理以及分析和监控数据库性能。同时,文章详细讲解了组合索引的概念及其最左前缀原则,即MySQL从索引的最左列开始匹配条件,若跳过最左列,则索引失效。通过示例代码,展示了如何在实际场景中应用这些优化策略,以提高数据库查询效率和系统响应速度。
658 10
|
7月前
|
SQL 存储 监控
SQL日志优化策略:提升数据库日志记录效率
通过以上方法结合起来运行调整方案, 可以显著地提升SQL环境下面向各种搜索引擎服务平台所需要满足标准条件下之数据库登记作业流程综合表现; 同时还能确保系统稳健运行并满越用户体验预期目标.
369 6
|
SQL 安全 关系型数据库
SQL注入之万能密码:原理、实践与防御全解析
本文深入解析了“万能密码”攻击的运行机制及其危险性,通过实例展示了SQL注入的基本原理与变种形式。文章还提供了企业级防御方案,包括参数化查询、输入验证、权限控制及WAF规则配置等深度防御策略。同时,探讨了二阶注入和布尔盲注等新型攻击方式,并给出开发者自查清单。最后强调安全防护需持续改进,无绝对安全,建议使用成熟ORM框架并定期审计。技术内容仅供学习参考,严禁非法用途。
1861 0
|
SQL 关系型数据库 MySQL
MySQL进阶突击系列(07) 她气鼓鼓递来一条SQL | 怎么看执行计划、SQL怎么优化?
在日常研发工作当中,系统性能优化,从大的方面来看主要涉及基础平台优化、业务系统性能优化、数据库优化。面对数据库优化,除了DBA在集群性能、服务器调优需要投入精力,我们研发需要负责业务SQL执行优化。当业务数据量达到一定规模后,SQL执行效率可能就会出现瓶颈,影响系统业务响应。掌握如何判断SQL执行慢、以及如何分析SQL执行计划、优化SQL的技能,在工作中解决SQL性能问题显得非常关键。
|
9月前
|
SQL 关系型数据库 Java
SQL 移植--SPL 轻量级多源混算实践 7
不同数据库的 SQL 语法存在差异,尤其是函数写法不同,导致 SQL 移植困难。SPL 提供 sqltranslate 函数,可将标准 SQL 转换为特定数据库语法,实现 SQL 语句在不同数据库间的无缝迁移,支持多种数据库函数映射与自定义扩展。
|
SQL 存储 自然语言处理
SQL的解析和优化的原理:一条sql 执行过程是什么?
SQL的解析和优化的原理:一条sql 执行过程是什么?
SQL的解析和优化的原理:一条sql 执行过程是什么?