¿Cuál es la ventaja de las vistas basadas en clases?

82

Leí hoy que Django 1.3 alpha está disponible, y la nueva característica más promocionada es la introducción de vistas basadas en clases .
He leído la documentación pertinente , pero me resulta difícil ver la gran ventaja ™ que podría obtener al usarlos, por lo que solicito ayuda para comprenderlos.
Tomemos un ejemplo avanzado de la documentación.

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

Y ahora comparémoslo con una solución de "vistas simples y antiguas", hecha por mí mismo en 5 minutos para esta pregunta (me disculpo por cualquier error que pueda encontrar).

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

La segunda versión para mí parece:

  • Equivalente en funcionalidad
  • Mucho más legible ( self.args[0]¡horrible!)
  • Corta
  • No menos compatible con DRY

¿Hay algo grande que me esté perdiendo? ¿Por qué debería usarlos? ¿Están en la documentación? Si es así, ¿cuál sería el caso de uso ideal? ¿Son los mixins tan útiles?

¡Gracias de antemano a todos los que contribuyen!

PD: para aquellos que se lo pregunten, nunca me cautivaron las vistas genéricas: tan pronto como necesité alguna funcionalidad avanzada, no se volvieron más cortas que las vistas normales.

Agos
fuente
4
Sí, tampoco veo la gran ventaja. Me encantaría ver una gran respuesta a esto.
M. Ryan
1
Completamente de acuerdo. Estoy especialmente disgustado con self.args [0] o self.kwargs ['slug']. Ahora también es mucho más difícil proporcionar valores predeterminados para los parámetros de URL, como este: def publisher_books_list (request, publisher_name = 'Herbert')
Kevin Renskers

Respuestas:

48

Puede subclasificar una clase y refinar métodos como get_context_data para casos específicos y dejar el resto como está. No puedes hacer eso con funciones.

Por ejemplo, es posible que deba crear una nueva vista que haga todo lo que hace una anterior, pero debe incluir una variable adicional en el contexto. Subclase la vista original y anule el método get_context_data.

Además, separar los pasos necesarios para representar la plantilla en métodos separados promueve un código más claro: cuanto menos se haga en un método, más fácil de entender. Con las funciones de visualización regulares, todo se vierte en una sola unidad de procesamiento.

Evan Porter
fuente
2
Sí, puedo ver esto. Es un caso fácil de anular y mezclar con frecuencia cuando se trata de decidir si debe usar RESTful, tener un sitio completo o un sitio móvil. Con esto, esa decisión se puede posponer el mayor tiempo posible mientras se deriva la funcionalidad. El módulo de Webware en Pylons tenía esto y era muy útil. Dicho esto, las vistas basadas en clases han sido posibles durante mucho tiempo con Django al anular el método __call __ ().
Elf Sternberg
9
Aceptar la respuesta ya que proporciona un muy buen punto ... pero aún sin sentir la necesidad de usarlos, ya que rara vez tengo este tipo de problemas que resolver. ¡Gracias!
Agos
18

Si te self.args[0]está molestando, la alternativa es:

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

Entonces podría usar self.kwargs['slug']en su lugar, haciéndolo un poco más legible.

Alex
fuente
10

Su función y clase de ejemplo no son iguales en características.

La versión basada en clases proporciona paginación de forma gratuita y prohíbe el uso de otros verbos HTTP que no sean GET.

Si desea agregar esto a su función, será mucho más largo.

Pero es, de hecho, más complicado.

e-satis
fuente
2
+1 para señalar la diferencia, pero personalmente creo que require_GET y django-pagination son triviales de usar, concisos, explícitos, etc. y los prefiero a cbvs en (casi :)) todo el tiempo.
Tomasz Zieliński
4

Esta es la primera vez que escucho sobre esto, y me gusta.

La ventaja que veo aquí, honestamente, es que hace que las vistas sean más consistentes con Django en general. Los modelos son clases y siempre sentí que las vistas también deberían serlo. Sé que no todo lo es, pero las vistas y los modelos son los dos tipos más utilizados .

¿En cuanto a la ventaja técnica? Bueno, en Python todo es una clase (¿ u objeto ?). Entonces, ¿hay realmente una diferencia? ¿No es 99% azúcar sintáctico en primer lugar?

Frank V
fuente
Diría que la consistencia permite una mayor reutilización del código. Básicamente, reducen una gran cantidad de texto estándar, si sus vistas se ajustan a ciertos patrones. por ejemplo, un formulario basado en un modelo es extremadamente rápido de generar con vistas basadas en clases. Si necesita un par de campos adicionales, comienza a ser un poco más complicado. Si necesita un formulario basado en tres modelos más dos campos adicionales, probablemente no le ahorrarán mucho esfuerzo.
wobbily_col
1

Una forma de pensar en las vistas basadas en clases es que son como un administrador de Django con las ruedas de entrenamiento apagadas y, por lo tanto, mucho más flexibles (pero más difíciles de entender).

Por ejemplo, la visualización de la lista en el administrador se basa claramente en el ListView genérico. La vista de lista más simple solo definiría un modelo o conjunto de consultas.

class MyExampleView(ListView);
    model = ExampleModel 

Deberá proporcionar su propia plantilla, pero básicamente será la misma que la ModelAdmin más básica. El atributo list_display en el administrador del modelo le indicará qué campos mostrar, mientras que en ListView lo haría en la plantilla.

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

Con el administrador tienes un parámetro

list_per_page = 100

que define cuántos objetos por página. La vista de lista tiene

paginate_by = 100

que logra lo mismo. Del mismo modo, si busca personalizar mucho el administrador, verá mucha superposición.

Este sitio aquí debería darle una mejor idea de lo que hacen también.

http://ccbv.co.uk/

wobbily_col
fuente