В чем преимущество представлений на основе классов?

82

Сегодня я прочитал, что выпускается альфа-версия Django 1.3, и самая разрекламированная новая функция - это представление на основе классов .
Я прочитал соответствующую документацию , но мне трудно увидеть большое преимущество ™, которое я мог бы получить, используя их, поэтому я прошу здесь помочь в их понимании.
Возьмем расширенный пример из документации.

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

А теперь давайте сравним его с решением «plain-old-views», которое я сделал для этого вопроса за 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))

Вторая версия мне выглядит:

  • Эквивалентен по функциональности
  • Намного более читабельный ( self.args[0]? Ужасный!)
  • Короче
  • Не менее DRY-совместимый

Мне что-то не хватает? Зачем мне их использовать? Это в документации? Если да, то каков идеальный вариант использования? Так ли полезны миксины ?

Заранее благодарим всех, кто вносит свой вклад!

PS для тех, кто может задаться вопросом, меня никогда не привлекали общие представления: как только мне потребовались некоторые расширенные функции, они стали не короче обычных представлений.

Агос
источник
4
Да, я тоже не вижу большого преимущества. Хотел бы увидеть большой ответ по этому поводу.
M. Ryan
1
Полностью согласен. Мне особенно противны self.args [0] или self.kwargs ['slug']. Теперь также намного сложнее предоставить значения по умолчанию для параметров URL, например: def publisher_books_list (request, publisher_name = 'Herbert')
Кевин Ренскерс,

Ответы:

48

Вы можете создать подкласс класса и уточнить методы, такие как get_context_data, для конкретных случаев, а все остальное оставить как есть. Вы не можете этого сделать с функциями.

Например, вам может потребоваться создать новое представление, которое делает все, что делает предыдущее, но вам нужно включить дополнительную переменную в контекст. Создайте подкласс исходного представления и переопределите метод get_context_data.

Кроме того, разделение шагов, необходимых для рендеринга шаблона на отдельные методы, способствует более ясному коду - чем меньше сделано в методе, тем легче его понять. С обычными функциями просмотра все это помещается в один процессор.

Эван Портер
источник
2
Да, я это вижу. Это обеспечивает простоту переопределения и частое смешивание, когда вы пытаетесь решить, следует ли вам использовать RESTful, иметь полный сайт или мобильный сайт. Таким образом, это решение можно отложить на максимально долгий срок, пока не будет реализована функциональность. Модуль Webware в Pylons имел это, и это было очень полезно. Тем не менее, представления на основе классов уже давно стали возможны в Django путем переопределения метода __call __ ().
Эльф Штернберг,
9
Принимаю ответ, поскольку он дает очень хороший аргумент ... но все еще не чувствую необходимости использовать их, поскольку мне редко приходится решать такие проблемы. Благодаря!
Agos,
18

Если self.args[0]вас беспокоит, альтернатива:

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

Тогда вы могли бы использовать self.kwargs['slug']вместо этого, сделав его более читабельным.

Alex
источник
10

Функция и класс вашего примера не равны по функциям.

Версия на основе классов обеспечивает бесплатную разбивку на страницы и запрещает использование других HTTP-глаголов, кроме GET.

Если вы хотите добавить это в свою функцию, это займет намного больше времени.

Но все действительно сложнее.

e-satis
источник
2
+1 за указание на разницу, но лично я считаю, что require_GET и django-pagination тривиальны в использовании, лаконичны, явны и т. Д., И я предпочитаю их cbvs в (почти :)) всегда.
Tomasz Zieliński
4

Я впервые об этом слышу - и мне это нравится.

Преимущество, которое я здесь вижу, честно говоря, в том, что он делает представления более совместимыми с Django в целом. Модели - это классы, и я всегда считал, что представления должны быть такими же. Я знаю не все, но представления и модели - это два наиболее часто используемых типа .

Что касается технического преимущества? Ну, в Python все является классом ( или объектом ?) - так есть ли разница? Разве это не 99% -ный синтаксический сахар?

Франк V
источник
Я бы сказал, что согласованность позволяет повторно использовать код в большей степени. Они в основном сокращают количество шаблонов, если ваши представления соответствуют определенным шаблонам. например, форма, основанная на модели, очень быстро создается с помощью представлений на основе классов. Если ему нужна пара дополнительных полей, все становится немного сложнее. Если вам нужна форма на основе трех моделей плюс два дополнительных поля, они, вероятно, не сэкономят вам много усилий.
wobbily_col
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/

wobbily_col
источник