コーディングスタイル—Djangoドキュメント

提供:Dev Guides
< DjangoDjango/docs/3.2.x/internals/contributing/writing-code/coding-style
移動先:案内検索

コーディングスタイル

Djangoに含めるコードを作成するときは、これらのコーディング標準に従ってください。

事前コミットチェック

pre-commit は、pre-commitフックを管理するためのフレームワークです。 これらのフックは、レビューのためにコードをコミットする前に、単純な問題を特定するのに役立ちます。 コードレビューの前にこれらの問題をチェックすることで、レビュー担当者は変更自体に集中でき、CIの実行回数を減らすこともできます。

このツールを使用するには、最初にpre-commitをインストールし、次にgitフックをインストールします。

最初のコミットでpre-commitはフックをインストールします。これらは独自の環境にインストールされ、最初の実行でインストールするのに少し時間がかかります。 その後のチェックは大幅に高速化されます。 エラーが見つかった場合は、適切なエラーメッセージが表示されます。 エラーがisortにあった場合、ツールは先に進み、それらを修正します。 変更を確認し、問題がなければコミットのために再ステージングします。


Pythonスタイル

  • .editorconfigファイルに記載されているインデントスタイルに準拠してください。 インデントと空白の問題を回避するために、 EditorConfig をサポートするテキストエディターを使用することをお勧めします。 Pythonファイルはインデントに4つのスペースを使用し、HTMLファイルは2つのスペースを使用します。

  • 特に指定のない限り、 PEP 8 に従ってください。

    flake8 を使用して、この領域の問題を確認してください。 setup.cfgファイルには、除外されたファイル(クリーンアップを気にしない非推奨のモジュールと、Djangoベンダーが提供するサードパーティコード)と、重大な違反とは見なされない除外されたエラーが含まれていることに注意してください。 。 PEP 8 は単なるガイドであるため、周囲のコードのスタイルを主な目標として尊重してください。

    PEP 8 の例外は、行の長さに関する規則です。 コードの見た目が著しく醜い、または読みにくい場合は、コードの行を79文字に制限しないでください。 これはGitHubコードレビューの幅であるため、最大119文字を許可します。 それ以上のものは水平スクロールを必要とし、レビューをより困難にします。 このチェックは、flake8を実行するときに含まれます。 PEP 8 は72を推奨していますが、ドキュメント、コメント、およびdocstringは79文字でラップする必要があります。

  • インデントには4つのスペースを使用します。

  • 垂直方向の配置ではなく、4つのスペースぶら下げインデントを使用します。

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

    それ以外の:

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

    これにより、スペースがより有効に活用され、最初の行の長さが変更された場合に文字列を再配置する必要がなくなります。

  • 文字列には一重引用符を使用し、文字列に一重引用符が含まれている場合は二重引用符を使用します。 このスタイルに準拠するために、既存のコードの無関係なリファクタリングを行うのに時間を無駄にしないでください。

  • 文字列変数の補間では、コードの可読性を最大化する目的で、必要に応じて %-f ormatting f-strings 、またはstr.format()を使用できます。

    読みやすさの最終的な判断は、合併の裁量に委ねられています。 ガイドとして、f-stringはプレーン変数とプロパティへのアクセスのみを使用し、より複雑な場合には事前にローカル変数を割り当てる必要があります。

    # 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()はより冗長であるため、他のフォーマット方法が推奨されます。

    書式設定方法を調整するために、既存のコードの無関係なリファクタリングを行うのに時間を無駄にしないでください。

  • コメントでの「私たち」の使用は避けてください。 「ループオーバー」ではなく「ループオーバー」。

  • 変数、関数、およびメソッドの名前には、キャメルケースではなくアンダースコアを使用します(つまり、 poll.get_unique_voters()poll.getUniqueVoters()ではありません)。

  • クラス名(またはクラスを返すファクトリ関数)にはInitialCapsを使用します。

  • docstringでは、既存のdocstringと PEP 257 のスタイルに従います。

  • テストでは、assertRaises()assertWarns()の代わりに assertRaisesMessage()assertWarnsMessage()を使用して、例外または警告メッセージを確認できるようにします。 assertRaisesRegex()およびassertWarnsRegex()は、正規表現のマッチングが必要な場合にのみ使用してください。

    assertTrue()assertFalse()ではなく、assertIs(…, True/False)を使用してブール値をテストすると、式の真実性ではなく、実際のブール値を確認できます。

  • テストドキュメント文字列で、各テストが示す予想される動作を記述します。 「Teststhat」や「Ensuresthat」などの前文は含めないでください。

    チケットにdocstringやコメントで簡単に説明できない追加の詳細が含まれている不明瞭な問題のためにチケット参照を予約します。 次のように、文の最後にチケット番号を含めます。

    def test_foo():
        """
        A test docstring looks like this (#123456).
        """
        ...


輸入

  • isort を使用して、以下のガイドラインを使用してインポートの並べ替えを自動化します。

    クイックスタート:

    これは、現在のディレクトリからisortを再帰的に実行し、ガイドラインに準拠していないファイルを変更します。 インポートの順序を狂わせる必要がある場合(たとえば、循環インポートを回避するため)、次のようなコメントを使用します。

    import module  # isort:skip
  • インポートを次のグループに入れます:future、標準ライブラリ、サードパーティライブラリ、その他のDjangoコンポーネント、ローカルDjangoコンポーネント、try / excepts。 各グループの行を完全なモジュール名のアルファベット順に並べ替えます。 各セクションのfrom module import objectsの前にすべてのimport moduleステートメントを配置します。 他のDjangoコンポーネントには絶対インポートを使用し、ローカルコンポーネントには相対インポートを使用します。

  • 各行で、小文字の項目の前に大文字の項目がグループ化された項目をアルファベット順に並べます。

  • 括弧を使用して長い行を区切り、継続行を4スペースインデントします。 最後のインポートの後に末尾のコンマを含め、閉じ括弧を独自の行に置きます。

    最後のインポートとモジュールレベルのコードの間に1行の空白行を使用し、最初の関数またはクラスの上に2行の空白行を使用します。

    例(コメントは説明のみを目的としています):

    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テンプレートコードでは、中括弧とタグの内容の間に1つ(そして1つだけ)のスペースを入れます。

    これを行う:

    {{ foo }}

    これをしないでください:

    {{foo}}


ビュースタイル

  • Djangoビューでは、ビュー関数の最初のパラメーターはrequestと呼ばれる必要があります。

    これを行う:

    def my_view(request, foo):
        # ...

    これをしないでください:

    def my_view(req, foo):
        # ...


モデルスタイル

  • キャメルケースの代わりにアンダースコアを使用して、フィールド名をすべて小文字にする必要があります。

    これを行う:

    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は、フィールドが定義された後に表示され、フィールドとクラス定義を1行で区切ります。

    これを行う:

    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行の前にいずれかの設定にアクセスすると、これは機能しません。 (内部的には、settingsLazyObjectであり、設定がまだ構成されていない場合、設定にアクセスすると自動的に構成されます)。

したがって、次のようなコードを含むモジュールがある場合:

from django.conf import settings
from django.urls import get_callable

default_foo_view = get_callable(settings.FOO_VIEW)

…次に、このモジュールをインポートすると、設定オブジェクトが構成されます。 つまり、サードパーティがモジュールをトップレベルでインポートする機能は、設定オブジェクトを手動で構成する機能と互換性がないか、状況によっては非常に困難になります。

上記のコードの代わりに、django.utils.functional.LazyObjectdjango.utils.functional.lazy()lambdaなどのレベルの遅延または間接参照を使用する必要があります。


その他

  • 国際化のためにすべての文字列をマークします。 詳細については、 i18nドキュメントを参照してください。
  • コードの変更時に使用されなくなったimportステートメントを削除します。 flake8 は、これらのインポートを識別します。 下位互換性のために未使用のインポートを残す必要がある場合は、終了を# NOQAでマークして、flake8警告を消します。
  • 不要なバイトを追加し、パッチに視覚的な混乱を追加し、場合によっては不要なマージの競合を引き起こす可能性があるため、コードから末尾の空白をすべて体系的に削除します。 一部のIDEは、それらを自動的に削除するように構成でき、ほとんどのVCSツールは、diff出力でそれらを強調表示するように設定できます。
  • 投稿するコードに自分の名前を入れないでください。 私たちのポリシーは、Djangoで配布されるAUTHORSファイルに寄稿者の名前を保持することであり、コードベース自体全体に散らばることはありません。 些細な変更を複数行う場合は、パッチにAUTHORSファイルへの変更を自由に含めてください。


JavaScriptスタイル

Djangoで使用されるJavaScriptコードスタイルの詳細については、 JavaScript を参照してください。