2010-05-26 24 views
29

En Django hay un archivo de configuración que define el middleware que se ejecutará en cada solicitud. Esta configuración de middleware es global. ¿Hay alguna manera de especificar un conjunto de middleware por vista? Quiero que las URL específicas usen un conjunto de middleware diferente del conjunto global.Middleware no global en Django

Respuesta

32

Quiere decorator_from_middleware.

from django.utils.decorators import decorator_from_middleware 

@decorator_from_middleware(MyMiddleware) 
def view_function(request): 
    #blah blah 

No se aplica a las direcciones URL, pero funciona por visión, por lo que puede tener un control preciso sobre su efecto.

+8

Ok, pero lo que si quiero excluir middleware en lugar de añadirlos. Por ejemplo, mi archivo de configuración muestra el middleware MIDDLEWARE_CLASSES = ('A', 'B', 'C') y quiero que una vista tenga A y B pero no C. ¿Hay un decorador para eliminar el middleware?Este material personalizado de middleware es necesario en una sola aplicación de Django, por lo que no quiero tener que agregar 'decorator_from_middleware' a cada otra vista en mi aplicación. – hekevintran

+2

'@ csrf_exempt', que hace algo similar a lo que está preguntando, funciona estableciendo un indicador en la vista que luego se verifica mediante el correspondiente middleware CSRF. No es una solución general, por supuesto, pero solo se nota. – sfridman

1

Utilice django.core.urlresolvers.resolve() contra request.path en un contenedor para que el middleware intente ver si la vista está dentro de la aplicación, y omita el procesamiento si es así.

+0

Entonces, ¿debo usar una instrucción if en mi código de middleware para forzarlo a saltear ciertas aplicaciones? – hekevintran

+0

En el contenedor, no el middleware en sí. –

+0

¿Qué es un ejemplo de un contenedor para middleware? – hekevintran

5

Aquí hay una solución Recientemente he usado para hacer frente al escenario que se presentan en un comentario a la respuesta de Ned ...

Asume que:

a) Este es un middleware personalizado o uno que se puede extender/envuelva con su propia clase middleware

B) su lógica puede esperar hasta process_view en lugar de process_request, porque en process_view puede inspeccionar el parámetro view_func después de que haya sido resuelto. (O puede ajustar el código a continuación para usar urlresolvers según lo indicado por Ignacio).

# settings.py 
EXCLUDE_FROM_MY_MIDDLEWARE = set('myapp.views.view_to_exclude', 
    'myapp.views.another_view_to_exclude') 

# some_middleware.py 

from django.conf import settings 

def process_view(self, request, view_func, view_args, view_kwargs): 
    # Get the view name as a string 
    view_name = '.'.join((view_func.__module__, view_func.__name__)) 

    # If the view name is in our exclusion list, exit early 
    exclusion_set = getattr(settings, 'EXCLUDE_FROM_MY_MIDDLEWARE', set()) 
    if view_name in exclusion_set: 
     return None 

    # ... middleware as normal ... 
    # 
    # Here you can also set a flag of some sort on the `request` object 
    # if you need to conditionally handle `process_response` as well. 

Puede haber una manera de generalizar este patrón más, pero esto cumplió mi objetivo bastante bien.

Para responder a su pregunta más general, no creo que haya nada en las bibliotecas de Django que lo ayude con esto actualmente. Sería un buen tema para la lista de correo de django-users si aún no se ha abordado allí.

5

Tengo una verdadera solución para este problema. Advertencia; es un poco hackeo

""" Allows short-curcuiting of ALL remaining middleware by attaching the 
@shortcircuitmiddleware decorator as the TOP LEVEL decorator of a view. 

Example settings.py: 

MIDDLEWARE_CLASSES = (
    'django.middleware.common.CommonMiddleware', 
    'django.contrib.sessions.middleware.SessionMiddleware', 
    'django.middleware.csrf.CsrfViewMiddleware', 
    'django.contrib.auth.middleware.AuthenticationMiddleware', 
    'django.contrib.messages.middleware.MessageMiddleware', 

    # THIS MIDDLEWARE 
    'myapp.middleware.shortcircuit.ShortCircuitMiddleware', 

    # SOME OTHER MIDDLE WARE YOU WANT TO SKIP SOMETIMES 
    'myapp.middleware.package.MostOfTheTimeMiddleware', 

    # MORE MIDDLEWARE YOU WANT TO SKIP SOMETIMES HERE 
) 

Example view to exclude from MostOfTheTimeMiddleware (and any subsequent): 

@shortcircuitmiddleware 
def myview(request): 
    ... 

""" 

def shortcircuitmiddleware(f): 
    """ view decorator, the sole purpose to is 'rename' the function 
    '_shortcircuitmiddleware' """ 
    def _shortcircuitmiddleware(*args, **kwargs): 
     return f(*args, **kwargs) 
    return _shortcircuitmiddleware 

class ShortCircuitMiddleware(object): 
    """ Middleware; looks for a view function named '_shortcircuitmiddleware' 
    and short-circuits. Relies on the fact that if you return an HttpResponse 
    from a view, it will short-circuit other middleware, see: 
    https://docs.djangoproject.com/en/dev/topics/http/middleware/#process-request 
    """ 
    def process_view(self, request, view_func, view_args, view_kwargs): 
     if view_func.func_name == "_shortcircuitmiddleware": 
      return view_func(request, *view_args, **view_kwargs) 
     return None 

Editar: eliminó la versión anterior que ejecutaba la vista dos veces.

0

Django urlmiddleware permite aplicar middleware solo a las vistas que se asignan a direcciones URL específicas.

+0

Bonita aplicación, sin embargo, todavía agrega middleware global que comprueba la url solicitada contra cualquier middleware configurado específico de url: https://github.com/d0ugal/django-urlmiddleware/blob/master/urlmiddleware/middleware.py#L18 – rednaw

1

Lo mejor que he podido encontrar es usar if request.path_info.startswith ('...') para omitir el middleware simplemente devolviendo la solicitud. Ahora bien, podría crear middleware solo por el simple hecho de omitirlo y luego heredarlo. Tal vez podría hacer algo aún más simple y guardar esa lista en su settings.py y luego omitir todo eso. Si estoy equivocado de alguna manera, házmelo saber.

1

Puede usar el método process_view, que se llama antes de llamar a la función func. En process_view puede verificar si esta vista requiere esta intercepción de middleware.

0

creo que este es el camino más fácil para excluir una vista desde middleware

from django.core.urlresolvers import resolve 
current_url = resolve(request.path_info).url_name 

if want to exclude url A, 

class your_middleware: 
    def process_request(request): 
     if not current_url == 'A': 
      "here add your code" 
Cuestiones relacionadas