62

Djangoビューは関数を指します。これは、機能を少しだけ変更したい場合に問題になる可能性があります。はい、関数内に数百万のキーワード引数とさらに多くのifステートメントを含めることができましたが、オブジェクト指向のアプローチを考えていました。

たとえば、ユーザーを表示するページがあります。このページは、グループを表示するページと非常によく似ていますが、別のデータモデルを使用する場合とはあまり似ていません。グループにもメンバーなどがいます...

1つの方法は、ビューをクラスメソッドにポイントしてから、そのクラスを拡張することです。誰かがこのアプローチを試したことがありますか、または他のアイデアがありますか?

4

9 に答える 9

46

独自のジェネリック ビュー クラスを作成して使用し、__call__クラスのインスタンスが呼び出し可能になるように定義しました。私は本当にそれが好き; Django のジェネリック ビューではキーワード引数を使用してある程度のカスタマイズが可能ですが、オブジェクト指向のジェネリック ビュー (動作がいくつかの個別のメソッドに分割されている場合) は、サブクラス化によってよりきめ細かいカスタマイズを行うことができます。(Django の一般的なビューでは許可されていないものを微調整する必要があるときはいつでも、同じビューの作成/更新ロジックを書き直すのにうんざりしています)。

djangosnippets.orgにいくつかのコードを投稿しました。

私が見た唯一の本当の欠点は、内部メソッド呼び出しの急増であり、パフォーマンスに多少影響を与える可能性があります。これはあまり問題ではないと思います。Python コードの実行が Web アプリのパフォーマンスのボトルネックになることはめったにありません。

UPDATE : Django 独自のジェネリック ビューがクラスベースになりました。

更新: FWIW、この回答が書かれて以来、クラスベースのビューに関する意見を変更しました。それらをいくつかのプロジェクトで広く使用した後、機能が非常に多くの異なる場所に分散しており、サブクラスが非常に依存しているため、書くのは満足のいく DRY ですが、後で読んで維持するのが非常に難しいコードになる傾向があると感じています。スーパークラスとミックスインのすべての実装の詳細について。TemplateResponseとビュー デコレータは、ビュー コードを分解するためのより良い答えだと感じています。

于 2008-08-29T04:29:22.053 に答える
13

クラスベースのビューを使用する必要がありましたが、ビュークラスを使用する前に常にインスタンス化することなく、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/に投稿しました)

于 2010-05-27T13:02:08.360 に答える
9

モデルからのデータを表示するだけなら、Django Generic Viewsを使用してみませんか? これらは、独自のビューや、URL パラメーターのビューへのマッピング、データのフェッチ、エッジ ケースの処理、出力のレンダリングなどに関するものを作成する必要なく、モデルからのデータを簡単に表示できるように設計されています。

于 2008-08-07T10:44:23.957 に答える
3

いつでもクラスを作成し、__call__関数をオーバーライドしてから、URL ファイルをクラスのインスタンスに向けることができます。FormWizardクラスを見て、これがどのように行われるかを確認できます。

于 2008-08-26T11:38:36.913 に答える
2

少し複雑なことをしたいのでなければ、一般的なビューを使用するのが良い方法です。それらは、その名前が示すよりもはるかに強力であり、モデルデータを表示するだけの場合は、汎用ビューがその役割を果たします。

于 2008-08-11T22:59:42.277 に答える
1

通常は汎用ビューが最適ですが、最終的にはURLを自由に処理できます。FormWizardは、RESTful API用の一部のアプリと同様に、クラスベースの方法で処理を実行します。

基本的にURLを使用すると、呼び出し可能変数を提供するための一連の変数と場所が与えられます。提供する呼び出し可能オブジェクトは完全にユーザー次第です。標準的な方法は関数を提供することですが、最終的にDjangoはユーザーの操作に制限を設けません。

これを行う方法の例がさらにいくつかあると私は同意しますが、FormWizardがおそらく出発点です。

于 2008-09-23T19:05:51.633 に答える
1

組み合わせてはいけないものを組み合わせようとしているように思えます。表示しようとしているのがユーザーオブジェクトであるかグループオブジェクトであるかに応じて、ビューで異なる処理を行う必要がある場合は、2つの異なるビュー関数を使用する必要があります。

一方、object_detailタイプのビューから抽出したい一般的なイディオムが存在する可能性があります...おそらく、デコレータまたは単にヘルパー関数を使用できますか?

-ダン

于 2008-08-03T17:40:25.553 に答える
1

Django Generic Views を使用できます。Django のジェネリック ビューを使用して、必要な機能を簡単に実現できます。

于 2014-10-08T05:53:09.677 に答える
1

ページ間で共通の機能を共有したい場合は、カスタム タグを検討することをお勧めします。非常に簡単に作成でき、非常に強力です。

また、テンプレートは他のテンプレートから拡張できます。これにより、ベース テンプレートを使用してページのレイアウトを設定し、空白を埋める他のテンプレート間でこれを共有できます。テンプレートは任意の深さにネストできます。1 か所で、関連するページの個別のグループのレイアウトを指定できます。

于 2008-08-26T11:30:50.050 に答える