クラスベースのビュー-使用理由と使用方法

Djangoバージョン1.3では、クラスベースのビューが導入されました。これは、ビューをクラスとして記述する方法です。 ただし、ドキュメントは汎用ビューのみに関するものであり、クラスの形式で「ビュー」を記述する一般的な手法については説明していません。 ジェネリックビューの使用を開始し、その動作を変更しようとすると、ソースコードを見て何かを行う方法を理解する必要が出てきました。 そこで、私はこのテキストを書くことにしました。 その目的は、クラスベースのビューの使用方法と、これがどのように役立つかを説明することです。



やる気



アイデアは単純です-頻繁に使用される機能(たとえば、データベースからのオブジェクト/オブジェクトのリストの表示、コンテキストのテンプレートへの転送など)があり、非常に頻繁に使用されます。 単調なコードを記述する必要がないように、そのようなビューはフレームワークのコードで直接記述されます。 これらを使用するには、オブジェクトのタイプやコンテキストの転送先のテンプレートの名前など、特定のパラメーターのみを報告する必要があります。



たとえば、Publisherクラスがあり、このクラスのすべてのオブジェクトのリストをページに表示したいとします。 Django 1.2では次のような汎用ビューを使用します。



# urls.py from django.views.generic import list_detail from books.models import Publisher urlpatterns = patterns('', (r'^publishers/$', list_detail.object_list, { "queryset" : Publisher.objects.all(), }) )
      
      





目的のクエリセットをパラメータディクショナリに渡すだけで、他のすべてはすでに実装されています。



ただし、開発プロセス中に、もともと汎用として実装されていた「ビュー」の動作を変更する必要がある場合(非常に頻繁に発生します)、問題が発生します。

  1. 汎用ビューには、対象の動作を変更するパラメーターはありません。
  2. 汎用ビューのパラメーターを形成するコードは、個別に記述された「ビュー」のコードとボリュームが同等であり、URLCONFにあります。


ビューを作成するために既製のDjango機能を使用できる一方で、その動作を任意の部分で変更できるテクノロジーが必要です。



クラスの一般的なビュー



ジェネリックビューで何かを変更できるようにするために、開発者は、メインパラメーターがフィールドで表されるクラスの形式でそれらを表示することを決定し、機能は明確に機能に分割されます-個別のディスパッチ、個別のコンテキストの形成、個別のテンプレートのレンダリング(詳細以下を参照)。 このようなクラスからビューを継承し、パラメーターで渡すのではなく、変数と関数をそれらでオーバーラップできます。 これは 、クラスでのPublisherの例の実装の外観です。



 # views.py from django.views.generic import DetailView from books.models import Publisher class PublisherDetailView(DetailView): model = Publisher
      
      







urls.pyでは、「view」という名前の代わりに、記述されたクラスのas_view()メソッドが渡されます。



 urlpatterns = patterns('', (r'^publishers/$', PublisherDetailView.as_view()), )
      
      





モデルまたはtemplate_name型の変数は、関数ベースのビューでこれを行った方法と同様に、この関数のパラメーターとして渡すことができます。



ここで、たとえば、テンプレートに渡されるコンテキストを変更する必要がある場合、コンテキストの形成に関与するこのクラスの関数get_context_data()を再定義するだけです。 そして、コードはviews.pyにあるはずです。 どの汎用ビューがどの機能であり、何をするのかを把握するだけです。



不純物



着信要求パラメーターの処理方法、データベースからのデータの選択方法、および回答の作成方法に関する質問への回答は、多くの場合互いに独立しています。 場合によっては、HTMLページを回答として、時にはJSONオブジェクトを作成したいことがあります。 リクエストを処理し、両方のケースで使用されるデータベースを操作するための一般的なコードを作成する場合は、コンテキストからの応答を生成するすべてのメソッドのグループを何らかの方法で選択する必要があります。 この問題は、 不純物のパターン( ミックスイン )を使用して解決できます。



各クラスベースの汎用ビュー:

  1. 基本クラスViewから継承。
  2. 1つまたは複数の不純物から継承されます。


したがって、機能的な汎用ビューを拡張するには、次が必要です。

  1. ドキュメントに含まれる不純物を調べてください。
  2. 興味のある動作が実装されている機能を果たすこれらの不純物を見つけてください。
  3. この関数をオーバーライドします。


クラスとしてのすべての「ビュー」



クラスベースの汎用ビューを使用すると、すべての「ビュー」をクラスの形式で作成するようになります。これは、再現性と構造化を減らすという同じ考慮事項からです。 関数ベースの汎用ビューがどれもあなたにふさわしくない場合-上記の理由により、クラスベースの汎用ビューは常に役に立ちます。



表示する


すべての汎用ビューはこのクラスを継承します。 ディスパッチ()関数を実装します。これは、要求を受け入れ、HttpReponseを返します。これは、ビューであるため、常にビューである関数です。 as_view()関数は、dispatch()へのポインタを返すだけであり、関数ベースのビューとの類似性を明確にしています-最小限のバージョンでは、Viewクラスは、コントローラーがURLCONFから呼び出す関数を1つだけ含むクラスです。



Viewクラスは、関数get()、post()などを呼び出すことができます。 要求のタイプに応じて、そこに要求を渡します。





クラス形式の「ビュー」の簡単な実装の例は、たとえばここにあります 。 以下は複雑な例です-私のドキュメントの例の作り直し-は、クラスの形で「ビュー」を書くことの便利さをより完全に示しています。



挑戦する


このプロジェクトでは、クライアントから要求されたデータは、GET要求パラメーターに応じて、通常のHTMLページまたはJSONオブジェクトとして返される必要があります。



解決策


一般的なクラスの「ビュー」を作成し、2つの方法で答えを提示し、それをプロジェクト内の後続のすべての「ビュー」から継承できるようにする必要があります。



djangoでは、 TemplateResponseMixinが実装され、そのrender_to_response()関数は、テンプレートとして渡されたコンテキストをテンプレートとしてtemplate_nameで指定されたテンプレートをレンダリングできます。



HTMLの代わりにJSONを返す混合物を作成しましょう。

 class JsonResponseMixin(object): def render_to_reponse(self, context): return http.HttpResponse(self.convert_context_to_json(context), content_type='application/json') def convert_context_to_json(self, context, extract_from_queryset=None): pass
      
      







コンテキストをJSONに変換する関数は、このコンテキストが何であるかをすでに理解している必要があるため、実装されていません。



次に、HTMLとJSONの両方を返すことができるクラスを作成します。

 class MixedView(View, JsonResponseMixin, TemplateResponseMixin): def get_context(self, request): pass def get(self, request, *args, **kwargs): context = self.get_context(request) if request.GET.get('format', 'html') == 'json' or self.template_name is None: return JsonResponseMixin.render_to_reponse(self, context) else: return TemplateResponseMixin.render_to_response(self, context)
      
      







get関数は、Viewで宣言された関数をオーバーライドします。 GETパラメーターに応じて、コンテキストは2つの不純物のいずれかでレンダリングするためにレンダリングされ、JSONまたはHTMLを返します。 最初のケースでは、このコンテキストの翻訳をjsonで定義する関数が必要です。 2番目のケースでは、このコンテキストがレンダリングされるテンプレートの名前が必要になります。 この子孫である「ビュー」には、コンテキストを形成するget_context(request)、およびJSONに変換するconvert_context_to_json(context)、および特定のtemplate_nameの2つのメソッドを実装する必要があります。



最終ビューの実装は、たとえば次のようになります。

 class PublisherView(MixedView): def get_context(self, request): context = dict() context['publishers'] = Publisher.objects.all() return context template_name = 'publisher_list.html' def convert_context_to_json(self, context): json_context = dict() json_context['publisher_names'] = [p.name for p in context['publishers']] return json.dumps(json_context, encoding='utf-8', ensure_ascii=False)
      
      







おわりに



この記事では、Djangoドキュメンテーションに欠けているもの、つまりクラスベースのビューの背後にあるアイデアとそれらの使用方法を明確にしようとしました。 汎用ビューのこのような広範囲の使用の実践と、必要な場合のその後の拡張が、誰かにとって役立つと思われることを願っています。



ご清聴ありがとうございました。どんな批判も喜んでいます。



All Articles