编码风格 — Django 文档
编码风格
在编写包含在 Django 中的代码时,请遵循这些编码标准。
预提交检查
pre-commit 是一个管理预提交钩子的框架。 这些钩子有助于在提交代码以供审查之前识别简单的问题。 通过在代码审查之前检查这些问题,它允许审查者专注于更改本身,它还可以帮助减少 CI 运行的次数。
要使用该工具,首先安装 pre-commit
,然后安装 git 钩子:
在第一次提交时 pre-commit
将安装钩子,这些钩子安装在它们自己的环境中,并且在第一次运行时需要很短的时间来安装。 后续检查将显着加快。 如果发现错误,将显示相应的错误消息。 如果错误与 isort
相关,那么该工具将继续为您修复它们。 如果您对更改感到满意,请查看更改并重新提交。
蟒蛇式
请遵循
.editorconfig
文件中规定的缩进样式。 我们建议使用支持 [X38X]EditorConfig 的文本编辑器以避免缩进和空格问题。 Python 文件使用 4 个空格作为缩进,HTML 文件使用 2 个空格。除非另有说明,否则请遵循 PEP 8。
使用flake8检查这方面的问题。 请注意,我们的
setup.cfg
文件包含一些排除的文件(我们不关心清理的弃用模块和一些 Django 供应商的第三方代码)以及一些我们不认为严重违规的排除错误. 请记住,PEP 8 只是一个指南,因此将尊重周围代码的风格作为主要目标。PEP 8 的一个例外是我们的行长规则。 不要将代码行限制为 79 个字符,如果这意味着代码看起来非常难看或难以阅读。 我们最多允许 119 个字符,因为这是 GitHub 代码审查的宽度; 任何更长的时间都需要水平滚动,这使得审查更加困难。 运行
flake8
时包括此检查。 尽管 PEP 8 建议使用 72 个字符,文档、评论和文档字符串应包含在 79 个字符内。使用四个空格作为缩进。
使用四个空格悬挂缩进而不是垂直对齐:
raise AttributeError( 'Here is a multiline error message ' 'shortened for clarity.' )
代替:
raise AttributeError('Here is a multiline error message ' 'shortened for clarity.')
这可以更好地利用空间并避免在第一行的长度发生变化时必须重新对齐字符串。
字符串使用单引号,如果字符串包含单引号,则使用双引号。 不要浪费时间对现有代码进行无关的重构以符合这种风格。
字符串变量插值可以视情况使用 %-f 格式、f-strings 或
str.format()
,以最大化代码可读性。可读性的最终判断由合并方自行决定。 作为指导,f-strings 应该只使用普通的变量和属性访问,对于更复杂的情况,预先分配局部变量:
# Allowed f'hello {user}' f'hello {user.name}' f'hello {self.user.name}' # Disallowed f'hello {get_user()}' f'you are {user.age * 365.25} days old' # Allowed with local variable assignment user = get_user() f'hello {user}' user_days_old = user.age * 365.25 f'you are {user_days_old} days old'
f-strings 不应用于任何可能需要翻译的字符串,包括错误和日志消息。 一般来说,
format()
比较冗长,所以首选其他格式化方法。不要浪费时间对现有代码进行无关的重构来调整格式化方法。
避免在评论中使用“我们”,例如 “循环”而不是“我们循环”。
对变量、函数和方法名称使用下划线,而不是驼峰式命名(即
poll.get_unique_voters()
,而不是poll.getUniqueVoters()
)。使用
InitialCaps
作为类名(或返回类的工厂函数)。在文档字符串中,遵循现有文档字符串的样式和 PEP 257。
在测试中,使用 assertRaisesMessage() 和 assertWarnsMessage() 代替
assertRaises()
和assertWarns()
,以便您可以检查异常或警告消息。 仅当需要正则表达式匹配时才使用assertRaisesRegex()
和assertWarnsRegex()
。使用
assertIs(…, True/False)
来测试布尔值,而不是assertTrue()
和assertFalse()
,这样你就可以检查实际的布尔值,而不是表达式的真实性。在测试文档字符串中,说明每个测试演示的预期行为。 不要包含诸如“Tests that”或“Ensures that”之类的序言。
保留票证参考以处理不明确的问题,其中票证具有无法在文档字符串或评论中轻松描述的其他详细信息。 在这样的句子末尾包含票号:
def test_foo(): """ A test docstring looks like this (#123456). """ ...
进口
使用 isort 按照以下指南自动进行导入排序。
快速启动:
这会从当前目录递归运行
isort
,修改任何不符合准则的文件。 如果您需要乱序导入(例如,为了避免循环导入),请使用如下注释:import module # isort:skip
将导入放在这些组中:未来、标准库、第三方库、其他 Django 组件、本地 Django 组件、try/excepts。 按完整模块名称的字母顺序对每个组中的行进行排序。 将所有
import module
语句放在每个部分的from module import objects
之前。 对其他 Django 组件使用绝对导入,对本地组件使用相对导入。在每一行上,按字母顺序排列项目,大写项目分组在小写项目之前。
使用括号将长行分隔,并将连续行缩进 4 个空格。 在最后一次导入后包含一个尾随逗号,并将右括号放在自己的行上。
在最后一个导入和任何模块级代码之间使用一个空行,并在第一个函数或类上方使用两个空行。
例如(评论仅用于解释目的):
# future from __future__ import unicode_literals # standard library import json from itertools import chain # third-party import bcrypt # Django from django.http import Http404 from django.http.response import ( Http404, HttpResponse, HttpResponseNotAllowed, StreamingHttpResponse, cookie, ) # local Django from .models import LogEntry # try/except try: import yaml except ImportError: yaml = None CONSTANT = 'foo' class Example: # ...
尽可能使用便利导入。 例如,执行以下操作:
from django.views import View
代替:
from django.views.generic.base import View
模板样式
在 Django 模板代码中,在大括号和标签内容之间放置一个(并且只有一个)空格。
这样做:
{{ foo }}
不要这样做:
{{foo}}
视图样式
在 Django 视图中,视图函数中的第一个参数应该被称为
request
。这样做:
def my_view(request, foo): # ...
不要这样做:
def my_view(req, foo): # ...
模特风格
字段名称应全部小写,使用下划线而不是驼峰命名。
这样做:
class Person(models.Model): first_name = models.CharField(max_length=20) last_name = models.CharField(max_length=40)
不要这样做:
class Person(models.Model): FirstName = models.CharField(max_length=20) Last_Name = models.CharField(max_length=40)
class Meta
应该出现在 字段定义之后的 ,用一个空行分隔字段和类定义。这样做:
class Person(models.Model): first_name = models.CharField(max_length=20) last_name = models.CharField(max_length=40) class Meta: verbose_name_plural = 'people'
不要这样做:
class Person(models.Model): first_name = models.CharField(max_length=20) last_name = models.CharField(max_length=40) class Meta: verbose_name_plural = 'people'
也不要这样做:
class Person(models.Model): class Meta: verbose_name_plural = 'people' first_name = models.CharField(max_length=20) last_name = models.CharField(max_length=40)
模型内部类和标准方法的顺序应该如下(注意这些不是全部必须的):
所有数据库字段
自定义管理器属性
class Meta
def __str__()
def save()
def get_absolute_url()
任何自定义方法
如果为给定的模型字段定义了
choices
,则将每个选项定义为一个元组列表,并将全大写的名称作为模型的类属性。 例子:class MyModel(models.Model): DIRECTION_UP = 'U' DIRECTION_DOWN = 'D' DIRECTION_CHOICES = [ (DIRECTION_UP, 'Up'), (DIRECTION_DOWN, 'Down'), ]
django.conf.settings的使用
模块通常不应使用存储在顶层 django.conf.settings
中的设置(即 在导入模块时进行评估)。 对此的解释如下:
手动配置设置(即 不依赖于 DJANGO_SETTINGS_MODULE 环境变量)是允许和可能的,如下所示:
from django.conf import settings
settings.configure({}, SOME_SETTING='foo')
但是,如果在 settings.configure
行之前访问任何设置,这将不起作用。 (在内部,settings
是一个 LazyObject
,如果尚未配置,则在访问设置时会自动配置自身)。
所以,如果有一个包含如下代码的模块:
from django.conf import settings
from django.urls import get_callable
default_foo_view = get_callable(settings.FOO_VIEW)
...然后导入这个模块将导致设置对象被配置。 这意味着第三方在顶层导入模块的能力与手动配置设置对象的能力不兼容,或者在某些情况下变得非常困难。
代替上面的代码,必须使用一定程度的惰性或间接性,例如 django.utils.functional.LazyObject
、django.utils.functional.lazy()
或 lambda
。
杂项
- 标记所有字符串以进行国际化; 有关详细信息,请参阅 i18n 文档 。
- 删除更改代码时不再使用的
import
语句。 flake8 将为您识别这些导入。 如果需要保留未使用的导入以向后兼容,请使用# NOQA
标记结束以消除 flake8 警告。 - 系统地从代码中删除所有尾随空格,因为它们会添加不必要的字节,给补丁添加视觉混乱,有时还会导致不必要的合并冲突。 一些 IDE 可以配置为自动删除它们,大多数 VCS 工具可以设置为在差异输出中突出显示它们。
- 请不要把你的名字放在你贡献的代码中。 我们的政策是将贡献者的名字保留在与 Django 一起分发的
AUTHORS
文件中——而不是分散在代码库本身中。 如果您进行了多个微不足道的更改,请随意在补丁中包含对AUTHORS
文件的更改。