编写代码以包含在Django中时,请遵循这些编码标准。
pre-commit 是一个用于管理提交前挂钩的框架。这些挂钩有助于在提交代码以供审查之前识别简单的问题。通过在代码审查之前检查这些问题,审查者可以将注意力集中在更改本身上,还可以帮助减少CI运行的数量。
要使用该工具,请首先安装 pre-commit
然后git挂钩:
$ python -m pip install pre-commit
$ pre-commit install
...\> py -m pip install pre-commit
...\> pre-commit install
在第一次提交时 pre-commit
将安装这些钩子,这些钩子安装在它们自己的环境中,在第一次运行时需要一段时间才能安装。后续检查将大大加快速度。如果发现错误,则会显示相应的错误消息。如果错误是与 black
或 isort
然后,该工具将继续为您修复它们。如果您对更改满意,请查看更改并重新提交。
所有文件都应使用 black 自动格式化程序。这项工作将由 pre-commit
如果已配置的话。
项目存储库包括一个 .editorconfig
文件。我们建议将文本编辑器与 EditorConfig 支持避免缩进和空格问题。Python文件使用4个空格进行缩进,而HTML文件使用2个空格。
除非另有规定,遵循 PEP 8 .
使用 flake8 以检查此区域中的问题。请注意,我们的 .flake8
文件包含一些被排除的文件(我们不在乎清理的过时模块和一些Django供应商的第三方代码),以及一些我们不认为是严重违规的被排除的错误。记住 PEP 8 只是一个指南,因此将尊重周围代码的样式作为主要目标。
例外于 PEP 8 是我们对线路长度的规定。不要将代码行数限制在79个字符以内,如果这意味着代码看起来更难看或更难读。我们最多允许88个字符,因为这是使用的行长 black
。当您运行时,将包括此检查 flake8
。文档、注释和文档字符串应以79个字符换行,即使 PEP 8 显示为72岁。
字符串变量插值可以使用 %-formatting , f-strings ,或 str.format()
视情况而定,目标是最大限度地提高代码的可读性。
对可读性的最终判断由合并者自行决定。作为指导,f字符串应仅使用普通变量和属性访问,对于更复杂的情况,提前分配局部变量::
# 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字符串不应用于任何可能需要翻译的字符串,包括错误和日志消息。一般来说 format()
更加详细,因此首选其他格式方法。
不要浪费时间对现有代码进行不相关的重构来调整格式方法。
避免在注释中使用“we”,例如“loop over”而不是“we loop over”。
变量、函数和方法名(即 poll.get_unique_voters()
不是 poll.getUniqueVoters()
)
使用 InitialCaps
用于类名(或用于返回类的工厂函数)。
在DocStrings中,遵循现有DocStrings的样式和 PEP 257 .
在测试中,使用 assertRaisesMessage()
和 assertWarnsMessage()
而不是 assertRaises()
和 assertWarns()
所以您可以检查异常或警告消息。使用 assertRaisesRegex()
和 assertWarnsRegex()
仅当需要正则表达式匹配时。
使用 assertIs(…, True/False)
用于测试布尔值,而不是 assertTrue()
和 assertFalse()
,因此您可以检查实际的布尔值,而不是检查表达的真实性。
在测试文档字符串中,说明每个测试所演示的预期行为。不要包含诸如“测试”或“确保”之类的前言。
为不明确的问题保留票据参考,其中票据具有文档字符串或注释中不容易描述的其他详细信息。在这样一句话的末尾包括票号:
def test_foo():
"""
A test docstring looks like this (#123456).
"""
...
使用 isort 要使用以下准则自动执行导入分类,请执行以下操作。
快速启动:
$ python -m pip install "isort >= 5.1.0"
$ isort .
...\> py -m pip install "isort >= 5.1.0"
...\> isort .
这运行 isort
从当前目录递归地修改任何不符合准则的文件。如果需要无序导入(例如,为了避免循环导入),请使用如下注释:
import module # isort:skip
将导入放在以下组中:未来、标准库、第三方库、其他Django组件、本地Django组件、Try/Excepts。按模块全名的字母顺序对每个组中的行进行排序。全部放置 import module
之前的陈述 from module import objects
在每个部分。对其他Django组件使用绝对导入,对本地组件使用相对导入。
在每一行中,按字母顺序排列项目,将大写项目分组在小写项目之前。
使用圆括号分隔长线,并将续行缩进4个空格。在最后一次导入后包含尾随逗号,并将右括号放在自己的行上。
在最后一次导入和任何模块级代码之间使用一个空行,并在第一个函数或类上方使用两个空行。
例如(注释仅供解释):
django/contrib/admin/example.py
¶# 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模板代码中遵循以下规则。
{% extends %}
应该是第一个非注释行。
这样做:
{% extends "base.html" %}
{% block content %}
<h1 class="font-semibold text-xl">
{{ pages.title }}
</h1>
{% endblock content %}
或者这样:
{# This is a comment #}
{% extends "base.html" %}
{% block content %}
<h1 class="font-semibold text-xl">
{{ pages.title }}
</h1>
{% endblock content %}
不要这样做:
{% load i18n %}
{% extends "base.html" %}
{% block content %}
<h1 class="font-semibold text-xl">
{{ pages.title }}
</h1>
{% endblock content %}
在中间恰好留出一个空格 {{
、可变内容和 }}
。
这样做:
{{ user }}
不要这样做:
{{user}}
在……里面 {% load ... %}
,按字母顺序列出库。
这样做:
{% load i18n l10 tz %}
不要这样做:
{% load l10 i18n tz %}
在中间恰好留出一个空格 {%
、标记内容和 %}
。
这样做:
{% load humanize %}
不要这样做:
{%load humanize%}
把那个 {% block %}
中的标记名 {% endblock %}
如果它不在同一行上,则标记。
这样做:
{% block header %}
Code goes here
{% endblock header %}
不要这样做:
{% block header %}
Code goes here
{% endblock %}
Inside curly braces, separate tokens by single spaces, except for around the
.
for attribute access and the |
for a filter.
这样做:
{% if user.name|lower == "admin" %}
不要这样做:
{% if user . name | lower == "admin" %}
{{ user.name | upper }}
在模板中使用 {% extends %}
,避免顶层缩进 {% block %}
标签。
这样做:
{% extends "base.html" %}
{% block content %}
不要这样做:
{% extends "base.html" %}
{% block content %}
...
在django视图中,应调用视图函数中的第一个参数 request
.
这样做:
def my_view(request, foo): ...
不要这样做:
def my_view(req, foo): ...
字段名应全部为小写,使用下划线而不是camelcase。
这样做:
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):
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",
}
或者,考虑使用 枚举类型 **
class MyModel(models.Model):
class Direction(models.TextChoices):
UP = "U", "Up"
DOWN = "D", "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 documentation 有关详细信息。
移除 import
更改代码时不再使用的语句。 flake8 将为您识别这些进口产品。如果需要保留未使用的导入以实现向后兼容,请使用 # NOQA
让雪花般的警告安静下来。
系统地从代码中删除所有尾随的空白,因为这些空白添加了不必要的字节,给补丁添加了视觉混乱,并且偶尔也会导致不必要的合并冲突。一些IDE可以配置为自动删除它们,大多数VCS工具可以设置为在diff输出中突出显示它们。
请不要把你的名字写在你的代码里。我们的政策是在 AUTHORS
使用django分发的文件——不分散在代码库本身。请随意更改 AUTHORS
如果您做了不止一个微不足道的更改,请将文件保存在补丁中。
有关Django使用的javascript代码样式的详细信息,请参见 JavaScrip代码 .
7月 22, 2024