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

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

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

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, то инструмент исправит их за вас. Просмотрите изменения и повторно отправьте их на фиксацию, если они вас устраивают.

Стиль питона

  • Все файлы должны быть отформатированы с помощью автоформатера black. Он будет выполняться pre-commit, если он настроен.

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

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

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

    Исключением из PEP 8 являются наши правила по длине строк. Не ограничивайте строки кода 79 символами, если это означает, что код выглядит значительно более уродливым или его труднее читать. Мы разрешаем до 88 символов, поскольку именно такая длина строки используется в black. Эта проверка включается при запуске flake8. Документация, комментарии и docstrings должны быть обернуты в 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() является более многословным, поэтому предпочтительнее использовать другие методы форматирования.

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

  • Избегайте использования «мы» в комментариях, например, «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).
        """
        ...
    
Changed in Django 4.0.3:

Весь Python-код в Django был переформатирован с помощью black.

Импорт

  • Используйте 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.

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