Стиль кодинга¶
Пожалуйста, следуйте этим стандартам кодирования при написании кода для Django.
Проверки с помощью pre-commit¶
pre-commit — это фреймворк для управления хуками pre-commit. Эти хуки помогают выявлять простые проблемы перед отправкой кода на проверку. Проверка этих проблем перед отправкой кода позволяет проверяющему сосредоточиться на самом изменении, а также может помочь сократить количество запусков CI.
Чтобы использовать этот инструмент, сначала установите pre-commit, а затем git hooks:
$ python -m pip install pre-commit
$ pre-commit install
...\> py -m pip install pre-commit
...\> pre-commit install
При первом коммите pre-commit установит хуки, они устанавливаются в своих собственных средах и их установка займет немного времени при первом запуске. Последующие проверки будут значительно быстрее. Если обнаружена ошибка, будет отображено соответствующее сообщение об ошибке. Если ошибка была с black или isort, то инструмент продолжит работу и исправит их для вас. Проверьте изменения и подтвердите свои изменения для коммита, если вы ими довольны.
Стиль Python¶
Все файлы должны быть отформатированы с помощью автоформатера black. Это будет запущено через
pre-commit, если он настроен.Репозиторий проекта включает файл
.editorconfig. Мы рекомендуем использовать текстовый редактор с поддержкой EditorConfig, чтобы избежать проблем с отступами и пробелами. Файлы Python используют 4 пробела для отступов, а файлы HTML используют 2 пробела.Если не указано иное, следуйте PEP 8.
Используйте flake8, чтобы проверить наличие проблем в этой области. Обратите внимание, что наш файл
.flake8исключает некоторые ошибки, которые мы не считаем грубыми нарушениями. Помните, что PEP 8 — это всего лишь руководство, поэтому уважайте стиль окружающего кода как основную цель.Исключением из PEP 8 являются наши правила относительно длины строк. Мы допускаем до 88 символов в коде, так как именно такая длина строки используется в
black. Документация, комментарии и строки документации должны быть заключены в 79 символов. Эти ограничения проверяются при запуске Flake8.При интерполяции строковых переменных можно использовать %-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».
Используйте подчеркивания, а не camelCase, для имен переменных, функций и методов (т. е.
poll.get_unique_voters(), а неpoll.getUniqueVoters()).Используйте
InitialCapsдля имен классов.В строках документации следуйте стилю существующих строк документации и PEP 257.
В тестах используйте
assertRaisesMessage()иassertWarnsMessage()вместоassertRaises()иassertWarns()чтобы можно было проверить сообщение об исключении или предупреждении. ИспользуйтеassertRaisesRegex()иassertWarnsRegex()только если вам нужно сопоставление с регулярным выражением.Используйте
assertIs(…, True/False)для проверки логических значений, а неassertTrue()иassertFalse(), чтобы можно было проверить фактическое логическое значение, а не истинность выражения.В строках документации тестов укажите ожидаемое поведение, которое демонстрирует каждый тест. Не включайте преамбулы, такие как «Tests that» или «Гарантирует, что».
Зарезервируйте ссылки на тикеты для неясных проблем, когда тикет имеет дополнительные подробности, которые нельзя легко описать в строках документации или комментариях. Включите номер тикета в конец предложения, например:
def test_foo(): """ A test docstring looks like this (#123456). """ ...
Там, где это применимо, используйте обобщения распаковки, соответствующие PEP 448, такие как сопоставления слияния (
{**x, **y}) или последовательности ([*a, *b]). Это повышает производительность, читаемость и удобство обслуживания, одновременно уменьшая количество ошибок.
Импорты¶
Используйте isort для автоматизации сортировки импорта, следуя приведенным ниже рекомендациям.
Быстрый старт:
$ python -m pip install "isort >= 7.0.0" $ isort .
...\> py -m pip install "isort >= 7.0.0" ...\> isort .
Это запускает
isortрекурсивно из вашего текущего каталога, изменяя любые файлы, которые не соответствуют правилам. Если вам нужно, чтобы импорт был выполнен не по порядку (например, чтобы избежать циклического импорта), используйте такой комментарий:import module # isort:skip
Поместите импорт в эти группы: будущее, стандартная библиотека, сторонние библиотеки, другие компоненты Django, локальный компонент Django, пробные/исключения. Отсортируйте строки в каждой группе в алфавитном порядке по полному имени модуля. Поместите все инструкции
импортировать модульпередиз объектов импорта модуляв каждом разделе. Используйте абсолютный импорт для других компонентов Django и относительный импорт с одной точкой («из .foo import Bar») для локальных компонентов. Избегайте относительного импорта с несколькими точками.В каждой строке расположите элементы в алфавитном порядке, сгруппировав элементы с заглавными буквами перед элементами со строчными буквами.
Разрывайте длинные строки с помощью скобок и делайте отступы строк продолжения на 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 %}
Внутри фигурных скобок разделяйте токены одинарными пробелами, за исключением
.для доступа к атрибуту и ``|`` для фильтра.Делайте это:
{% 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 Metadef __str__()и другие магические методы Pythondef 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)
…тогда импорт этого модуля приведет к настройке объекта настроек. Это означает, что возможность для третьих лиц импортировать модуль на верхнем уровне несовместима с возможностью настройки объекта настроек вручную или делает это очень сложным в некоторых обстоятельствах.
Вместо этого кода необходимо использовать уровень laziness, например, django.utils.functional.LazyObject, django.utils.functional.lazy() или lambda.
Разнообразный¶
Отметить все строки для интернационализации; подробности см. в i18n-документации.
Удалите операторы
import, которые больше не используются при изменении кода. flake8 определит эти импорты для вас. Если неиспользуемый импорт необходимо сохранить для обратной совместимости, добавьте в конец строки комментарий# NOQA, чтобы заглушить предупреждение flake8.Систематически удаляйте все конечные пробелы из вашего кода, так как они добавляют ненужные байты, визуально загромождают патчи и могут также иногда вызывать ненужные конфликты слияния. Некоторые IDE можно настроить на автоматическое их удаление, а большинство инструментов VCS можно настроить на их выделение в результатах сравнения diff.
Пожалуйста, не указывайте свое имя в коде, который вы вносите. Наша политика заключается в том, чтобы сохранять имена участников в файле
AUTHORS, распространяемом с Django, а не разбросанными по всей кодовой базе. Не стесняйтесь включать изменение в файлAUTHORSв вашем патче, если вы вносите более одного тривиального изменения.
Стиль Javascript¶
Подробную информацию о стиле кода JavaScript, используемом Django, см. в документе Код JavaScript.