Jaka jest zaleta widoków opartych na klasach?

82

Czytałem dzisiaj, że Django 1.3 alpha jest w sprzedaży, a najbardziej reklamowaną nową funkcją jest wprowadzenie widoków klasowych .
Przeczytałem odpowiednią dokumentację , ale trudno mi dostrzec wielką zaletę, jaką mogę uzyskać dzięki ich stosowaniu, dlatego proszę o pomoc w ich zrozumieniu.
Weźmy zaawansowany przykład z dokumentacji.

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

A teraz porównajmy to z rozwiązaniem „zwykłych starych poglądów”, wykonanym przeze mnie w ciągu 5 minut na to pytanie (przepraszam za każdy błąd, który można w nim znaleźć).

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

Druga wersja dla mnie wygląda:

  • Odpowiednik funkcjonalności
  • O wiele bardziej czytelny ( self.args[0]? Okropny!)
  • Krótszy
  • Nie mniej zgodny z DRY

Czy brakuje mi czegoś dużego? Dlaczego powinienem ich używać? Czy to jest dokumentacja? Jeśli tak, to jaki byłby idealny przypadek użycia? Czy miksy są przydatne?

Z góry dziękuję każdemu, kto wnosi wkład!

PS dla tych, którzy mogą się zastanawiać, nigdy nie fascynowały mnie również widoki ogólne: gdy tylko potrzebowałem jakiejś zaawansowanej funkcjonalności, stały się nie krótsze niż zwykłe widoki.

Agos
źródło
4
Tak, ja też nie widzę dużej przewagi. Chciałbym zobaczyć dużą odpowiedź na ten temat.
M. Ryan
1
Całkowicie się zgadzam. Szczególnie zniesmaczają mnie self.args [0] lub self.kwargs ['slug']. Dużo trudniej jest teraz podać domyślne wartości parametrów
adresu

Odpowiedzi:

48

Możesz podklasować klasę i udoskonalać metody, takie jak get_context_data, dla określonych przypadków, a resztę pozostawić bez zmian. Nie możesz tego zrobić za pomocą funkcji.

Na przykład może być konieczne utworzenie nowego widoku, który robi wszystko, co robi poprzedni, ale trzeba uwzględnić dodatkową zmienną w kontekście. Podklasuj oryginalny widok i nadpisz metodę get_context_data.

Ponadto rozdzielenie kroków potrzebnych do wyrenderowania szablonu na oddzielne metody sprzyja jaśniejszemu kodowi - im mniej wykonanych w metodzie, tym łatwiej jest ją zrozumieć. Dzięki zwykłym funkcjom widoku wszystko jest zrzucane do jednej jednostki przetwarzania.

Evan Porter
źródło
2
Tak, widzę to. Ułatwia to zastąpienie i częste mieszanie w przypadku, gdy próbujesz zdecydować, czy powinieneś przejść na REST, mieć pełną witrynę czy witrynę mobilną. Dzięki temu tę decyzję można odłożyć tak długo, jak to możliwe, podczas wyprowadzania funkcjonalności. Moduł Webware w Pylons miał to i był bardzo przydatny. To powiedziawszy, widoki oparte na klasach były od dawna możliwe dzięki Django poprzez nadpisanie metody __call __ ().
Elf Sternberg
9
Przyjęcie odpowiedzi, bo to bardzo dobry punkt widzenia ... ale nadal nie czuję potrzeby ich użycia, ponieważ rzadko mam takie problemy do rozwiązania. Dzięki!
Agos
18

Jeśli self.args[0]Ci przeszkadza, alternatywą jest:

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

Następnie możesz użyć self.kwargs['slug']zamiast tego, dzięki czemu będzie nieco bardziej czytelny.

Alex
źródło
10

Twoja przykładowa funkcja i klasa nie są równe pod względem funkcji.

Wersja oparta na klasach zapewnia paginację za darmo i zabrania używania innych czasowników HTTP niż GET.

Jeśli chcesz dodać to do swojej funkcji, będzie to znacznie dłuższe.

Ale jest to rzeczywiście bardziej skomplikowane.

e-satis
źródło
2
+1 za wskazanie różnicy, ale osobiście uważam, że require_GET i django-pagination są trywialne w użyciu, zwięzłe, wyraźne itp. I wolę je od cbvs (prawie :)) przez cały czas.
Tomasz Zieliński
4

To jest pierwsza, o której słyszę - i mi się to podoba.

Zaletą, którą tutaj widzę, szczerze, jest to, że ogólnie rzecz biorąc, poglądy są bardziej spójne z Django. Modele to klasy i zawsze uważałem, że poglądy też powinny. Wiem, że nie wszystko jest, ale widoki i modele to dwa często używane typy .

A jeśli chodzi o przewagę techniczną? Cóż, w Pythonie wszystko jest klasą ( lub obiektem ?) - czy naprawdę jest różnica? Czy nie jest to przede wszystkim 99% cukier syntaktyczny?

Frank V
źródło
Powiedziałbym, że spójność pozwala na większe ponowne wykorzystanie kodu. Zasadniczo ograniczają się do wielu schematów, jeśli twoje poglądy są zgodne z określonymi wzorcami. np. formularz oparty na modelu aa jest niezwykle szybki do wygenerowania z widokami opartymi na klasach. Jeśli potrzebuje kilku dodatkowych pól, zaczyna być nieco trudniejsze. Jeśli potrzebujesz formularza opartego na trzech modelach i dwóch dodatkowych polach, prawdopodobnie nie zaoszczędzą ci one wiele wysiłku.
wobbily_col
1

Jednym ze sposobów myślenia o widokach opartych na klasach jest to, że są one jak administrator Django z wyłączonym szkoleniem, a zatem o wiele bardziej elastyczne (ale trudniejsze do zrozumienia).

Na przykład wyświetlanie listy w panelu administracyjnym jest wyraźnie oparte na ogólnym ListView. W najprostszym widoku listy zdefiniowałbyś tylko model lub zestaw zapytań.

class MyExampleView(ListView);
    model = ExampleModel 

Będziesz musiał dostarczyć swój własny szablon, ale będzie on zasadniczo taki sam, jak najbardziej podstawowy ModelAdmin. Atrybut list_display w administratorze modelu powie mu, które pola mają być wyświetlane, podczas gdy w ListView zrobiłbyś to w szablonie.

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

Z administratorem masz parametr

list_per_page = 100

który określa, ile obiektów na stronę. Widok listy ma

paginate_by = 100

co daje to samo. Podobnie, jeśli przyjrzysz się dostosowaniu administratora, zobaczysz wiele nakładek.

Ta strona powinna dać ci lepsze wyobrażenie o tym, co robią.

http://ccbv.co.uk/

wobbily_col
źródło