アプリケーション¶
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プロジェクト全体の中で固有である必要があります。
警告
マイグレーションがアプリケーションに適用された後でこの属性を変更すると、プロジェクトに不整合な変更が生じたり、再利用可能なアプリの場合、そのアプリの既存のインストールに影響を与えることになります。これは、
AppConfig.labelがデータベーステーブルやマイグレーションファイル内でアプリを依存関係リストで参照する際に使用されるためです。
- 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を発生させます。Requires the app registry to be fully populated unless the
require_readyargument is set toFalse.require_readybehaves exactly as inapps.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")
警告
Although you can access model classes as described above, avoid interacting with the database in your
ready()implementation. This includes model methods that execute queries (save(),delete(), manager methods etc.), and also raw SQL queries viadjango.db.connection. Yourready()method will run during startup of every management command. For example, even though the test database configuration is separate from the production settings,manage.py testwould still execute some queries against your production database!注釈
通常の初期化処理では、
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にしておくことをお勧めします。
初期化プロセス¶
アプリケーションはどう読み込まれるか¶
When Django starts, django.setup() is responsible for populating the
application registry.
- setup(set_prefix=True)[ソース]¶
下記によって Django を設定します:
設定を読み込む。
ロギングをセットアップする。
set_prefixが True の場合、URLリゾルバのスクリプトのプレフィックスを、 定義されていればFORCE_SCRIPT_NAMEに、そうでなければ/に設定する。アプリケーション・レジストリを初期化する。
この関数は以下の場合に自動で呼び出されます:
Django の ASGI や WSGI サポート経由で HTTP サーバを実行する場合。
管理コマンドを起動するとき。
それ以外の場合、たとえばプレーンなPythonスクリプトでは、明示的に呼び出す必要があります。
アプリケーションレジストリは 3 段階で初期化されます。それぞれの段階で、 Django は全てのアプリケーションを INSTALLED_APPS の順番で処理します。
まず Django は
INSTALLED_APPSの各アイテムをインポートします。アプリケーション設定クラスであれば、Django は
name属性で定義されたアプリケーションのルートパッケージをインポートします。Python パッケージの場合、 Django はapps.pyサブモジュールにあるアプリケーション設定を探すか、あるいはデフォルトのアプリケーション設定を作成します。"この時点では、どのモデルもインポートしてはいけません!"
言い換えると、アプリケーションのルートパッケージとアプリケーションの configuration クラスを定義するモジュールは、間接的であってもモデルをインポートすべきではありません。
厳密に言えば、Django はアプリケーションの設定が読み込まれた時点でモデルのインポートを許可します。しかし、
INSTALLED_APPSの順番に無用な制約が加わらないようにするため、この段階ではモデルをインポートしないことを強く推奨します。Once this stage completes, APIs that operate on application configurations such as
get_app_config()become usable.それから Django は、各アプリケーションの
modelsサブモジュールがあれば、それをインポートしようとします。アプリケーションの
models.pyまたはmodels/__init__.pyですべてのモデルを定義またはインポートする必要があります。そうしないと、この時点でアプリケーションのレジストリが完全に登録されていない可能性があり、ORM が誤動作する可能性があります。Once this stage completes, APIs that operate on models such as
get_model()become usable.Finally Django runs the
ready()method of each application configuration.
トラブルシューティング¶
初期化中に遭遇する可能性のある一般的な問題をいくつか紹介します:
AppRegistryNotReady: これは、アプリケーション設定やモデルモジュールのインポートが、アプリレジストリに依存するコードをトリガした場合に発生します。For example,
gettext()uses the app registry to look up translation catalogs in applications. To translate at import time, you needgettext_lazy()instead. (Usinggettext()would be a bug, because the translation would happen at import time, rather than at each request depending on the active language.)モデルモジュールのインポート時に ORM でデータベースクエリを実行すると、この例外も発生します。すべてのモデルが利用可能になるまで、ORM は適切に機能しません。
This exception also happens if you forget to call
django.setup()in a standalone Python script.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というコマンドを使用します。