クラスベースビューの利点は何ですか?


82

今日、Django 1.3 alphaが出荷されていることを読みました。最も宣伝されている新機能は、クラスベースのビューの導入です。関連するドキュメント
を読みましたが、それらを使用することで得られる大きな利点™を見つけるのが難しいので、ここでそれらを理解するための助けを求めています。ドキュメントから高度な例を見て みましょう。

urls.py

from books.views import PublisherBookListView

urlpatterns = patterns('',
    (r'^books/(\w+)/$', PublisherBookListView.as_view()),
)

views.py

from django.shortcuts import get_object_or_404
from django.views.generic import ListView
from books.models import Book, Publisher

class PublisherBookListView(ListView):

    context_object_name = "book_list"
    template_name = "books/books_by_publisher.html",

    def get_queryset(self):
        self.publisher = get_object_or_404(Publisher, name__iexact=self.args[0])
        return Book.objects.filter(publisher=self.publisher)

    def get_context_data(self, **kwargs):
        # Call the base implementation first to get a context
        context = super(PublisherBookListView, self).get_context_data(**kwargs)
        # Add in the publisher
        context['publisher'] = self.publisher
        return context

それでは、この質問に対して5分で自分で作成した「プレーンオールドビュー」ソリューションと比較してみましょう(エラーが発生した場合はお詫びします)。

urls.py

urlpatterns = patterns('books.views',
    url(r'^books/(\w+)/$', 'publisher_books_list', name="publisher_books_list"),
)

views.py

from django.shortcuts import get_object_or_404
from books.models import Book, Publisher

def publisher_books_list(request, publisher_name):
    publisher = get_object_or_404(Publisher, name__iexact=publisher_name)
    book_list = Book.objects.filter(publisher=publisher)

    return render_to_response('books/books_by_publisher.html', {
        "book_list": book_list,
        "publisher": publisher,
    }, context_instance=RequestContext(request))

私にとって2番目のバージョンは次のように見えます。

  • 機能的に同等
  • もっと読みやすい(self.args[0]?ひどい!)
  • 短い
  • DRY準拠以上

私が見逃している大きなものはありますか?なぜそれらを使用する必要がありますか?それらはドキュメントにありますか?もしそうなら、理想的なユースケースは何でしょうか?あるミックスイン便利なことは?

貢献してくれた人に感謝します!

不思議に思うかもしれない人のためのPS、私も一般的なビューに夢中になることはありませんでした:いくつかの高度な機能が必要になるとすぐに、それらは通常のビューよりも短くなりませんでした。


4
ええ、私も大きなアドバンテージを見ていません。これについての大きな答えを見たいです。
M.ライアン

1
完全に同意します。私は特にself.args [0]またはself.kwargs ['slug']にうんざりしています。次のように、URLパラメータのデフォルト値を提供することも非常に困難になりました
。defpublisher_books_list

回答:


48

クラスをサブクラス化し、特定の場合にget_context_dataなどのメソッドを改良し、残りをそのままにしておくことができます。関数ではそれを行うことはできません。

たとえば、前のビューが行うすべてのことを行う新しいビューを作成する必要があるかもしれませんが、コンテキストに追加の変数を含める必要があります。元のビューをサブクラス化し、get_context_dataメソッドをオーバーライドします。

また、テンプレートを個別のメソッドにレンダリングするために必要なステップを分離すると、コードがより明確になります。メソッドでの実行が少ないほど、理解しやすくなります。通常のビュー機能では、すべてが1つの処理装置にダンプされます。


2
ええ、私はこれを見ることができます。これにより、RESTfulに移行するか、フルサイトにするか、モバイルサイトにするかを決定しようとするときに、オーバーライドが容易になり、頻繁に混同される可能性があります。これにより、機能が派生している間、その決定を可能な限り延期することができます。PylonsのWebwareモジュールにはこれがあり、非常に便利でした。とは言うものの、クラスベースのビューは、__ call __()メソッドをオーバーライドすることでDjangoで長い間可能でした。
エルフ・スタンバーグ2010

9
非常に良い点があるので答えを受け入れる...しかし、私はそのような問題を解決することはめったにないので、それでもそれらを使用する必要性を感じていません。ありがとう!
agos 2010

18

self.args[0]気になる場合は、次の方法があります。

urlpatterns = patterns('books.views',
    url(r'^books/(?P<slug>\w+)/$', 'publisher_books_list', name="publisher_books_list"),
)

次にself.kwargs['slug']、代わりに使用して、少し読みやすくすることができます。


10

サンプルの関数とクラスは、機能が同じではありません。

クラスベースバージョンは無料でページ付けを提供し、GET以外のHTTP動詞の使用を禁止します。

これを関数に追加したい場合は、はるかに長くなります。

しかし、それは確かにもっと複雑です。


2
違いを指摘するための+1ですが、個人的には、require_GETdjango-paginationは、使用するのは簡単で、簡潔で、明示的などであると思います。
トマスツ・ジーリンスキー

4

これは私がこれを聞いた最初のものです-そして私はそれが好きです。

ここで私が見ている利点は、正直なところ、ビューがDjango全体とより一貫していることです。モデルはクラスであり、ビューもそうあるべきだといつも感じていました。私はすべてがそうであるというわけではないことを知っていますが、ビューとモデルは2つの頻繁に使用されるタイプです。

技術的なメリットは?さて、Pythonではすべてがクラス(またはオブジェクト?)です-それで本当に違いはありますか?そもそも99%の糖衣構文ではないですか?


一貫性により、コードの再利用が可能になると思います。あなたの見解が特定のパターンに一致している場合、それらは基本的に多くの定型文を削減します。たとえば、モデルに基づくフォームは、クラスベースのビューを使用して非常にすばやく生成できます。いくつかの追加フィールドが必要な場合は、少し注意が必要になります。3つのモデルと2つの追加フィールドに基づくフォームが必要な場合は、おそらくそれほど労力を節約することはできません。
wobbily_col 2015年

1

クラスベースのビューについて考える1つの方法は、補助輪がオフになっているDjango管理者のようなものであるため、柔軟性が大幅に向上します(ただし、理解が難しくなります)。

たとえば、管理者のリスト表示は、明らかに汎用のListViewに基づいています。モデルまたはクエリセットのみを定義する最も単純なリストビュー。

class MyExampleView(ListView);
    model = ExampleModel 

独自のテンプレートを提供する必要がありますが、基本的には最も基本的なModelAdminと同じです。モデル管理者のlist_display属性は、表示するフィールドを指示しますが、ListViewではテンプレートでこれを行います。

class SpeciesAdmin(admin.ModelAdmin):
    list_display = ['name']
admin.site.register(ExampleModel , ExampleModelAdmin)

管理者にはパラメータがあります

list_per_page = 100

これは、ページごとのオブジェクトの数を定義します。リストビューには

paginate_by = 100

同じことを達成します。同様に、管理者を大幅にカスタマイズすることを検討すると、多くの重複が見られます。

ここのこのサイトは、彼らが何をしているのかについてのより良い考えをあなたに与えるはずです。

http://ccbv.co.uk/

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.