Стиль кодирования

Пожалуйста, следуйте этим стандартам кодирования при написании кода для включения в Django.

Проверки перед коммитом

pre-commit is a framework for managing pre-commit hooks. These hooks help to identify simple issues before committing code for review. By checking for these issues before code review it allows the reviewer to focus on the change itself, and it can also help to reduce the number of CI runs.

Чтобы воспользоваться инструментом, сначала установите pre-commit, а затем git hooks:

$ python -m pip install pre-commit
$ pre-commit install
...\> py -m pip install pre-commit
...\> pre-commit install

On the first commit pre-commit will install the hooks, these are installed in their own environments and will take a short while to install on the first run. Subsequent checks will be significantly faster. If an error is found an appropriate error message will be displayed. If the error was with isort then the tool will go ahead and fix them for you. Review the changes and re-stage for commit if you are happy with them.

Стиль питона

  • Пожалуйста, соблюдайте стиль отступов, продиктованный в файле .editorconfig. Мы рекомендуем использовать текстовый редактор с поддержкой EditorConfig, чтобы избежать проблем с отступами и пробелами. В файлах Python для отступов используется 4 пробела, а в файлах HTML - 2 пробела.

  • Если не указано иное, следуйте PEP 8.

    Используйте flake8 для проверки проблем в этой области. Обратите внимание, что наш файл setup.cfg содержит некоторые исключенные файлы (устаревшие модули, об очистке которых мы не заботимся, и некоторый сторонний код, который поставляется Django), а также некоторые исключенные ошибки, которые мы не считаем грубыми нарушениями. Помните, что PEP 8 - это только руководство, поэтому соблюдение стиля окружающего кода является главной целью.

    Исключением из PEP 8 являются наши правила по длине строк. Не ограничивайте строки кода 79 символами, если это означает, что код выглядит значительно более уродливым или его труднее читать. Мы разрешаем до 119 символов, поскольку это ширина обзора кода на GitHub; все, что длиннее, требует горизонтальной прокрутки, что затрудняет обзор. Эта проверка включается, когда вы выполняете flake8. Документация, комментарии и docstrings должны быть обернуты в 79 символов, хотя PEP 8 предлагает 72.

  • Используйте четыре пробела для отступа.

  • Используйте отступ в четыре интервала, а не вертикальное выравнивание:

    raise AttributeError(
        'Here is a multiline error message '
        'shortened for clarity.'
    )
    

    Вместо:

    raise AttributeError('Here is a multiline error message '
                         'shortened for clarity.')
    

    Это позволяет лучше использовать пространство и избежать необходимости выравнивания строк при изменении длины первой строки.

  • Используйте одинарные кавычки для строк, или двойную кавычку, если строка содержит одинарную кавычку. Не тратьте время на несвязный рефакторинг существующего кода, чтобы привести его в соответствие с этим стилем.

  • Интерполяция строковых переменных может использовать :py<<<<0 >>>, :py<<<<1 >>>, или :py<<<<2 >>> в зависимости от ситуации, с целью максимизации читабельности кода.

    Окончательные суждения о читабельности остаются на усмотрение Слияния. В качестве руководства, 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() является более многословным, поэтому предпочтительнее использовать другие методы форматирования.

    Не тратьте время на несвязный рефакторинг существующего кода для настройки метода форматирования.

  • Избегайте использования «мы» в комментариях, например, «Loop over», а не «We loop over».

  • Используйте подчеркивание, а не camelCase, для имен переменных, функций и методов (т.е. poll.get_unique_voters(), а не poll.getUniqueVoters()).

  • Используйте InitialCaps для имен классов (или для фабричных функций, которые возвращают классы).

  • В документах следуйте стилю существующих документов и 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
    
  • Поместите импорт в эти группы: future, standard library, third-party libraries, other Django components, local Django component, 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 ставьте один (и только один) пробел между фигурными скобками и содержимым тега.

    Сделайте это:

    {{ foo }}
    

    Не делайте этого:

    {{foo}}
    

Вид стиля

  • В представлениях 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):
        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 documentation.
  • Удалите утверждения import, которые больше не используются, когда вы изменяете код. flake8 определит эти импорты для вас. Если неиспользуемый импорт должен остаться для обеспечения обратной совместимости, пометьте конец # NOQA, чтобы заглушить предупреждение flake8.
  • Систематически удаляйте из кода все пробелы в конце кода, поскольку они добавляют ненужные байты, визуально загромождают патчи и иногда могут вызывать ненужные конфликты слияния. Некоторые IDE могут быть настроены на автоматическое удаление пробелов, а большинство инструментов VCS могут быть настроены на их выделение в результатах различий.
  • Пожалуйста, не указывайте свое имя в коде, который вы предоставляете. Наша политика заключается в том, чтобы имена участников были указаны в файле AUTHORS, распространяемом вместе с Django - а не разбросаны по всей кодовой базе. Не стесняйтесь включать изменения в файл AUTHORS в свой патч, если вы вносите более чем одно тривиальное изменение.

Стиль JavaScript

Подробнее о стиле кода JavaScript, используемом в Django, смотрите JavaScript.

Вернуться на верх