Was ist der Vorteil von klassenbasierten Ansichten?

82

Ich habe heute gelesen, dass Django 1.3 alpha ausgeliefert wird, und die am meisten angepriesene neue Funktion ist die Einführung klassenbasierter Ansichten .
Ich habe die entsprechende Dokumentation gelesen , aber es fällt mir schwer, den großen Vorteil ™ zu erkennen , den ich durch ihre Verwendung erzielen könnte. Deshalb bitte ich hier um Hilfe beim Verständnis.
Nehmen wir ein erweitertes Beispiel aus der Dokumentation.

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

Und jetzt vergleichen wir es mit einer Lösung, die ich in 5 Minuten für diese Frage erstellt habe (ich entschuldige mich für etwaige Fehler).

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))

Die zweite Version sieht für mich so aus:

  • Entspricht der Funktionalität
  • Viel besser lesbar ( self.args[0]? Schrecklich!)
  • Kürzer
  • Nicht weniger DRY-konform

Fehlt mir etwas Großes? Warum sollte ich sie verwenden? Sind die in der Dokumentation? Wenn ja, was wäre dann der ideale Anwendungsfall? Sind Mixins so nützlich?

Vielen Dank im Voraus an alle, die dazu beitragen!

PS für diejenigen, die sich vielleicht fragen, ich war auch nie begeistert von allgemeinen Ansichten: Sobald ich einige erweiterte Funktionen benötigte, wurden sie nicht kürzer als normale Ansichten.

Agos
quelle
4
Ja, ich sehe auch keinen großen Vorteil. Würde gerne eine große Antwort darauf sehen.
M. Ryan
1
Stimme voll und ganz zu. Ich bin besonders angewidert von self.args [0] oder self.kwargs ['slug']. Es ist jetzt auch viel schwieriger, Standardwerte für URL-Parameter wie diesen bereitzustellen: def publisher_books_list (Anfrage, publisher_name = 'Herbert')
Kevin Renskers

Antworten:

48

Sie können eine Klasse in Unterklassen unterteilen und Methoden wie get_context_data für bestimmte Fälle verfeinern und den Rest unverändert lassen. Mit Funktionen geht das nicht.

Beispielsweise müssen Sie möglicherweise eine neue Ansicht erstellen, die alles tut, was eine vorherige tut, aber Sie müssen zusätzliche Variablen in den Kontext aufnehmen. Unterklassifizieren Sie die ursprüngliche Ansicht und überschreiben Sie die Methode get_context_data.

Wenn Sie die zum Rendern der Vorlage erforderlichen Schritte in separate Methoden unterteilen, wird der Code klarer. Je weniger in einer Methode ausgeführt wird, desto einfacher ist das Verständnis. Mit regulären Ansichtsfunktionen wird alles in einer Verarbeitungseinheit gespeichert.

Evan Porter
quelle
2
Ja, ich kann das sehen. Dies erleichtert das Überschreiben und das häufige Einmischen, wenn Sie entscheiden möchten, ob Sie RESTful, eine vollständige Site oder eine mobile Site verwenden möchten. Damit kann diese Entscheidung so lange wie möglich verschoben werden, während die Funktionalität abgeleitet wird. Das Webware-Modul in Pylons hatte dies und es war sehr nützlich. Allerdings sind klassenbasierte Ansichten mit Django seit langem möglich, indem die Methode __call __ () überschrieben wird.
Elf Sternberg
9
Die Antwort zu akzeptieren, da sie einen sehr guten Punkt liefert ... aber immer noch nicht das Bedürfnis verspürt, sie zu verwenden, da ich solche Probleme selten zu lösen habe. Vielen Dank!
Agos
18

Wenn self.args[0]Sie gestört werden, ist die Alternative:

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

Dann könnten Sie self.kwargs['slug']stattdessen verwenden, um es etwas lesbarer zu machen.

Alex
quelle
10

Ihre Beispielfunktion und Klasse sind in Funktionen nicht gleich.

Die klassenbasierte Version bietet eine kostenlose Paginierung und verbietet die Verwendung anderer HTTP-Verben als GET.

Wenn Sie dies zu Ihrer Funktion hinzufügen möchten, wird es viel länger dauern.

Aber es ist in der Tat komplizierter.

e-satis
quelle
2
+1, um auf den Unterschied hinzuweisen, aber ich persönlich denke, dass require_GET und Django-Paginierung trivial zu verwenden, prägnant, explizit usw. sind, und ich bevorzuge sie immer (fast :)) gegenüber cbvs.
Tomasz Zieliński
4

Dies ist das erste Mal, dass ich davon höre - und ich mag es.

Der Vorteil, den ich hier ehrlich sehe, ist, dass dadurch die Ansichten insgesamt besser mit Django übereinstimmen. Models sind Klassen und ich hatte immer das Gefühl, dass Ansichten auch so sein sollten. Ich weiß, dass nicht alles so ist, aber Ansichten und Modelle sind die beiden am häufigsten verwendeten Typen .

Was den technischen Vorteil betrifft? Nun, in Python ist alles eine Klasse ( oder ein Objekt ?) - gibt es also wirklich einen Unterschied? Ist es nicht in erster Linie 99% syntaktischer Zucker?

Frank V.
quelle
Ich würde sagen, dass die Konsistenz eine größere Wiederverwendung von Code ermöglicht. Sie reduzieren im Grunde genommen eine Menge Boilerplate, wenn Ihre Ansichten bestimmten Mustern entsprechen. Beispielsweise lässt sich ein auf einem Modell basierendes Formular mit klassenbasierten Ansichten extrem schnell generieren. Wenn es ein paar zusätzliche Felder braucht, wird es etwas schwieriger. Wenn Sie ein Formular benötigen, das auf drei Modellen plus zwei zusätzlichen Feldern basiert, sparen Sie wahrscheinlich nicht viel Aufwand.
Wobbily_col
1

Eine Möglichkeit, über klassenbasierte Ansichten nachzudenken, besteht darin, dass sie wie ein Django-Administrator mit ausgeschalteten Trainingsrädern sind und daher viel flexibler (aber schwieriger zu verstehen).

Zum Beispiel basiert die Listenanzeige im Administrator eindeutig auf der generischen ListView. In der einfachsten Listenansicht würden Sie nur ein Modell oder einen Abfragesatz definieren.

class MyExampleView(ListView);
    model = ExampleModel 

Sie müssen Ihre eigene Vorlage bereitstellen, diese entspricht jedoch im Wesentlichen der grundlegendsten ModelAdmin-Vorlage. Das Attribut list_display im Modelladministrator gibt an, welche Felder angezeigt werden sollen, während Sie dies in der ListView in der Vorlage tun würden.

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

Mit dem Admin haben Sie einen Parameter

list_per_page = 100

Hiermit wird festgelegt, wie viele Objekte pro Seite vorhanden sind. Listenansicht hat

paginate_by = 100

das erreicht das gleiche. Wenn Sie sich intensiv mit der Anpassung des Administrators befassen, werden Sie ebenfalls viele Überschneidungen feststellen.

Diese Seite hier soll Ihnen eine bessere Vorstellung davon geben, was sie auch tun.

http://ccbv.co.uk/

wackelig_col
quelle