アプリケーション

Django には、設定の保存と調査の手段を提供するインストール済みアプリケーションのレジストリがあり、利用可能な モデル のリストもアクセスできます。

このレジストリは apps と呼ばれ、 django.apps で利用できます:

>>> from django.apps import apps
>>> apps.get_app_config("admin").verbose_name
'Administration'

プロジェクトとアプリケーション

プロジェクト (project) という単語は、Django の web アプリケーションを指します。プロジェクトの Python パッケージは主に settings モジュールで定義されますが、通常は他のファイルも含まれます。たとえば、 django-admin startproject mysite を実行すると、mysite プロジェクトディレクトリが作成され、その中には settings.pyurls.pyasgi.pywsgi.py などのファイルが含まれる mysite Python パッケージが作られます。プロジェクトパッケージは、fixture や CSS、テンプレートなど特定のアプリケーションに束縛されないファイルも含まれることがふつうです。

プロジェクトのルートディレクトリ (manage.py があるディレクトリ) は、プロジェクトと一緒にインストールされるすべてのアプリケーションのコンテナとして機能します。

アプリケーション (application) という言葉は、何らかの機能を提供する Python パッケージを意味します。アプリケーションはさまざまなプロジェクトで 再利用する ことができます。

アプリケーションには、モデル、ビュー、テンプレート、テンプレートタグ、静的ファイル、ミドルウェアなどが含まれます。これらは一般に INSTALLED_APPS 設定で有効になり、それ以外では URLconf、 MIDDLEWARE 設定、テンプレート継承などの仕組みから使われます。

Django のアプリケーションは、フレームワークのさまざまなパーツとやりとりをするコードの集まりであると理解するのは大切です。Application オブジェクトのようなものは存在しません。しかしながら、Django がインストール済みのアプリケーションの主に設定やイントロスペクションとやりとりをする必要があることもあります。そのため、インストールアプリケーションごとのメタデータは、アプリケーションレジストリが AppConfig インスタンス内に保存しています。

プロジェクトパッケージがアプリケーションとみなされず、モデルなどを持てないといった制限はありません (その場合は INSTALLED_APPS に設定を追加する必要があります。)。

アプリケーションを設定する

アプリケーションを設定するためには、アプリケーション内に apps.py モジュールを作成し、そこに AppConfig のサブクラスを定義してください。

INSTALLED_APPS にアプリケーションモジュールへのドット区切りパスが含まれている場合、デフォルトでは、 Django が apps.py サブモジュールの中に AppConfig サブクラスを一つでも見つけると、その設定をアプリケーションに使用します。この動作は AppConfig.defaultFalse に設定すれば無効にできます。

apps.py モジュールに複数の AppConfig のサブクラスが含まれている場合、Djangoは AppConfig.defaultTrue である単一のサブクラスを探します。

もし AppConfig のサブクラスが見つからなければ、 AppConfig の基底クラスが使用されます。

あるいは、INSTALLED_APPS に設定クラスへのドット区切りパスを記述して、明示的に指定することもできます:

INSTALLED_APPS = [
    ...,
    "polls.apps.PollsAppConfig",
    ...,
]

アプリケーション開発者向け

例えば、あなたが"Rock 'n' roll"という名前のプラガブルなアプリケーションを作っているとしたら、このようにアプリケーションのadminに適切な名前をつけることになるでしょう:

# rock_n_roll/apps.py

from django.apps import AppConfig


class RockNRollConfig(AppConfig):
    name = "rock_n_roll"
    verbose_name = "Rock ’n’ roll"

RockNRollConfigINSTALLED_APPS'rock_n_roll' を含むときに自動的に読み込まれます。もしこれを防止したい場合、 defaultFalse に設定してください。

異なる動作をする AppConfig サブクラスを複数用意することができます。Django にどれをデフォルトで使うかを教えるには、 defaultTrue に設定してください。ユーザがデフォルトでない設定を選びたい場合は、 INSTALLED_APPS の設定で 'rock_n_roll' をその特定のクラスへのドット区切りパスに置き換える必要があります。

AppConfig.name 属性は、この設定がどのアプリケーションに適用されるかを Django に伝えます。その他の属性は AppConfig API リファレンスで定義できます。

AppConfig サブクラスはどこに定義しても構いません。 apps.py の規約は、 INSTALLED_APPS に設定クラスへのパスではなく、アプリケー ションモジュールへのパスが含まれている場合に、Django がそれらを自動的に読み込むようにしているだけです。

注釈

アプリケーションの __init__.py でアプリケーションレジストリをインポートする場合、apps という名前は apps サブモジュールと衝突します。 ベストプラクティスはそのコードをサブモジュールに移動してインポートすることです。回避策はレジストリを別の名前でインポートすることです:

from django.apps import apps as django_apps

アプリケーションユーザー向け

anthology という名前のプロジェクト内にて "Rock 'n' roll" を利用するものの、その表示は "Jazz Manouche" としたいとします。この場合は設定を以下のようにします。

# anthology/apps.py

from rock_n_roll.apps import RockNRollConfig


class JazzManoucheConfig(RockNRollConfig):
    verbose_name = "Jazz Manouche"


# anthology/settings.py

INSTALLED_APPS = [
    "anthology.apps.JazzManoucheConfig",
    # ...
]

この例ではプロジェクト固有の設定クラスを apps.py というサブモジュールに呼び出しています。 これは慣習であり、必須ではありません。 AppConfig サブクラスはどこに定義しても構いません。

この状況では、外部のアプリケーションに存在するため、設定クラスへのドット区切りパスが INSTALLED_APPS に含まれている必要があります。自動的に検出することはできません。

アプリケーションの設定

class AppConfig[ソース]

アプリケーション設定オブジェクトはアプリケーションのメタデータを保存します。 いくつかの属性は AppConfig サブクラスで設定できます。他の属性は Django によって設定され、読み取り専用です。

設定可能な属性

AppConfig.name

アプリケーションへの Python フルパス、たとえば 'django.contrib.admin'

この属性は設定がどのアプリケーションに適用されるかを定義します。全ての AppConfig サブクラスで設定する必要があります。

Djangoプロジェクト全体の中で固有である必要があります。

AppConfig.label

アプリケーション用のショートネーム 例 "'admin'"

この属性により、2つのアプリケーションのラベルが競合している場合に、アプリケーションのラベルを変更できます。デフォルトは name の最後のコンポーネントです。これは有効な Python 識別子でなければなりません。

Djangoプロジェクト全体の中で固有である必要があります。

警告

Changing this attribute after migrations have been applied for an application will result in breaking changes to a project or, in the case of a reusable app, any existing installs of that app. This is because AppConfig.label is used in database tables and migration files when referencing an app in the dependencies list.

AppConfig.verbose_name

人間が読めるアプリケーション名、たとえば "Administration"。

この属性のデフォルトは label.title() です。

AppConfig.path

アプリケーションディレクトリへのファイルシステムのパス、たとえば '/usr/lib/pythonX.Y/dist-packages/django/contrib/admin'

ほとんどの場合、Django は自動的にこれを検出して設定しますが、 AppConfig サブクラスのクラス属性として、明示的にオーバーライドを指定することもできます。例えば、アプリパッケージが複数のパスを持つ namespace package である場合などです。

AppConfig.default

この属性を False に設定すると、 Django が自動的に設定クラスを選択しないようにします。これは、apps.pyAppConfig サブクラスが一つだけ定義されているが、 Django にデフォルトでそれを使わせたくない場合に便利です。

この属性を True に設定すると、 Django に設定クラスを自動的に選択するように指示します。これは、apps.py が複数の AppConfig サブクラスを定義していて、 Django にそのうちの一つをデフォルトで使わせたい場合に便利です。

デフォルトではこの属性は設定されていません。

AppConfig.default_auto_field[ソース]

このアプリ内のモデルに追加する暗黙の主キー型です。これを使うと、サードパーティアプリの主キー型を AutoField にしておくことができます。

デフォルトでは DEFAULT_AUTO_FIELD の値です。

読み取り専用属性

AppConfig.module

アプリケーションのルートモジュール、たとえば <module 'django.contrib.admin' from 'django/contrib/admin/__init__.py'>

AppConfig.models_module

モデルを含むモジュール、たとえば <module 'django.contrib.admin.models' from 'django/contrib/admin/models.py'>

アプリケーションが models モジュールを含んでいない場合は None になります。 pre_migratepost_migrate といったデータベース関連のシグナルは、 models モジュールを持つアプリケーションに対してのみ発行されることに注意してください。

メソッド

AppConfig.get_models(include_auto_created=False, include_swapped=False)[ソース]

このアプリケーションの Model クラスのイテラブルを返します。

アプリのレジストリが完全に入力されている必要があります。

AppConfig.get_model(model_name, require_ready=True)[ソース]

与えられた model_name を持つ Model を返します。 model_name は大文字小文字を区別しません。

このアプリケーションにそのようなモデルが存在しない場合、 LookupError を発生させます。

require_ready 引数が False に設定されていない限り、アプリのレジストリが完全に登録されている必要があります。 require_readyapps.get_model() と全く同じ動作をします。

AppConfig.ready()[ソース]

サブクラスはこのメソッドをオーバーライドして、シグナルの登録などの初期化タスクを実行できます。 このメソッドは、レジストリが完全に登録されるとすぐに呼び出されます。

AppConfig クラスが定義されているモジュールレベルでモデルをインポートすることはできませんが、 import ステートメントか get_model() を使って ready() でインポートできます。

モデル シグナル を登録する場合、モデルクラスそのものを使うのではなく、その文字列ラベルで送信者を参照できます。

実装例:

from django.apps import AppConfig
from django.db.models.signals import pre_save


class RockNRollConfig(AppConfig):
    # ...

    def ready(self):
        # importing model classes
        from .models import MyModel  # or...

        MyModel = self.get_model("MyModel")

        # registering signals with the model's string label
        pre_save.connect(receiver, sender="app_label.MyModel")

警告

上記のようにモデルクラスにアクセスすることはできますが、 ready() の実装でデータベースとやり取りすることは避けてください。これには、クエリを実行するモデルメソッド (save(), delete(),マネージャメソッドなど) や、 django.db.connection を介した素の SQL クエリも含まれます。 ready() メソッドはすべての管理コマンドの起動時に実行されます。たとえば、テスト用のデータベースの設定が本番用の設定とは異なっていても、 manage.py test本番用 データベースに対してクエリを実行します!

注釈

通常の初期化処理では、 ready メソッドは Django から一度だけ呼び出されます。しかし、特にインストールされたアプリケーションを操作するテストでは、ready は複数回呼び出されるかもしれません。 そのような場合は、idempotent メソッドを書くか、 AppConfig クラスにフラグを付けて、一度だけ実行されるべきコードの再実行を防いでください。

アプリとしての名前空間 (namespace) パッケージ

__init__.py ファイルを持たない Python パッケージは "namespace package" と呼ばれ、 sys.path 上の異なる場所にある複数のディレクトリにまたがっている可能性があります (PEP 420 を参照してください)。

Djangoアプリケーションは(設定に応じて)、Djangoがテンプレートや静的アセットを探す単一のベースファイスシステムパスを必要とします。したがって、名前空間パッケージは以下のいずれかが真である場合にのみ、Django アプリケーションになることができます。

  1. 名前空間パッケージは実際には単一の場所にしか存在しません(つまり、複数のディレクトリに分散していないということです)。
  2. アプリケーションの設定に使われる AppConfig クラスには path クラス属性があり、これは Django がアプリケーションの単一のベースパスとして使う絶対ディレクトリパスです。

これらの条件のどちらも満たさない場合、Django は ImproperlyConfigured を発生させます。

アプリケーションレジストリ

apps

アプリケーションレジストリは、以下の公開APIを提供しています。以下に記載されていないメソッドは非公開とみなされ、予告なく変更される可能性があります。

apps.ready

レジストリが完全に登録され、すべての AppConfig.ready() メソッドが呼び出された後に True に設定される真偽値属性です。

apps.get_app_configs()

AppConfig インスタンスのイテラブルを返します。

apps.get_app_config(app_label)

与えられた app_label を持つアプリケーションの AppConfig を返します。そのようなアプリケーションが存在しない場合は LookupError を返します。

apps.is_installed(app_name)

与えられた名前のアプリケーションがレジストリに存在するかどうかを調べます。 app_name はアプリのフルネームで、たとえば 'django.contrib.admin' です。

apps.get_model(app_label, model_name, require_ready=True)

与えられた app_labelmodel_name を持つ Model を返します。 ショートカットとして、このメソッドは app_label.model_name 形式の引数も受け付けます。 model_name は大文字小文字を区別しません。

そのようなアプリケーションやモデルが存在しない場合 LookupError を発生させます。 正確に1つのドットを含まない単一の引数で呼び出された場合、 ValueError を発生させます。

require_ready 引数が False に設定されていない限り、アプリのレジストリが完全に登録されている必要があります。

require_readyFalse に設定することで、 アプリのレジストリを作成している間 、特にモデルをインポートする2番目のフェーズでモデルを検索できます。この場合、get_model() はモデルをインポートするのと同じ効果があります。主なユースケースは、モデルクラスを AUTH_USER_MODEL のような設定で構成することです。

require_readyFalse の場合、get_model() はアプリのレジストリが完全に入力されるまで、完全に機能しない (例えば、逆アクセサが存在しない) モデルクラスを返します。このため、常に require_ready をデフォルト値の True にしておくことをお勧めします。

初期化プロセス

アプリケーションはどう読み込まれるか

Django が起動すると、 django.setup() がアプリケーションレジストリの入力を行います。

setup(set_prefix=True)[ソース]

下記によって Django を設定します:

  • 設定を読み込む。
  • ロギングをセットアップする。
  • set_prefix が True の場合、URLリゾルバのスクリプトのプレフィックスを、 定義されていれば FORCE_SCRIPT_NAME に、そうでなければ / に設定する。
  • アプリケーション・レジストリを初期化する。

この関数は以下の場合に自動で呼び出されます:

  • Django の ASGI や WSGI サポート経由で HTTP サーバを実行する場合。
  • 管理コマンドを起動するとき。

それ以外の場合、たとえばプレーンなPythonスクリプトでは、明示的に呼び出す必要があります。

Changed in Django 5.0:

アプリのレジストリが完全に登録される前にアプリがデータベースとやり取りをすると RuntimeWarning を発生させます。

アプリケーションレジストリは 3 段階で初期化されます。それぞれの段階で、 Django は全てのアプリケーションを INSTALLED_APPS の順番で処理します。

  1. まず Django は INSTALLED_APPS の各アイテムをインポートします。

    アプリケーション設定クラスであれば、Django は name 属性で定義されたアプリケーションのルートパッケージをインポートします。Python パッケージの場合、 Django は apps.py サブモジュールにあるアプリケーション設定を探すか、あるいはデフォルトのアプリケーション設定を作成します。

    "この時点では、どのモデルもインポートしてはいけません!"

    言い換えると、アプリケーションのルートパッケージとアプリケーションの configuration クラスを定義するモジュールは、間接的であってもモデルをインポートすべきではありません。

    厳密に言えば、Django はアプリケーションの設定が読み込まれた時点でモデルのインポートを許可します。しかし、 INSTALLED_APPS の順番に無用な制約が加わらないようにするため、この段階ではモデルをインポートしないことを強く推奨します。

    この段階が完了すると、 get_app_config() のようなアプリケーションの設定を操作するAPIが使えるようになります。

  2. それから Django は、各アプリケーションの models サブモジュールがあれば、それをインポートしようとします。

    アプリケーションの models.py または models/__init__.py ですべてのモデルを定義またはインポートする必要があります。そうしないと、この時点でアプリケーションのレジストリが完全に登録されていない可能性があり、ORM が誤動作する可能性があります。

    この段階が完了すると、 get_model() のようなモデルを操作するAPIが使えるようになります。

  3. 最後に Django は、各アプリケーション設定の ready() メソッドを実行します。

トラブルシューティング

初期化中に遭遇する可能性のある一般的な問題をいくつか紹介します:

  • AppRegistryNotReady: これは、アプリケーション設定やモデルモジュールのインポートが、アプリレジストリに依存するコードをトリガした場合に発生します。

    たとえば、 gettext() はアプリケーションの翻訳カタログを検索するためにアプリレジストリを使います。インポート時に翻訳するには、代わりに gettext_lazy() が必要です。(gettext() を使うと、アクティブな言語に応じてリクエストごとに翻訳が行われるのではなく、インポート時に翻訳が行われるのでバグになります)。

    モデルモジュールのインポート時に ORM でデータベースクエリを実行すると、この例外も発生します。すべてのモデルが利用可能になるまで、ORM は適切に機能しません。

    この例外は、スタンドアロンの Python スクリプトで django.setup() を呼び出すのを忘れた場合にも起こります。

  • ImportError: cannot import name ... これはインポートのシーケンスがループしてしまう場合に起こります。

    このような問題をなくすためには、モデルモジュール間の依存関係を最小にし、インポート時の作業をできるだけ少なくする必要があります。インポート時にコードを実行しないようにするには、そのコードを関数に移動させ、その結果をキャッシュします。コードは、最初にその結果が必要になったときに実行されます。この概念は「遅延評価」として知られています。

  • django.contrib.admin はインストールされたアプリケーションの admin モジュールの自動検出を自動的に行います。これを防ぐには、 INSTALLED_APPS'django.contrib.admin' の代わりに 'django.contrib.admin.apps.SimpleAdminConfig' を含めるように変更してください。

  • RuntimeWarning: Accessing the database during app initialization is discouraged. この警告は、アプリが準備完了前に実行されるデータベースクエリに対して発生します。例えば、モジュールのインポート中や AppConfig.ready() メソッド内などです。このような早すぎるデータベースクエリは、すべての管理コマンドの起動時に実行されるため、プロジェクトの起動が遅くなったり、古いデータがキャッシュされたり、マイグレーションが保留中の場合には失敗する可能性があるため、推奨されません。

    たとえば、よくある間違いは、フォームフィールドの選択肢を入力するためにデータベースクエリを作成することです:

    class LocationForm(forms.Form):
        country = forms.ChoiceField(choices=[c.name for c in Country.objects.all()])
    

    上の例では、 QuerySet がイテレートされるため、 Country.objects.all() からのクエリがモジュールのインポート時に実行されます。警告を回避するには、代わりに ModelChoiceField を使用します:

    class LocationForm(forms.Form):
        country = forms.ModelChoiceField(queryset=Country.objects.all())
    

    この警告を引き起こしたコードを見つけやすくするために、Pythonで 警告をエラーとして扱う ことでスタックトレースを明らかにできます。例えば、python -Werror manage.py shell というコマンドを使用します。

Back to Top