2010-05-26 4 views
29

In Django gibt es eine Einstellungsdatei, die die Middleware definiert, die bei jeder Anfrage ausgeführt werden soll. Diese Middleware-Einstellung ist global. Gibt es eine Möglichkeit, eine Reihe von Middleware pro View festzulegen? Ich möchte, dass bestimmte URLs eine andere Middleware als die globale verwenden.Nicht-globale Middleware in Django

Antwort

32

Sie möchten decorator_from_middleware.

from django.utils.decorators import decorator_from_middleware 

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

Es gilt nicht für URLs, aber es funktioniert per-View, so dass man eine fein abgestimmte Kontrolle über seine Wirkung haben kann.

+8

Ok, auszuschließen, aber was ist, wenn ich Middleware ausschließen wollen, anstatt sie anhängen. Zum Beispiel listet meine Einstellungsdatei Middleware MIDDLEWARE_CLASSES = ('A', 'B', 'C') auf und ich möchte, dass eine Ansicht A und B hat, aber nicht C. Gibt es einen Dekorator, der Middleware entfernt?Dieses benutzerdefinierte Middleware-Zeug wird nur in einer Django-App benötigt, daher möchte ich 'decorator_from_middleware' nicht zu jeder anderen Ansicht in meiner Anwendung hinzufügen. – hekevintran

+2

'@ csrf_exempt', die etwas Ähnliches tut, was Sie fragen, funktioniert, indem Sie ein Flag für die Ansicht setzen, das dann von der entsprechenden CSRF-Middleware überprüft wird. Nicht eine allgemeine Lösung, natürlich, aber nur notieren. – sfridman

1

Verwenden Sie django.core.urlresolvers.resolve() gegen request.path in einem Wrapper für die Middleware, um zu sehen, ob die Ansicht innerhalb der App ist, und die Verarbeitung überspringen, wenn dies der Fall ist.

+0

Also muss ich eine if-Anweisung in meinem Middleware-Code verwenden, um es in bestimmten Apps überspringen zu lassen? – hekevintran

+0

Im Wrapper, nicht die Middleware selbst. –

+0

Was ist ein Beispiel für einen Wrapper für Middleware? – hekevintran

5

Hier ist eine Lösung, die ich vor kurzem das Szenario Ihnen präsentiert in einem Kommentar zu Neds Antwort Adresse verwendet ...

Er geht davon aus, dass:

A) Dies ist ein Brauch Middleware oder eine, die Sie erweitern können/Verpackung mit Ihrer eigenen Middleware-Klasse

B) Ihre Logik bis process_view statt process_request warten kann, weil in process_view Sie die view_func Parameter überprüfen können, nachdem es aufgelöst worden ist. (Oder Sie können den folgenden Code anpassen, um urlresolvers wie von Ignacio angegeben zu verwenden).

# 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. 

Es mag einen Weg geben, dieses Muster weiter zu verallgemeinern, aber das hat mein Ziel ziemlich gut erreicht.

Um Ihre allgemeinere Frage zu beantworten, glaube ich nicht, dass es irgendetwas in den Django-Bibliotheken gibt, um Ihnen mit diesem aktuell zu helfen. Wäre ein gutes Thema für die django-users-Mailingliste, wenn es dort nicht schon angesprochen worden wäre.

5

Ich habe eine echte Lösung für dieses Problem. Warnung; es ist ein bisschen wie ein Hack.

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

Bearbeiten: frühere Version entfernt, die die Ansicht zweimal ausgeführt wurde.

0

Django urlmiddleware ermöglicht die Verwendung von Middleware nur für Ansichten, die bestimmten URLs zugeordnet sind.

+0

Schöne App, aber es fügt immer noch globale Middleware, die die angeforderte URL gegen jede konfigurierte URL spezifische Middleware überprüft: https://github.com/dugal/django-urlmiddleware/blob/master/urlmiddleware/middleware.py#L18 – rednaw

1

Das Beste, was ich finden konnte, ist mit request.path_info.startswith ('...'), um die Middleware zu überspringen, indem Sie einfach die Anfrage zurückgeben. Jetzt könnten Sie Middleware nur erstellen, um sie zu überspringen und dann zu erben. Vielleicht könntest du etwas noch einfacher machen und diese Liste in deinem settings.py speichern und dann alle überspringen. Wenn ich in irgendeiner Weise falsch liege, lass es mich wissen.

1

Sie können die process_view-Methode verwenden, die vor dem Aufruf der View-Funktion aufgerufen wird. In process_view können Sie überprüfen, ob diese Ansicht diese Middleware Interception erfordert.

0

Ich denke, das der einfache Weg ist eine Ansicht von 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"