注記: 私はちゃんとした私はPythonプログラマーですが、Pythonを多用しています。継承クラスを書いたり、イテレータや内包表記を使ったりしています。私が言いたいのは、満杯言語の理解、例えばその通りPython オブジェクトを構成するもの、__init__.py
モジュールを指定する以外に必要な理由など。Django に関しては、私は (SO の助けを借りて) マルチアプリ サイトを作成し、Django のテンプレート システム、ブロック、およびそれらのネスト方法を非常に楽しんでいます。これで、私のアプリは完全に分離され、再利用できるようになりましたか? これがこの投稿の主題です。
この免責事項を述べるのは、多くの Django リソースが、これらのことを知っていることを前提としているように思われるからです。このため、(サブパワー) ユーザーにとっては、一部のドキュメントや SO の質問を理解するのが難しくなります。そのため、この質問にはその点を念頭に置いて回答してください。
質問
これらの質問は、Django で startapp を使用して新しいアプリを作成するのはいつですか?によるはかんそしてその答えによって与えられた@アンティ・ラシネンジェームズ・ベネットの2008年のPyCon プレゼンテーション
ベネット氏のプレゼンテーションの重要なポイントは次のとおりです。
- サイトはアプリの集合体です
- アプリは1つのことだけをうまくこなす
すると、彼の「プロジェクトの結合は再利用を妨げる」というセクションにたどり着きます。そこには、次のようなことが書かれています。
- Python パス上の単一モジュール (登録、タグ付けなど)
- パッケージ内の関連モジュール (ellington.events、ellington.podcasts など)
質問0
この場合の「モジュール」とは、他のアプリで構成されたアプリのことでしょうか?
質問1
(関連機能と共有モデルを持つアプリ)
アプリがモデルを共有する場合はどうすればいいですか?
バレット氏のスライドでは、ユーザー登録とユーザー プロファイルは別個のものであり、別々のアプリであるべきであることが示唆されています (彼は確かに、プロファイルはユーザー登録とは何の関係もないと述べています)。
両方必要な場合、プロジェクトには次のような 2 つのアプリが含まれることになります。
- ユーザー登録
- ユーザープロフィール
アプリはuser-profile
のユーザーモデルを必要とするのでしょうかuser-registration
? それとも単一のアプリ ( module
) を作成しますか:
- ユーザーアプリ
- 登録
- プロフィール
両方を含むものはどれですか?
質問2
(機能は異なるがモデルは共通するアプリ)
質問 1 の例を拡張して、メイン アプリ (またはメイン アプリによって使用される他のアプリ) がユーザー モデルの一部 (たとえば、チャット サイトの場合は最近アクティブになったメンバー) を利用しているものとします。
明らかに、メイン アプリはユーザー モデルからこの情報を取得します。メイン アプリはuser-app
モジュールの下にバンドルされるようになりますか?
これは最良の例ではないかもしれませんが、要点は次のとおりです。
app-dependency
との2つのアプリがありapp-needs-dependency
、それぞれのアプリは1つのことを1つだけうまくこなします...app-needs-dependency
は からの情報を必要としていますapp-dependency
。この場合、どうすればいいでしょうか。すべてelse about はapp-needs-dependency
完全に分離されていますapp-dependency
(他のプロジェクトで使用できます)?
質問3
(柔軟性を重視したアプリの作成)
現在、私のサイトにはいくつかのアプリがあります。各アプリはそれぞれの役割を担い、それをうまくこなしています。この場合、メイン アプリはランディング ページ/概要として機能します。
他のすべてのアプリで、メイン アプリの静的ファイルとテンプレート ファイルを使用/継承するようにします。
すべての静的ファイルとテンプレートはどこに保存すればよいですか? メイン アプリに保存し、それを他のアプリのデフォルトとして設定しますか? または、これらの静的ファイル/テンプレート (例base.css
: base.html
) はどこに保存すればよいですか? 冗長ではありますが、他のアプリごとにこれらのファイルのコピーを作成して、実行できるようにしますか?
どちらがアプリの柔軟性を高めますか?
ベストアンサー1
質問0
Python のコンテキストにおける「モジュール」とは、単に定義とステートメントを含むファイルです。したがって、「パッケージ内の関連モジュール」とは、実際には「コードの実行内容に基づいてコードを別々のファイルに分割する」ことを意味します。
これを「他のアプリで作成されたアプリ」と説明すると、Django のアプリの概念と Python のモジュールの概念 (前述のように、コードを格納するファイルにすぎません) が混同されてしまいます。
質問1
アプリがモデルを共有する場合はどうすればいいですか?
それでも、「アプリは 1 つのことだけをうまく行う」という格言に従うようにしてください。この場合、プロファイル アプリと登録アプリを別々にすることは良い考えのようです。なぜなら、これらのアプリはまったく異なる機能を持っているからです。登録アプリには、ユーザーがサイトに登録できるようにするためのロジックが含まれます。プロファイル アプリは、ユーザーについてどのような情報を保存するかに関するものです。
これら 2 つのアプリが相互に関係を持つことには何の問題もありません - 以下を参照してください。
質問2
メイン アプリ (またはメイン アプリによって使用される他のアプリ) がユーザー モデルの一部 (たとえば、チャット サイトの場合は最近アクティブになったメンバー) を利用するとします。明らかに、メイン アプリはユーザー モデルからこの情報を取得します。メイン アプリはユーザー アプリの下にバンドルされるようになりますか?
いいえ。他のアプリへのリンクがある別のアプリである必要があります。
ユーザーモデルは良い例です。Djangoでは、カスタムユーザーモデルこれにより、ユーザーに関する必要な追加データを保存できます。
現在、ユーザー登録や認証などを行うサードパーティのアプリが数多く存在します。これらはDjangoのデフォルトのユーザーモデルだけでなく、あらゆるユーザーモデルで動作するように設計されています。その方法は、get_user_model()
User
直接インポートするのではなく、モデルを参照する必要がある場所であればどこでもdjango.contrib.auth.models.User
。
つまり、独自のプロジェクト用に定義したユーザー モデルでサードパーティ アプリを使用できるということです。
Django のget_user_model()
ユーティリティは、非常に一般的なユースケースに対応するためのものです。ただし、同じ原則を独自のアプリに拡張できます。アプリ間にスワップ可能な依存関係がある場合は、それをスワップアウトする方法を提供できます。たとえば、アプリを使用する他のプロジェクトが代替を指定できるようにする設定/構成などです。
Djangoエコシステムには、このような設定例が何百もあります。たとえば、Django自体には独自のdjango.contrib.auth
認証アプリが付属しています。ただし、独自の認証ロジックを実装したい場合、認証アプリ全体を自分で再実装する必要はありません(それは大変な作業です)。代わりに、認証バックエンド認証アプリが認証に使用するものです。認証アプリは、どのプロジェクトでも最小限の労力で機能のコア部分を交換できるように設計されています。
そのためmain
、アプリでは、どのモデルを使用するかを制御する設定を定義できますprofile
。つまり、他のユーザーが別のプロファイル モデルを使用したい場合は、この設定を変更するだけで準備完了です。アプリに縛られることはなくなりますprofile
。
たとえば、main
ユーザー データを表示するビューがあり、別のアプリによって提供される登録ビューへのリンクも提供するアプリがあるとします。どの登録アプリを使用しているかに関係なく、他のユーザーがそのアプリを使用できるようにする必要があります。このビューを次のように再利用可能にすることができます。
でmain/views.py
:
from django.contrib.auth import get_user_model
from django.conf import settings
from django.urls import reverse
class UserDetailView(DetailView):
# First of all, we're using get_user_model so that a project
# can specify whatever user model it wants, and still use this
# view.
model = get_user_model()
def get_context_data(self, *args, *kwargs):
ctx = super().get_context_data(*args, **kwargs)
# We want to add a link to a registration view into this template context.
# But we want this to be configurable.
# Your REGISTRATION_URL would be something like 'profile:registration'
ctx['registration_link'] = reverse(settings.REGISTRATION_URL)
return ctx
質問3
この場合、メイン アプリはランディング ページ/概要として機能します。他のすべてのアプリでメイン アプリの静的ファイルとテンプレート ファイルを使用/継承するようにします。すべての静的ファイルとテンプレートはどこに保存すればよいですか?
テンプレートはそれぞれのアプリに保存する必要があります。メイン アプリが基本テンプレートを提供している場合は、それらのテンプレートはメイン アプリ内に保存する必要があります。
プロフィール アプリが登録ビューを提供する場合、そのためのテンプレートはプロフィール アプリ内に存在する必要があります。メイン アプリから基本テンプレートを拡張しても問題はありません。これは、必要に応じてプロジェクトによって簡単に上書きできます。
2 つのアプリが互いにどのように関連しているかについて仮定を立てることは問題ありません。ただし、それらの仮定を上書きできるように注意する必要があります。