2008-08-03 6 views
45

Django puntos de vista 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 hay enunciados en la función, pero estaba pensando más en un enfoque orientado a objetos.Vistas de clase en Django

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 aún no es tan similar a simplemente usar otro modelo de datos. El grupo también tiene miembros, etc ...

Una forma sería apuntar vistas a los métodos de clase y luego extender esa clase. ¿Alguien ha probado este enfoque o tiene alguna otra idea?

Respuesta

41

He creado y usado mis propias clases de vista genéricas, que definen __call__ por lo que se puede invocar una instancia de la clase. 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 fina mediante subclases, lo que me permite repetir mucho menos. (Me cansé de volver a escribir la misma lógica de creación/actualización de vista en cualquier momento que necesite modificar algo que las vistas genéricas de Django no permiten).

He publicado un código en djangosnippets.org.

La única desventaja real que veo es la proliferación de llamadas a métodos internos, que pueden afectar un poco el rendimiento. No creo que esto sea una gran preocupación; es raro que la ejecución del código Python sea su cuello de botella de rendimiento en una aplicación web.

ACTUALIZACIÓN: de Django propia generic views son ahora basado en clases.

ACTUALIZACIÓN: FWIW, he cambiado mi opinión sobre las vistas basadas en clases desde que se escribió esta respuesta. Después de haberlos utilizado extensamente en un par de proyectos, creo que tienden a generar un código que es satisfactorio DRY para escribir, pero muy difícil de leer y mantener más tarde, porque la funcionalidad se distribuye en tantos lugares diferentes, y las subclases son muy dependientes. en cada detalle de implementación de las superclases y mixinas. Ahora siento que TemplateResponse y ver decoradores es una mejor respuesta para descomponer el código de vista.

+0

La ejecución de Python no es EL cuello de botella, pero podría afectar la escalabilidad del sitio y, en general, el rendimiento. ¡Estoy tan contento de que exista Memcache! – StefanNch

2

Me parece que está intentando 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 observar, entonces debe usar dos funciones de vista diferentes.

Por otro lado, puede haber expresiones comunes que te gustaría para extraer provecho de sus puntos de vista _ objeto de tipo detalle ... tal vez usted podría utilizar un decorador o sólo funciones de ayuda?

-Dan

9

Si sólo va a mostrar los datos de los modelos, por qué no usar el Django Generic Views? Están diseñados para que pueda fáciles muestran los datos de un modelo sin tener que escribir su propio punto de vista y la materia sobre la cartografía Paramaters URL a vistas, ir a buscar los datos, el manejo de casos extremos, la salida de representación, etc.

2

A menos que usted quiere hacer algo un poco complejo, usar las vistas genéricas es el camino a seguir. Son mucho más poderosos de lo que su nombre lo indica, y si solo muestra los datos del modelo, las vistas genéricas harán el trabajo.

1

Si desea compartir una funcionalidad común entre páginas, le sugiero que busque etiquetas personalizadas. Son bastante easy to create, y son muy potentes.

También, templates can extend from other templates. Esto le permite tener una plantilla base para configurar el diseño de la página y compartirla entre otras plantillas que completan los espacios en blanco. Puede anidar plantillas a cualquier profundidad; permitiéndole especificar el diseño en grupos separados de páginas relacionadas en un solo lugar.

+0

No creo que poner demasiada lógica en la plantilla sea una buena idea. –

3

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

+0

El procesador de marcado comió su \ _ \ _ 's. Use \\ _ para ocultar el marcado. El método de clase \ _ \ _ call \ _ \ _ es lo que se llama. El problema es asegurarse de que urls.py tenga una instancia de la clase disponible. Hace que tu urls.py sea algo más complicado. –

1

Generalmente, las vistas genéricas serán el camino a seguir, pero en última instancia, usted es libre de manejar las URL como desee. FormWizard hace cosas en una forma 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 lugar para proporcionar una exigible, lo invocable que proporciona es totalmente suya - la forma estándar es proporcionar una función - pero en última instancia Django pone ninguna restricción en lo que hacer.

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

13

que necesitaba usar puntos de vista basados ​​en la clase, pero quería ser capaz de utilizar el nombre completo de la clase en mi URLconf sin tener siempre que una instancia de la clase de vista antes de usarlo. 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) 

puedo ahora ambos instanciar clases de vista y el uso de los casos como funciones de vista, o simplemente puedo señalar mi URLconf a mi clase y tienen la instantiate metaclase (y llamada) la clase de vista para mí. Esto funciona verificando el primer argumento en __call__ - si es un HttpRequest, debe ser una solicitud HTTP real, ya que no tendría sentido recurrir a una instancia de una clase de vista con una instancia de 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 este a http://djangosnippets.org/snippets/2041/)

+1

literalmente increíble – Anentropic

1

Puede utilizar las Vistas Django genéricos. Puede lograr fácilmente la funcionalidad deseada a través de las vistas genéricas de Django

Cuestiones relacionadas