Vistas a clase en Django


Django view apunta a una función, lo que puede ser un problema si desea cambiar solo un poco de funcionalidad. Sí, podría tener millones de argumentos de palabras clave y aún más si las declaraciones en la función, pero estaba pensando más en un enfoque orientado a objetos.

Por ejemplo, tengo una página que muestra un usuario. Esta página es muy similar a la página que muestra un grupo, pero todavía no es tan similar a simplemente usar otro modelo de datos. El grupo también tiene miembros, etc...

Uno way sería apuntar puntos de vista a métodos de clase y luego extender esa clase. ¿Alguien ha intentado este enfoque o tiene alguna otra idea?

Author: Community, 2008-08-03

9 answers

He creado y utilizado mis propias clases de vista genérica, definiendo __call__ así que una instancia de la clase es llamable. Me gusta mucho; mientras que las vistas genéricas de Django permiten cierta personalización a través de argumentos de palabras clave, las vistas genéricas OO (si su comportamiento se divide en varios métodos separados) pueden tener una personalización mucho más precisa a través de subclases, lo que me permite repetirme mucho menos. (Me canso de reescribir la misma lógica de vista crear / actualizar cada vez que necesito modificar algo que las vistas genéricas de Django no permiten).

He publicado algún código en djangosnippets.org .

El único inconveniente real que veo es la proliferación de llamadas a métodos internos, que pueden afectar el rendimiento de alguna manera. No creo que esto sea una gran preocupación; es raro que la ejecución de código Python sea su cuello de botella de rendimiento en una aplicación web.

UPDATE : Las propias vistas genéricas de Django ahora están basadas en clases.

ACTUALIZACIÓN: FWIW, He cambiado mi opinión sobre los puntos de vista basados en la clase desde que esta respuesta fue escrita. Después de haberlos utilizado ampliamente en un par de proyectos, siento que tienden a conducir a código que es satisfactoriamente SECO de escribir, pero muy difícil de leer y mantener más tarde, porque la funcionalidad se extiende a través de muchos lugares diferentes, y las subclases son tan dependientes de cada detalle de implementación de las superclases y mixins. Ahora siento que TemplateResponse y view decorators es una mejor respuesta para descomponiendo el código de la vista.

 42
Author: Carl Meyer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-11-15 20:39:59

Necesitaba usar vistas basadas en clases, pero quería poder usar el nombre completo de la clase en mi URLconf sin tener que instanciar siempre la clase view antes de usarla. Lo que me ayudó fue una metaclase sorprendentemente simple:

class CallableViewClass(type):
    def __call__(cls, *args, **kwargs):
        if args and isinstance(args[0], HttpRequest):
            instance = super(CallableViewClass, cls).__call__()
            return instance.__call__(*args, **kwargs)
        else:
            instance = super(CallableViewClass, cls).__call__(*args, **kwargs)
            return instance


class View(object):
    __metaclass__ = CallableViewClass

    def __call__(self, request, *args, **kwargs):
        if hasattr(self, request.method):
            handler = getattr(self, request.method)
            if hasattr(handler, '__call__'):
                return handler(request, *args, **kwargs)
        return HttpResponseBadRequest('Method Not Allowed', status=405)

Ahora puedo crear instancias de clases de vista y usar las instancias como funciones de vista, O simplemente puedo apuntar mi URLconf a mi clase y hacer que la metaclase cree instancias (y llame) a la clase de vista por mí. Esto funciona comprobando el primer argumento a __call__ – si se trata de un HttpRequest, debe ser una petición HTTP real porque sería absurdo attept para instanciar una clase de vista con una instancia HttpRequest.

class MyView(View):
    def __init__(self, arg=None):
        self.arg = arg
    def GET(request):
        return HttpResponse(self.arg or 'no args provided')

@login_required
class MyOtherView(View):
    def POST(request):
        pass

# And all the following work as expected.
urlpatterns = patterns(''
    url(r'^myview1$', 'myapp.views.MyView', name='myview1'),
    url(r'^myview2$', myapp.views.MyView, name='myview2'),
    url(r'^myview3$', myapp.views.MyView('foobar'), name='myview3'),
    url(r'^myotherview$', 'myapp.views.MyOtherView', name='otherview'),
)

(He publicado un fragmento de código para esto en http://djangosnippets.org/snippets/2041/)

 13
Author: Erik Allik,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-05-31 15:54:36

Si simplemente está mostrando datos de modelos, ¿por qué no usar las Vistas genéricas de Django? Están diseñados para permitirle mostrar fácilmente los datos de un modelo sin tener que escribir su propia vista y cosas sobre la asignación de parámetros de URL a las vistas, la obtención de datos, el manejo de casos de borde, la representación de salida, etc.

 10
Author: rossp,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-07-12 19:06:48

Siempre se puede crear una clase,__call__ función y luego apunte el archivo URL a una instancia de la clase. Puedes echar un vistazo a la clase FormWizard para ver cómo se hace esto.

 3
Author: dguaraglia,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-11-15 20:41:16

Me parece que estás tratando de combinar cosas que no deberían combinarse. Si necesita hacer un procesamiento diferente en su vista dependiendo de si se trata de un objeto de Usuario o Grupo que está tratando de mirar, entonces debe usar dos funciones de vista diferentes.

Por otro lado, puede haber expresiones comunes que desee extraer de sus vistas de tipo object_detail... tal vez usted podría utilizar un decorador o simplemente funciones de ayuda?

-Dan

 2
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-08-03 17:40:25

A menos que quiera hacer algo un poco complejo, usar las vistas genéricas es el camino a seguir. Son mucho más potentes de lo que su nombre implica, y si solo está mostrando vistas genéricas de datos de modelo hará el trabajo.

 2
Author: Harley Holcombe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-08-11 22:59:42

Las vistas genéricas suelen ser el camino a seguir, pero en última instancia, eres libre de manejar las URL como quieras. FormWizard hace las cosas de una manera basada en clases, al igual que algunas aplicaciones para API RESTful.

Básicamente, con una URL se le da un montón de variables y el lugar para proporcionar un llamable, lo que se puede llamar que proporcione depende completamente de usted - la forma estándar es proporcionar una función - pero en última instancia Django no pone restricciones a lo que usted hace.

Estoy de acuerdo en que algunos ejemplos más de cómo hacer esto sería bueno, sin embargo, FormWizard es probablemente el lugar para comenzar.

 1
Author: Andrew Ingram,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-23 19:05:51

Si desea compartir funciones comunes entre las páginas, le sugiero que mire las etiquetas personalizadas. Son bastante fáciles de crear, y son muy potentes.

Además, las plantillas pueden extenderse desde otras plantillas. Esto le permite tener una plantilla base para configurar el diseño de la página y compartir esto entre otras plantillas que llenan los espacios en blanco. Puede anidar plantillas a cualquier profundidad; lo que le permite especificar el diseño en grupos separados de páginas relacionadas en una lugar.

 1
Author: Andrew Wilkinson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-07-12 19:05:51

Puede usar las vistas Genéricas de Django. Puede lograr fácilmente la funcionalidad deseada a través de Django generic Views

 1
Author: Varun Chadha,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-10-08 05:53:09