32

The official documentation is a bit messy: 'before' & 'after' are used for ordering MiddleWare in a tuple, but in some places 'before'&'after' refers to request-response phases. Also, 'should be first/last' are mixed and it's not clear which one to use as 'first'.

I do understand the difference.. however it seems to complicated for a newbie in Django.

Can you suggest some correct ordering for builtin MiddleWare classes (assuming we enable all of them) and — most importantly — explain WHY one goes before/after other ones?

here's the list, with the info from docs I managed to find:

  1. UpdateCacheMiddleware
    • Before those that modify 'Vary:' SessionMiddleware, GZipMiddleware, LocaleMiddleware
  2. GZipMiddleware
    • Before any MW that may change or use the response body
    • After UpdateCacheMiddleware: Modifies 'Vary:'
  3. ConditionalGetMiddleware
    • Before CommonMiddleware: uses its 'Etag:' header when USE_ETAGS=True
  4. SessionMiddleware
    • After UpdateCacheMiddleware: Modifies 'Vary:'
    • Before TransactionMiddleware: we don't need transactions here
  5. LocaleMiddleware, One of the topmost, after SessionMiddleware, CacheMiddleware
    • After UpdateCacheMiddleware: Modifies 'Vary:'
    • After SessionMiddleware: uses session data
  6. CommonMiddleware
    • Before any MW that may change the response (it calculates ETags)
    • After GZipMiddleware so it won't calculate an E-Tag on gzipped contents
    • Close to the top: it redirects when APPEND_SLASH or PREPEND_WWW
  7. CsrfViewMiddleware
    • Before any view middleware that assumes that CSRF attacks have been dealt with
  8. AuthenticationMiddleware
    • After SessionMiddleware: uses session storage
  9. MessageMiddleware
    • After SessionMiddleware: can use Session-based storage
  10. XViewMiddleware
  11. TransactionMiddleware
    • After MWs that use DB: SessionMiddleware (configurable to use DB)
    • All *CacheMiddleWare is not affected (as an exception: uses own DB cursor)
  12. FetchFromCacheMiddleware
    • After those those that modify 'Vary:' if uses them to pick a value for cache hash-key
    • After AuthenticationMiddleware so it's possible to use CACHE_MIDDLEWARE_ANONYMOUS_ONLY
  13. FlatpageFallbackMiddleware
    • Bottom: last resort
    • Uses DB, however, is not a problem for TransactionMiddleware (yes?)
  14. RedirectFallbackMiddleware
    • Bottom: last resort
    • Uses DB, however, is not a problem for TransactionMiddleware (yes?)

(I will add suggestions to this list to collect all of them in one place)

Gunnlaugur Briem
  • 2,684
  • 2
  • 23
  • 24
kolypto
  • 31,774
  • 17
  • 105
  • 99
  • 3
    MessageMiddleware needs to be after SessionMiddleWare because the message framework *can* use a session-based backend for storing messages. – Madison Caldwell Jan 08 '11 at 04:30
  • This should be a Community Question as there can be no single person with a single correct answer :) however, I see no checkbox – kolypto Jan 08 '11 at 04:32
  • I agree that the terminology is confusing. Perhaps 'inside' and 'outside' would be more appropriate. Those listed closer to the beginning of settings.MIDDLEWARE_CLASSES are 'outside;' those listed closer to the end are 'inside.' This matches the graphic depiction in the django docs, and also represents the fact that middleware, when executed, can set up an environment **within which** subsequent middleware would operate. – Aryeh Leib Taurog Mar 12 '12 at 21:49
  • 3
    Why this question doesn't have hundreds more stars and upvotes, I'll never know! Thanks! – mkoistinen May 25 '13 at 00:01
  • 2
    Django changed quite a lot in two years time, any pointers to an identical, but more *recent* resource? Thanks, +1ed. – Joseph Victor Zammit Jul 22 '13 at 16:27
  • Maybe [SecurityMiddleware](https://docs.djangoproject.com/en/3.0/ref/middleware/#module-django.middleware.security) on top? – Ivan Ogai Apr 03 '20 at 13:37

2 Answers2

4

The most difficult part is that you have to consider both directions at the same time when setting the order. I would say that's a flaw in the design and I personally would opt for a separate request and response middleware order (so you wouldn't need hacks like FetchFromCacheMiddleware and UpdateCacheMiddleware).

But... alas, it's this way right now.

Either way, the idea of it all is that your request passes through the list of middlewares in top-down order for process_request and process_view. And it passes your response through process_response and process_exception in reverse order.

With UpdateCacheMiddleware this means that any middleware that changes the Vary headers in the HTTP request should come before it. If you change the order here than it would be possible for some user to get a cached page for some other user.

How can you find out if the Vary header is changed by a middleware? You can either hope that there are docs available, or simply look at the source. It's usually quite obvious :)

Wolph
  • 78,177
  • 11
  • 137
  • 148
  • [Django 1.10 splits separates request and response setups using the new `MIDDLEWARE` approach](https://docs.djangoproject.com/en/1.10/releases/1.10/#new-style-middleware) – Ian Clark Mar 29 '17 at 09:49
  • I tried every order in middleware, but as you say user two gets the cached result meant for user one and any new change in the database table is not reflected in the cache, it keeps using the same old unexpired cache. I have posted my problem here, can you help?? pleaseee..i have struggling for quite some time now [https://stackoverflow.com/q/70320750/8315427](https://stackoverflow.com/q/70320750/8315427) – reindeer Dec 12 '21 at 09:52
2

One tip that can save your hair is to put TransactionMiddleware in such place on the list, in which it isn't able to rollback changes commited to the database by other middlewares, which changes should be commited no matter if view raised an exception or not.

Tomasz Zieliński
  • 16,136
  • 7
  • 59
  • 83