アプリケーション¶
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.py
、urls.py
、asgi.py
、wsgi.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.default
を False
に設定すれば無効にできます。
apps.py
モジュールに複数の AppConfig
のサブクラスが含まれている場合、Djangoは AppConfig.default
が True
である単一のサブクラスを探します。
もし AppConfig
のサブクラスが見つからなければ、 AppConfig
の基底クラスが使用されます。
あるいは、INSTALLED_APPS
に設定クラスへのドット区切りパスを記述して、明示的に指定することもできます:
INSTALLED_APPS = [
...,
"polls.apps.PollsAppConfig",
...,
]
アプリケーションユーザー向け¶
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.py
でAppConfig
サブクラスが一つだけ定義されているが、 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_migrate
やpost_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_ready
はapps.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 アプリケーションになることができます。
名前空間パッケージは実際には単一の場所にしか存在しません(つまり、複数のディレクトリに分散していないということです)。
アプリケーションの設定に使われる
AppConfig
クラスにはpath
クラス属性があり、これは Django がアプリケーションの単一のベースパスとして使う絶対ディレクトリパスです。
これらの条件のどちらも満たさない場合、Django は ImproperlyConfigured
を発生させます。
アプリケーションレジストリ¶
- apps¶
アプリケーションレジストリは、以下の公開APIを提供しています。以下に記載されていないメソッドは非公開とみなされ、予告なく変更される可能性があります。
- apps.ready¶
レジストリが完全に登録され、すべての
AppConfig.ready()
メソッドが呼び出された後にTrue
に設定される真偽値属性です。
- 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_label
とmodel_name
を持つModel
を返します。 ショートカットとして、このメソッドはapp_label.model_name
形式の引数も受け付けます。model_name
は大文字小文字を区別しません。そのようなアプリケーションやモデルが存在しない場合
LookupError
を発生させます。 正確に1つのドットを含まない単一の引数で呼び出された場合、ValueError
を発生させます。require_ready
引数がFalse
に設定されていない限り、アプリのレジストリが完全に登録されている必要があります。require_ready
をFalse
に設定することで、 アプリのレジストリを作成している間 、特にモデルをインポートする2番目のフェーズでモデルを検索できます。この場合、get_model()
はモデルをインポートするのと同じ効果があります。主なユースケースは、モデルクラスをAUTH_USER_MODEL
のような設定で構成することです。require_ready
がFalse
の場合、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
の順番で処理します。
まず Django は
INSTALLED_APPS
の各アイテムをインポートします。アプリケーション設定クラスであれば、Django は
name
属性で定義されたアプリケーションのルートパッケージをインポートします。Python パッケージの場合、 Django はapps.py
サブモジュールにあるアプリケーション設定を探すか、あるいはデフォルトのアプリケーション設定を作成します。"この時点では、どのモデルもインポートしてはいけません!"
言い換えると、アプリケーションのルートパッケージとアプリケーションの configuration クラスを定義するモジュールは、間接的であってもモデルをインポートすべきではありません。
厳密に言えば、Django はアプリケーションの設定が読み込まれた時点でモデルのインポートを許可します。しかし、
INSTALLED_APPS
の順番に無用な制約が加わらないようにするため、この段階ではモデルをインポートしないことを強く推奨します。この段階が完了すると、
get_app_config()
のようなアプリケーションの設定を操作するAPIが使えるようになります。それから Django は、各アプリケーションの
models
サブモジュールがあれば、それをインポートしようとします。アプリケーションの
models.py
またはmodels/__init__.py
ですべてのモデルを定義またはインポートする必要があります。そうしないと、この時点でアプリケーションのレジストリが完全に登録されていない可能性があり、ORM が誤動作する可能性があります。この段階が完了すると、
get_model()
のようなモデルを操作するAPIが使えるようになります。最後に 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
というコマンドを使用します。