Alan Hou的个人博客

Django 3网页开发指南第4版 第10章 锦上添花

完整目录请见:Django 3网页开发指南 – 第4版

本章中包含如下小节:

引言

本章中我们会学习一些重要的点点滴滴来更好地理解和使用Django。这里会总览如何使用Django shell来在文件中编写前进行代码的测试。还会介绍猴子补丁,也称“杂牌军补丁”,这是像Python和Ruby这样的动态语言所具备的强大特性。同时会讨论全文本搜索的功能,并会学习到如何调试代码并检测其性能。然后,我们会学习如何获取任意模块中登录的用户(和其它请求参数)。还会学习到如何处理信号及创建系统检测。准备开启有趣的编程体验之行吧!

技术要求

运行本章的代码要求安装最新稳定版的Python 3、MySQL或PostgreSQL数据库以及通过虚拟环境创建的Django项目。

可在GitHub仓库的Chapter10目录中查看本章的代码。

使用Django shell

启用虚拟环境并进入当前项目目录,在命令行工具中输入如下命令:

通过执行以上命令,会进入一个交互的Python shell,配置为你的Django项目,在其中可以实时操作代码、检测类、测试方法或执行脚本。本节中,我们将学习操作Django shell所需了解的一些最重要的功能。

准备工作

可以安装IPython或bpython来对Python shell提供更多的界面选项,也可以同时安装这两者进行选择。它们会在Django shell的输出中高亮语法显示,并会添加一些帮助类。使用如下命令在虚拟环境中进行安装:

如何实现…

按照如下内容学习使用Django shell的基础知识:

实现原理…

普通Python shell 和 Django shell之间的区别在于在运行Django shell时,manage.py设置的DJANGO_SETTINGS_MODULE让其指向项目的settings.py路径,然后Django shell中的所有代码都在项目的上下文中进行处理。通过使用第三方的IPython或bpython界面,可以进一步的增强默认的Python shell,比如语法高亮、自动补全等等。

相关内容

使用数据库查询表达式

Django对象关系映射(ORM)具有特殊的抽象构造,可用于构建复杂的数据库查询。称为查询表达式,让我们可以过滤数据、排序、注解新字段及聚合关联等。本节中,我们会学习在实际场景中如何使用。我们创建一个显示爆款视频的应用并计算每个视频被匿名或登录用户观看的次数。

准备工作

首先,创建一个带有ViralVideo模型的viral_videos应用并配置系统来让其默认自动记录入日志文件:

这会将调试信息记录至临时文件tmp/debug.log中。

如何实现…

为讲解查询表达式,我们来创建一个爆款视频详情页并将其加入到URL配置中,如下:

  1. 在views.py中创建爆款视频列表和详情视图如下:
  2. 为该应用定义URL配置如下:
  3. 在项目的顶级URL配置文件中添加应用URL配置如下:
  4. 为爆款视频列表视图创建模板如下:
  5. 为爆款视频详情视图创建模板如下:
  6. 为viral_videos应用配置后台如下,并在完成后在数据库中添加一些视频:

实现原理…

你可能注意到了视图中的logger.debug()语句。如果以DEBUG模式运行服务并在浏览器中访问视频(例如本地开发的 http://127.0.0.1:8000/en/viral-videos/2b14ffd3-d1f1-4699-a07b-1328421d8312/),会看到在日志(tmp/debug.log)中打印类似下面这样的SQL查询:

然后在浏览器中可以看到显示如下内容的简单页面:

类似如下图片:

TODO

Django查询集中的annotate()方法让我们可以对 SELECT SQL语句添加更多的字段,并且对通过查询集所获取的对象实时进行属性的创建。借助models.F()我们可以引用所选数据表的不同字段值。本例中,我们将创建total_views属性,它是已登录和匿名用户浏览量的总和。

通过models.Case() 和 models.When(),我们可以根据不同的条件返回值。使用models.Value()来标记这些值。本例中我们将创建SQL查询的label字段以及由QuerySet所返回的对象属性。如果浏览量大于500则会设置为popular,若在24小时之内创建则设置为new,其它情况为cool。

在视图的最后,我们调用了qs.update()方法。这些方法根据浏览视频的用户是否登录增加当前视频的authenticated_views和anonymous_views。这一增长不是在Python层面,而是在SQL层面。这解决了所谓竞态条件的问题,即两个访客同时使用该视图,又同步增长视频浏览量。

相关内容

slugify()的猴子补子改进国际化支持

猴子补丁(或称杂牌军补丁)是在运行时扩展或修改其它代码的一段代码。不推荐经常使用猴子补丁,有时在不创建模块的单独分支的情况下这是修改复杂第三方模块中bug的唯一途径。同时,猴子补丁还可用于在不使用复杂及耗时的数据库或文件操作的情况下,进行功能或单元测试。

本节中,我们将学习如何将默认的slugify()函数替换为第三方转译包中的那个,它更智能地处理了Unicode字符向ASCII对应字符的转化并包含很多语言包,甚至在需要时还有更多的具体转换。快速提醒一下,我们使用slugify() 来用对象标题或上传的文件名创建对用户更友好的版本。在处理时,该函数去除前后空格,将文本转化为小写,删除非字母数字字符,并将空格转化为中间杠。

准备工作

执行如下的小步骤:

  1. 在虚拟环境中安装transliterate如下:
  2. 然后在项目中创建guerrilla_patches应用并添加到配置文件的INSTALLED_APPS中。

如何实现…

在guerrilla_patches应用的models.py文件中,使用transliterate包中的slugify函数重写django.utils.text中的那个:

实现原理…

默认的Django slugify() 函数对德语变音符号的处理有误。想要查看,可以试着对一个带所胡德语变音符号的长词进行url 转换。首先在Django shell中运行如下未打猴子补丁的代码:

这在德语中是不正确的,字母ß完全被去除了而没有用ss进行替换,而字母ä、ö和ü被转换成了a、o和u,实际上应该由ae、oe和ue来进行替换。

我们所创建的猴子补子在初始化时加载django.utils.text模块并对核心的slugify()函数重新赋值transliteration.slugify。这时如何在Django shell中运行同样的代码,会得到正确的结果,如下:

ℹ️ 参见https://pypi.org/project/transliterate/来阅读更多有关如何使用transliterate模块的知识。

扩展知识…

在创建猴子补丁之前,我们需要完全明白希望修改后的代码如何运行。这可通过分析已有代码和查看各个变量的值来实现。有一个有用的内置Python调试器模块pdb,可以临时添加到Django代码(或第三方模块)中来在开发服务器上在任意断点处停止执行。使用如下代码来调试Python模块中不清楚部分的代码:

相关文章:Python自动化脚本-运维人员宝典第二章 Python脚本调试和性能测试

这会启动一个交互式shell,在其中可以输入变量名来查看值。如果输入 c 或continue,代码继承执行直至遇到下一个断点。如果输入q 或 quit,会停止管理命令。

ℹ️可以通过https://docs.python.org/3/library/pdb.html学习更多Python调试器命令以及如何查看代码回溯追踪。

另一种在开发服务器上快速查看变量值的方式是以变量作为消息抛出一个警告,如下:

在处于DEBUG模式时,Django日志器会为你提供回溯及其它本地变量。

💡在将代码提交到仓库前别忘了要删除调试代码。

如果使用PyCharm交互式开发环境,可以无需修改源代码直接用图形化界面设置断点及调试变量。

相关内容

切换Debug工具栏

在使用Django进行开发时,可能会希望查看请求头部和参数,检查当前模板上下文,或度量SQL查询的性能。所有这些和更多功能都可通过Django调试工作栏实现。它是一个显示有关当前请求和响应各种调试信息的可配置面板集。本节中,我们将讲解如何根据由小书签设置的cookie值切换调试工具栏的可见性。小书签是一小段JavaScript代码的书签,可以在浏览的任意页面中运行。

准备工作

按照如下步骤来切换调试工具栏的可见性:

  1. 在虚拟环境中安装Django调试工具栏:
  2. 在配置文件的INSTALLED_APPS中添加debug_toolbar:

如何实现…

按照如下步骤来配置Django调试工具栏,可使用浏览器的小标签来进行开关:

  1. 添加如下项目配置:
  2. 在core应用中,使用custom_show_toolbar() 函数创建一个misc.py文件,如下:
  3. 在项目的urls.py中添加如下配置规则:
  4. 打开Chrome或Firefox浏览器并进入书签管理器。然后,新建包含JavaScript的两个书签。第一个急拉显示工具栏,类似下面这样:
    TODO
    JavaScript代码如下:
  5. 第二段JavaScript链接会隐藏工具栏,效果类似下面这样:
    TODO
    完整的JavaScript代码如下:

实现原理…

DEBUG_TOOLBAR_PANELS配置定义在工具栏中显示的面板。DEBUG_TOOLBAR_CONFIG字典定义工具栏的配置,包含用于查看是否显示工具样款的函数的路径。

默认,在浏览项目时,不会显示Django调试工具栏,但在点击Debug Toolbar On小书签时,DebugToolbar的cookie会设置为1,页面会进行刷新 ,就会看到带有调试面板的工具栏,例如,我们可以查看SQL语句的性能以供优化,如下图所示:

TODO

还能够查看当前视图的模板上下文变量,如下图所示:

TODO

点击第二个小书签Debug Toolbar Off,相应地会将DebugToolbar的设置为0并刷新页面,再次隐藏工具栏。

相关内容

使用ThreadLocalMiddleware

HttpRequest对象包含有关当前用户、语言、服务端变量、cookie、session等有用信息。事实上HttpRequest在视图和middleware中进行提供,可以将其(或其属性值)传递给表单、模型方法、模型管理器和模板等等。要进行简化,可以使用所谓的ThreadLocalMiddleware,它在全局可访问的Python线程中存储当前HttpRequest对象。因此,可以在模型方法、表单、信号处理器和其它那些此前不能直接访问到HttpRequest对象的地方访问它。本节中,我们将定义这一中间件。

准备工作

如未创建,请创建core应用并将其加到配置文件的INSTALLED_APPS中。

如何实现…

执行如下两步来配置ThreadLocalMiddleware,可用于在项目代码的任意函数或方法中获取当前HttpRequest或用户:

  1. 使用如下内容在core应用中添加middleware.py文件:
  2. 将该中间件添加到配置文件的MIDDLEWARE中:

实现原理…

ThreadLocalMiddleware处理每个请求并存储当前线程中的HttpRequest对象。Django中的每个请求-响应环都是单线程的。我们创建了两个函数get_current_request() 和 get_current_user()。这两个函数可用在任意地方来分别获取当前HttpRequest对象或当前用户。

例如,可以使用中间件来开发、使用CreatorMixin,它会保存当前用户为模型对象的创建者,如下:

相关内容

使用信号来通知管理员新条目

Django框架中有一个信号(signal)的概念,类似于JavaScript中的事件。有很多内置的信号。可以使用它们来在模型初始化、保存或删除实例、迁移数据库模式或处理请求等之前及之后触发一些动作。同时在可复用应用中可以创建自己的信号来在其它应用中进行处理。本节中我们学习如何使用信号来在保存指定模型时向管理员发送邮件。

准备工作

我们采用使用数据库查询表达式一节中创建的viral_videos应用。

如何实现…

按照如下步骤来为管理员创建通知:

  1. 使用如下内容创建文件signals.py:
  2. 然后我们需要创建一些模型,先从模板的email主题开始:
  3. 然后创建一个普通文本消息模板,类似下面这样:
  4. 接着对HTML消息创建如下模板:
  5. 使用如下内容创建文件apps.py:
  6. 使用如下内容更新__init__.py文件:

    确保在项目配置文件中像如下这样配置了ADMINS:

实现原理…

ViralVideosAppConfig配置类中有一个ready()方法,在所有项目模型加载到内存中的时候会被调用。根据Django官方文档,信号允许某些发送者通知一组接收者发生了某一动作。因此在ready()方法中,我们导入了inform_administrators()函数。

借助@receiver装饰器,对post_save信号注册了inform_administrators(),并且仅在发送者为ViralVideo模型时进行该信号的处理。因此,在进行ViralVideo对象保存时,会调用接收者函数。inform_administrators()函数查看视频是否为新建的。如是,它会向配置文件中ADMINS所列举的系统管理员发送邮件。

我们使用模型来生成subject、plain_text_message以及html_message的内容,这样可以在应用中对各自定义默认模板。如果把viral_videos应用对外开放,那些在自己项目中拉取它的可以按照需要对模型进行自定义,或许是将它们封装到公司邮件模板包装中去。

ℹ️可在官方文档中学习更多有关Django信号的知识。

相关内容

检测缺失的设置

从Django 1.7开始,你可以使用可继承的系统检测框架,它替代掉了老的validate管理命令。本节中,我们将学习如何创建一个对ADMINS是否已配置的检测。类似地,我们可以检测密钥或所使用的API的连接token是否进行了设置。

准备工作

我们采用使用数据库查询表达式一节中创建并在前面小节中进行扩展了的viral_videos应用来开始我们的学习。

如何实现…

按照如下步骤来使用系统检测框架:

  1. 通过如下内容来创建文件checks.py:
  2. 在应用配置的ready()方法中导入这一检测,如下:
  3. 测试刚刚创建的检测,删除或注释掉ADMINS配置,然后在虚拟环境中运行check管理命令:

实现原理…

系统检测框架有一些模型、字段、数据库、管理认证配置、内容类型和安全配置的检测,如果在项目中未进行正确配置的话会报出错误或警告。此外,可以创建自有检测,类似于本节中所做的操作。

我们注册了settings_check()函数,如果在项目中未定义ADMINS配置的话会返回一个带有Warning的列表。

除django.core.checks模块中的Warning实例外,返回列表中还可包含Debug、Info、Error和Critical内置类或其它继承自django.core.checks.CheckMessage的类的实例。debug、info和warning级别的日志会静默略过,而error和critical级别的则会阻止项目的进一步执行。

本例中,通过传递给@register装饰器的Tags.compatibility参数来为检测添加兼容性检测的标记。Tags所包含的其它选项有:

ℹ️参见官方文档学习更多有关系统检测框架的知识。

相关内容

退出移动版