开发进程
今天来学习下众多的组件及工具,来帮助你开发和测试 Django 应用:
一、设置:
概览
什么是Django 配置
Django 的配置文件包含 Django 应用的所有配置项。本文档介绍配置是如何生效的,以及哪些设置项是可配置的。
基础知识
配置文件只是一个使用模块级变量的一个 Python 模块。
一组配置例子代码:
ALLOWED_HOSTS = ['www.example.com']
DEBUG = False
DEFAULT_FROM_EMAIL = 'webmaster@example.com'
因为配置文件是一个 Python 模块,所以要注意以下几项:
不能有 Python 语法错误
可以用 Python 语法实现动态配置,例如:
MY_SETTING = [str(i) for i in range(30)]
可以从其他配置文件中引入变量
指定配置文件
DJANGO_SETTINGS_MODULE
当你使用 Django 的时候,你必须告诉它你正在使用哪些设置。通过使用环境变量 DJANGO_SETTINGS_MODULE 来实现。
DJANGO_SETTINGS_MODULE 的值是一个符合 Python 语法的路径,例如 mysite.settings。要注意配置模块应位于 Python 的 import 搜索路径 中。
django-admin 工具
使用 django-admin 时,你可以一次性设定环境变量,也可以在运行此工具时,显式地传入配置模块。
例子(Unix Bash shell):
export DJANGO_SETTINGS_MODULE=mysite.settings
django-admin runserver
例子(Windows shell):
set DJANGO_SETTINGS_MODULE=mysite.settings
django-admin runserver
使用 --settings 命令行参数指定配置模块路径:
django-admin runserver --settings=mysite.settings
服务器端 (mode_wsgi)
在服务器环境下,要通知WSGI应用当前使用的是哪个配置文件,用到 os.environ:
import os
os.environ['DJANGO_SETTINGS_MODULE'] = 'mysite.settings'
完整的设置列表
核心配置
下面是 Django 核心中可用的配置及其默认值的列表。下面列出了 contrib 应用提供的设置,后面是核心配置的专题索引。
ABSOLUTE_URL_OVERRIDES
默认: {} (空字典)
将 “app_label.model_name” 字符串映射到接受模型对象并返回其 URL 的函数的字典。这是一种在每个预安装基础上插入或覆盖 get_absolute_url() 方法的方式。
例如:
ABSOLUTE_URL_OVERRIDES = {
'blogs.weblog': lambda o: "/blogs/%s/" % o.slug,
'news.story': lambda o: "/stories/%s/%s/" % (o.pub_year, o.slug),
}
ADMINS
默认: [] (空列表)
所有收到代码错误通知的人的列表。当 DEBUG=False 和 AdminEmailHandler 中设置了 LOGGING 时(默认情况下是这样做的),Django 会将请求/响应周期中出现的异常的详细信息通过邮件发送给这些人。
列表中的每个项目应该是一个元组 (全名, 电子邮件地址)。
例如:
[('John', 'john@example.com'), ('Mary', 'mary@example.com')]
二、应用程序:
概览
Django 包含一个已安装应用程序的注册表,能够存储配置和内省。它还维护着一个可用的 模型 列表。
这个注册表叫做 app,它在 django.app 中可用:
>>> from django.apps import apps
>>> apps.get_app_config('admin').verbose_name
'Administration'
项目和应用程序
术语 项目 描述了一个 Django 网络应用。项目的 Python 包主要是由一个配置模块定义的,但它通常包含其他东西。例如,当你运行 django-admin startproject mysite 时,你会得到一个 mysite 项目目录,其中包含一个 mysite 的 Python 包,其中有 settings.py、urls.py、asgi.py 和 wsgi.py。该项目包经常被扩展到包括像辅助工具、CSS 和模板这样的东西,这些东西并不与特定的应用程序相关。
一个 项目的根目录 (包含 manage.py 文件的目录)通常是项目中所有未单独安装的应用程序的容器。
术语 应用程序 指的是提供了一些功能的 Python 包。应用程序 可在多个项目中重用。
应用程序包括模型,视图,模板,模板标签,静态文件,URL,中间件等的一些组合。它们通常使用 INSTALLED_APPS 选项加入到项目中,也可以使用其他机制,如 URLconf, MIDDLEWARE 配置或模板继承。
重要的是要理解 Django 应用程序是一组与框架各部分交互的代码。并不存在 Application 对象这种东西。但是,在一些地方,Django 需要与已安装的应用进行交互,主要是为了配置,也是为了自省。所以应用注册表为每个安装的应用在一个 AppConfig 实例中维护元数据。
一个项目包可以自由的作为一个应用程序并包含一些模型等(前提是,需要把它加入 INSTALLED_APPS)。
配置应用程序
要设置一个应用程序,在应用程序中创建一个 apps.py 模块,然后在那里定义一个 AppConfig 的子类。
当 INSTALLED_APPS 中包含一个应用程序模块的点分隔路径时,默认情况下,如果 Django 在 apps.py 子模块中找到一个 AppConfig 子类,它就会将该配置用于应用程序。这个行为可以通过设置 AppConfig.default 为 False 来禁止。
如果 apps.py 模块包含多个 AppConfig 子类,Django 会寻找一个 AppConfig.default 为 True 的子类。
如果没有找到 AppConfig 子类,将使用 AppConfig 基类。
另外,INSTALLED_APPS 也可以包含一个配置类的点分隔路径,以明确地指定它:
INSTALLED_APPS = [
...
'polls.apps.PollsAppConfig',
...
]
对于应用程序作者
如果你正在创建一个名为 “Rock ’n’ roll” 的可插拔应用,那么这边将告诉你将如何为管理后台提供一个合适的名称:
# rock_n_roll/apps.py
from django.apps import AppConfig
class RockNRollConfig(AppConfig):
name = 'rock_n_roll'
verbose_name = "Rock ’n’ roll"
当 INSTALLED_APPS 包含 ‘rock_n_roll’ 时,RockNRollConfig 将自动加载。如果需要防止这种情况发生,可以在类定义中把 default 设置为 False。
你可以提供多个 AppConfig 子类来实现不同的行为。要告诉 Django 默认使用哪一个,可以在定义中把 default 设置为 True。如果你的用户想选择一个非默认的配置,他们必须在他们的 INSTALLED_APPS 配置中用这个类的点分隔路径替换 ‘rock_n_roll’。
AppConfig.name 属性告诉 Django 这个配置适用于哪个应用。你可以定义在 AppConfig API 参考中描述任何其他属性。
AppConfig 子类可以在任何地方定义。apps.py 惯例只是允许 Django 在 INSTALLED_APPS 包含一个应用程序模块的路径而不是一个配置类的路径时自动加载它们。
对于应用程序使用者
项目中直接使用 “Rock ’n’ roll”,其名字会是 anthology,但是你可能期望显示 “Jazz Manouche”,这需要你提供自定义配置:
# anthology/apps.py
from rock_n_roll.apps import RockNRollConfig
class JazzManoucheConfig(RockNRollConfig):
verbose_name = "Jazz Manouche"
# anthology/settings.py
INSTALLED_APPS = [
'anthology.apps.JazzManoucheConfig',
# ...
]
三、异常:
概览
Django 异常
Django 会引发一些自己的异常以及标准的 Python 异常。
Django 核心异常
Django 核心异常类定义在 django.core.exceptions 中。
AppRegistryNotReady
exception AppRegistryNotReady[源代码]
当在初始化 ORM 的 应用加载过程 完成之前,试图使用模型时,就会引发这个异常。
ObjectDoesNotExist
exception ObjectDoesNotExist[源代码]
Model.DoesNotExist 异常的基类。一个对 ObjectDoesNotExist 的 try/except 将捕获对所有模型的 DoesNotExist 异常。
EmptyResultSet
exception EmptyResultSet[源代码]
如果一个查询不返回任何结果,那么 EmptyResultSet 可能会在生成查询的过程中被触发。大多数 Django 项目不会遇到这个异常,但它可能对实现自定义查找和表达式很有用。
FieldDoesNotExist
exception FieldDoesNotExist[源代码]
当请求的字段在模型或模型的父类上不存在时,模型的 _meta.get_field() 方法会引发 FieldDoesNotExist 异常。
MultipleObjectsReturned
exception MultipleObjectsReturned[源代码]
Model.MultipleObjectsReturned 异常的基类。一个对 MultipleObjectsReturned 的 try/except 将捕获对所有模型的 MultipleObjectsReturned 异常。
四、django-admin.py 和 manage.py:
概览
django-admin 和 manage.py
django admin 是 Django 用于管理任务的命令行实用程序。这份文件概述了它所能做的一切。
此外,manage.py 会在每个 Django 项目中自动创建。它做的事情和 django-admin 一样,但也设置了 DJANGO_SETTINGS_MODULE 环境变量,使其指向你的项目的 settings.py 文件。
如果你通过 pip 安装 Django,django-admin 脚本应该在你的系统路径中。如果它不在你的系统路径中,请确保你的虚拟环境已经被激活。
一般来说,当你在一个 Django 项目中工作时,使用 manage.py 比使用 django-admin 更容易。如果你需要在多个 Django 配置文件之间切换,可以使用 django-admin 与 DJANGO_SETTINGS_MODULE 或 --settings 命令行选项。
为了保持一致,本文中的命令行例子都使用了 django-admin,但任何例子都可以使用 manage.py 或 python -m django。
用法
$ django-admin <command> [options]
$ manage.py <command> [options]
$ python -m django <command> [options]
command 应是本文件所列的命令之一。options 是可选的,应该是 0 个或更多可用于指定命令的选项。
获得运行时帮助
django-admin help
-
运行 django-admin help 来显示使用信息和每个应用程序提供的命令列表。
-
运行 django-admin help --commands 来显示所有可用命令的列表。
-
运行 django-admin help 来显示命令的描述和可用选项的列表。
应用名称
许多命令都需要一个“应用名称”的列表。一个“应用名称”是包含你模型的包的基名。例如,如果你的 INSTALLED_APPS 包含字符串 ‘mysite.blog’,则应用名称为 blog。
确定版本
django-admin version
运行 django-admin version 来显示当前的 Django 版本。
输出遵循 PEP 440 中描述的架构:
1.4.dev17026
1.4a1
1.4
显示 debug 输出
使用 --verbosity,如果支持的话,可以指定 django-admin 打印到控制台的通知和调试信息的数量。
添加自定义命令
编写自定义 django-admin 命令
应用程序可以用 manage.py 注册自己的动作。例如,你可能想为你正在分发的 Django 应用添加一个 manage.py 动作。在本文档中,我们将为 教程 中的 polls 应用程序构建一个自定义的 closepoll 命令。
要做到这一点,在应用程序中添加一个 management/commands 目录。Django 会给目录下的每个 Python 模块注册一个 manage.py 命令,这个命令的名字不以下划线开头。
例如:
polls/
__init__.py
models.py
management/
__init__.py
commands/
__init__.py
_private.py
closepoll.py
tests.py
views.py
在这个例子中,closepoll 命令将提供给任何在 INSTALLED_APPS 中包含 polls 应用程序的项目。
_private.py 模块将不会作为管理命令使用。
closepoll.py 模块只有一个要求——必须定义 Command 类,该类继承自 BaseCommand 或其 子类。
五、测试:
介绍
Django 中的测试
对现在的 Web 开发者来说,自动化测试是一个非常有用的发现 bug 的工具。你可以使用一套测试—— 测试套件 ——去解决,避免一堆的问题:
当你编写新代码时,你可以利用测试确保代码按照期望的方式运行。
当你重构或修改旧代码,你可以利用测试来确保你的修改不会使应用运行出错。
测试一个 Web 应用是一项复杂的工作,因为 Web 应用包含了多层业务逻辑——从 HTTP 层响应请求,到表单有效性检测和处理,再到模板渲染。利用 Django 的测试执行框架和配套的工具,你可以模拟其你去,插入测试数据,检查应用的输出,以此检验你的代码是否按照期望运行。
在 Django 中编写测试的首选方式是使用 Python 标准库中内置的 unittest 模块。这一点在 编写并运行测试 文档中有详细介绍。
你也可以使用 另一个 Python 测试框架;Django 提供了用于这种集成的 API 和工具。这在 进阶测试主题 的 使用不同的测试框架 章节中有介绍。
编写并运行测试
测试工具
进阶测试主题
书写并运行测试
编写测试
Django 的单元测试采用 Python 的标准模块: unittest。该模块以类的形式定义测试。
下面是一个例子,它是 django.test.TestCase 的子类,同时父类也是 unittest.TestCase 的子类,在事务内部运行每个测试以提供隔离:
from django.test import TestCase
from myapp.models import Animal
class AnimalTestCase(TestCase):
def setUp(self):
Animal.objects.create(name="lion", sound="roar")
Animal.objects.create(name="cat", sound="meow")
def test_animals_can_speak(self):
"""Animals that can speak are correctly identified"""
lion = Animal.objects.get(name="lion")
cat = Animal.objects.get(name="cat")
self.assertEqual(lion.speak(), 'The lion says "roar"')
self.assertEqual(cat.speak(), 'The cat says "meow"')
当你 运行你的测试 时,测试工具的默认行为是在任何名字以 test 开头的文件中找到所有的测试用例(也就是 unittest.TestCase 的子类),从这些测试用例中自动构建一个测试套件,然后运行该套件。
包含的测试工具
测试客户端
测试客户端是一个 Python 类,它充当一个虚拟的 Web 浏览器,允许你测试视图并以编程方式与 Django 驱动的应用程序交互。
你可以使用测试客户端执行以下操作:
模拟 URL 上的 GET 和 POST 请求并观察响应——从低级 HTTP(结果头和状态码)到页面内容,应有尽有。
查看重定向链(如果有的话),并检查每个步骤的 URL 和状态码。
测试给定的请求是否由给定的包含某些值以及模板上下文的 Django 模板渲染。
请注意,测试客户端并不是要取代 Selenium 或其他“浏览器内”框架。Django 的测试客户端有不同的侧重点。简而言之:
使用 Django 的测试客户端来确定要渲染的模板正确,并且模板已传递了正确的上下文数据。
使用如 Selenium 之类的浏览器内框架来测试 渲染后的 HTML 和 Web 页面 行为,即 JavaScript 功能。Django 也为这些框架提供了特殊的支持,详情参见 LiveServerTestCase。
一个全面的测试套件应该使用这两种测试类型的组合。
概述和一个简单的例子
要使用测试客户端,请实例化 django.test.Client 并检索 Web 页面:
>>> from django.test import Client
>>> c = Client()
>>> response = c.post('/login/', {'username': 'john', 'password': 'smith'})
>>> response.status_code
200
>>> response = c.get('/customer/details/')
>>> response.content
b'<!DOCTYPE html...'
高级主题
进阶测试主题:请求工厂
class RequestFactory
RequestFactory 与测试客户端共享相同的 API。 但是,RequestFactory 不能像浏览器那样运行,而是提供一种生成请求实例的方法,该实例可用作任何视图的第一个参数。 这意味着您可以像测试任何其他功能一样测试视图函数——就像一个黑匣子一样,具有确切已知的输入,可以测试特定的输出。
RequestFactory 的 API 是测试客户端 API 的一个稍加限制的子集。
它只能访问 HTTP 的 get()、post()、put()、delete()、head()、options() 和 trace() 方法。
这些方法接受所有相同的参数,除了 follow。因为这只是一个产生请求的工厂,所以由你来处理响应。
它不支持中间件。如果需要视图正常运行,会话和认证属性必须由测试本身提供。
下面是一个使用请求工厂的单元测试:
from django.contrib.auth.models import AnonymousUser, User
from django.test import RequestFactory, TestCase
from .views import MyView, my_view
class SimpleTest(TestCase):
def setUp(self):
# Every test needs access to the request factory.
self.factory = RequestFactory()
self.user = User.objects.create_user(
username='jacob', email='jacob@…', password='top_secret')
def test_details(self):
# Create an instance of a GET request.
request = self.factory.get('/customer/details')
# Recall that middleware are not supported. You can simulate a
# logged-in user by setting request.user manually.
request.user = self.user
# Or you can simulate an anonymous user by setting request.user to
# an AnonymousUser instance.
request.user = AnonymousUser()
# Test my_view() as if it were deployed at /customer/details
response = my_view(request)
# Use this syntax for class-based views.
response = MyView.as_view()(request)
self.assertEqual(response.status_code, 200)
六、部署:
概述
部署 Django
Django 中简化 Web 开发的快捷函数俯拾皆是,但是如果不能轻松部署网站的话,所有的工具都徒劳无益。Django 从最初就把方便部署当作一个主要目标。
部署你的Django应用程序有很多选择,可以基于你的架构或者特定的业务需要,但是这不在Django可以给出指导建议的范围内。
Django是一个需要Web服务器来运行的Web框架。然而由于大多数Web服务器不是用Python编写,我们需要一个接口来实现沟通。
Django现在支持两种接口:WSGI和ASGI。
WSGI 服务器
如何使用 WSGI 进行部署
Django 的主要部署平台是 WSGI,它是 Web 服务器和 Web 应用的 Python 标准。
Django 的管理命令 startproject 生成了一个最小化的默认 WSGI 配置,你可以按照自己项目的需要去调整这个配置,任何兼容 WSGI 的应用程序服务器都可以直接使用。
Django 提供了下面这些 WSGI 服务的入门文档:
如何使用 Gunicorn 托管 Django
如何用 uWSGI 托管 Django
如何使用 Apache 和 mod_wsgi 托管 Django
Apache 利用 Django 的用户数据库进行验证
ASGI 服务器
如何使用 ASGI 来部署
同 WSGI 一样,Django 也支持使用 ASGI 来部署,它是为了支持异步网络服务器和应用而新出现的 Python 标准。
Django 的管理命令 startproject 生成了一个默认的 ASGI 配置,你可以按照自己项目的需要去调整这个配置,任何兼容 ASGI 的应用程序服务器都可以直接使用。
Django 提供了下面这些 ASGI 服务的入门文档:
如何使用 Daphne 托管 Django
如何使用 Hypercorn 托管 Django。
如何使用 Uvicorn 托管 Django
部署静态文件
在生产环境提供静态文件服务
在生产环境部署静态文件的基础要点有两步:在静态文件变化时,运行 collectstatic,然后将已收集的静态文件目录配置(STATIC_ROOT)移至静态文件服务器并提供服务。 STATICFILES_STORAGE 配置可能会要求手动将文件移动到新位置,不过 Storage 类的 post_process 方法可能会处理它。
像所有的部署任务一样,细节决定成败。每个生成环境的配置可能都有点不同个,所以,需要调整基础配置以满足你的需求。以下是常见模式,可能对你有所帮助。
在同一服务器提供站点和静态文件服务
如果你想在早已提供站点服务器服务器上同时提供静态文件服务,操作步骤类似这样:
将代码推送至部署服务器。
在服务器上运行 collectstatic,将所有的静态文件拷贝至 STATIC_ROOT。
配置 Web 服务器,使其在 STATIC_URL 下为 STATIC_ROOT 目录下的文件提供静态文件服务。例如, 这里是如何以 Apache 配合 mod_wsgi 开始。
你可能期望将该流程自动化,特别是在你有好几个 web 服务器的时候。
专用服务器提供静态文件服务
大多数大型 Django 站点使用一个独立的 Web 服务器——即,该服务器并未运行 Django,值提供静态文件服务。这种服务器一般运行一种不同的 Web 服务器——更快,更简单。常见选项如下:
Nginx
一个 Apache 的朴素版本
如何配置这些服务器超出了本文范围;查阅这些服务器各自的文档获取介绍。
由于静态文件服务器并不运行 Django,你需要将部署策略改成这样:
当静态文件改变时,本地运行 collectstatic。
将本地 STATIC_ROOT 推送到静态文件服务器提供服务的目录。 rsync 是一个常见选项,因为这种配置只会传输文件修改部分的数据流。
使用 email 追踪代码错误
发送错误
当您运行着公开的网页时,你应该把设置中的 DEBUG 选项设为关闭。 这将使您的服务器运行得更快,并且还可以防止恶意用户在错误页面中看到应用的详细信息。
然而,把配置 DEBUG 设置为 False, 这意味着你永远不会在你的网站上看到错误的细节,所有的人相应会看到你公开的错误页面。当你需要在部署的网页上追踪出现的错误,Django 可以通过设置去报告错误的细节。
部署检查清单
部署清单
互联网是一个恶劣的环境。在部署你的 Django 项目之前,你应该将安全、性能和操作铭记于心,并花一些时间来检查你的配置。
Django 包含了许多 安全特性。一些是内置的并且总保持激活状态,其他的则是可选的因为它们不总是恰当的,或者因为它们不便于之后的开发。举个例子,强制的 HTTPS 并不一定适合所有网站,它对于本地开发就是不切实际的。
性能优化是另一项便利性权衡的主题。例如,缓存在生成环境很有用,但是对本地开发就作用不大。错误报告的需求也大不相同。
以下清单包括以下配置:
- 必须正确地设置 Django 以提供预期的安全级别;
- 期望在每个环境中都是不同的;
- 启用可选的安全功能;
- 启用性能优化;
- 提供错误报告功能。
- 许多配置项是敏感的,需要被当做机密对待。如果要发布项目源码,常见操作是为开发开放合适的配置项,为生产环境配置私密设置模块。