質問
ジャンゴ view は関数を指しているため、機能を少しだけ変更したい場合には問題になる可能性があります。はい、関数内に 100 万個のキーワード引数やさらに多くの if ステートメントを含めることもできますが、私はオブジェクト指向のアプローチを考えていました。
たとえば、ユーザーを表示するページがあります。このページはグループを表示するページに非常に似ていますが、別のデータ モデルを使用するだけという点ではそれほど似ていません。グループにはメンバーなどもいます...
1 つの方法は、ビューをクラス メソッドにポイントし、そのクラスを拡張することです。誰かがこのアプローチを試したことがありますか、または他のアイデアがありますか?
解決
独自の汎用ビュー クラスを作成して使用し、以下を定義しました。 __call__
したがって、クラスのインスタンスは呼び出し可能です。私は本当にそれが好き;Django のジェネリック ビューでは、キーワード引数を使用してある程度のカスタマイズが可能ですが、OO ジェネリック ビュー (その動作が多数の別個のメソッドに分割されている場合) では、サブクラス化を介してさらにきめ細かいカスタマイズができるため、同じことを繰り返すことが大幅に減ります。(Django の汎用ビューではまったく許可されていないものを微調整する必要があるたびに、同じビューの作成/更新ロジックを書き直すのにうんざりします)。
にコードを投稿しました djangosnippets.org.
私が考える唯一の本当の欠点は、内部メソッド呼び出しの急増であり、パフォーマンスに多少の影響を与える可能性があります。これはそれほど心配することではないと思います。Web アプリで Python コードの実行がパフォーマンスのボトルネックになることはほとんどありません。
アップデート:ジャンゴ自身の 一般的なビュー はクラスベースになりました。
アップデート:FWIW、この回答が書かれて以来、クラスベースのビューについての意見を変更しました。いくつかのプロジェクトでこれらを広範囲に使用した後、機能が非常に多くの異なる場所に分散され、サブクラスが非常に依存しているため、満足のいく DRY で記述できるものの、後で読み取ったり保守したりするのが非常に難しいコードになる傾向があると感じました。スーパークラスとミックスインのあらゆる実装の詳細について。今私はそう感じています テンプレート応答 ビュー デコレータは、ビュー コードを分解するためのより良い解決策です。
他のヒント
クラスベースのビューを使用する必要がありましたが、使用前に常にビュー クラスをインスタンス化する必要がなく、URLconf でクラスの完全名を使用できるようにしたいと考えていました。私を助けてくれたのは、驚くほど単純なメタクラスでした。
class CallableViewClass(type):
def __call__(cls, *args, **kwargs):
if args and isinstance(args[0], HttpRequest):
instance = super(CallableViewClass, cls).__call__()
return instance.__call__(*args, **kwargs)
else:
instance = super(CallableViewClass, cls).__call__(*args, **kwargs)
return instance
class View(object):
__metaclass__ = CallableViewClass
def __call__(self, request, *args, **kwargs):
if hasattr(self, request.method):
handler = getattr(self, request.method)
if hasattr(handler, '__call__'):
return handler(request, *args, **kwargs)
return HttpResponseBadRequest('Method Not Allowed', status=405)
これで、ビュー クラスをインスタンス化して、そのインスタンスをビュー関数として使用することも、単に URLconf でクラスを指定し、メタクラスにビュー クラスをインスタンス化 (および呼び出し) させることもできます。これは、最初の引数をチェックすることで機能します __call__
– もしそれが HttpRequest
, を使用してビュー クラスをインスタンス化しようとするのはナンセンスであるため、これは実際の HTTP リクエストである必要があります。 HttpRequest
実例。
class MyView(View):
def __init__(self, arg=None):
self.arg = arg
def GET(request):
return HttpResponse(self.arg or 'no args provided')
@login_required
class MyOtherView(View):
def POST(request):
pass
# And all the following work as expected.
urlpatterns = patterns(''
url(r'^myview1$', 'myapp.views.MyView', name='myview1'),
url(r'^myview2$', myapp.views.MyView, name='myview2'),
url(r'^myview3$', myapp.views.MyView('foobar'), name='myview3'),
url(r'^myotherview$', 'myapp.views.MyOtherView', name='otherview'),
)
(このスニペットを次の場所に投稿しました) http://djangosnippets.org/snippets/2041/)
モデルからのデータを表示するだけの場合は、 Django の一般的なビュー?これらは、独自のビューや、URL パラメーターのビューへのマッピング、データのフェッチ、エッジ ケースの処理、出力のレンダリングなどを作成することなく、モデルからのデータを簡単に表示できるように設計されています。
いつでもクラスを作成し、そのクラスをオーバーライドできます。 __call__
関数を作成し、URL ファイルがクラスのインスタンスを指すようにします。をご覧ください。 フォームウィザード クラスを使用して、これがどのように行われるかを確認してください。
組み合わせてはいけないものを組み合わせようとしているように思えます。調べようとしているオブジェクトがユーザー オブジェクトであるかグループ オブジェクトであるかに応じて、ビューで異なる処理を実行する必要がある場合は、2 つの異なるビュー関数を使用する必要があります。
一方で、object_detail タイプのビューから抽出したい一般的なイディオムもあるかもしれません...おそらく、デコレーターまたは単なるヘルパー関数を使用できますか?
-ダン
少し複雑なことをしたい場合を除き、汎用ビューを使用することをお勧めします。これらはその名前が示すよりもはるかに強力で、モデル データを表示するだけの場合は汎用ビューで十分です。
通常は汎用ビューが適していますが、最終的には URL を自由に処理できます。FormWizard は、RESTful API 用の一部のアプリと同様に、クラスベースの方法で処理を実行します。
基本的に URL では、呼び出し可能なものを提供するための変数と場所がたくさん与えられます。どの呼び出し可能なものを提供するかは完全にユーザー次第です - 標準的な方法は関数を提供することです - しかし、最終的に Django はユーザーの行動に制限を設けません。
これを行う方法の例をもう少し挙げると良いだろうという意見には同意しますが、おそらく FormWizard から始めるのがよいでしょう。
ページ間で共通の機能を共有したい場合は、カスタム タグを検討することをお勧めします。彼らはかなりです 簡単に作成できます, 、そして非常に強力です。
また、 テンプレートは他のテンプレートから拡張できます. 。これにより、ページのレイアウトを設定するための基本テンプレートを用意し、これを空白を埋める他のテンプレート間で共有することができます。テンプレートは任意の深さまでネストできます。関連するページの別々のグループのレイアウトを 1 か所で指定できるようになります。
Django の汎用ビューを使用できます。Django の汎用ビューを通じて目的の機能を簡単に実現できます