• 3.1
  • 3.2
  • 6.1
  • Версия документации: 5.0

Стиль кодинга

Пожалуйста, следуйте этим стандартам кодирования при написании кода для 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 содержит некоторые исключенные файлы (устаревшие модули, которые мы не хотим очищать, и некоторый сторонний код, который поставщики Django), а также некоторые исключенные ошибки, которые мы не считаем грубыми нарушениями. Помните, что PEP 8 — это всего лишь руководство. Старайтесь, чтобы формат вашего кода соответствовал уже существующему коду в проекте.

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

  • Для интерполяции строковых переменных можно использовать %, f-строки или 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).
        """
        ...
    

Импорты

  • Используйте 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, стандартная библиотека, сторонние библиотеки, другие компоненты Django, локальный компонент Django, try/exceptions. Отсортируйте строки в каждой группе в алфавитном порядке по полному имени модуля. Поместите все 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 %}
    
  • Внутри фигурных скобок разделяйте токены одинарными пробелами, за исключением . для доступа к атрибуту и ​​``|`` для фильтра.

    Делайте это:

    {% 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)

…тогда импорт этого модуля приведет к настройке объекта настроек. Это означает, что возможность для третьих лиц импортировать модуль на верхнем уровне несовместима с возможностью настройки объекта настроек вручную или делает это очень сложным в некоторых обстоятельствах.

Вместо этого кода необходимо использовать уровень 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.

Back to Top