Hidden in plain sight, 8% of Django projects have flaky middleware.
Tags: django, webdev, python, programming
Published: 2021-01-11 09:18:14

Django Doctor audits code and auto fixes Django anti-patterns. We checked 666 Django projects for problems hindering maintainability and found that **8% of the Django websites have incorrectly ordered middleware** [read more](https://django.doctor/advice/C4000).

Incorrect middleware order is can break middleware hence docs for middleware advise _this should come before x_ or _after y._ Some middleware read headers that others set. Some set headers that affect caching. Some perform [actions on the rendered response content](https://docs.djangoproject.com/en/3.1/ref/middleware/#module-django.middleware.gzip) such as gzip. Thus we can see why order is important.

Let's delve into the order the built-in Django middleware should conform to, and why your website might break if you don't adhere to this order. Incorrect ordered middleware can break make these features not work as you intended at times.

### Near the start

[`SecurityMiddleware`](https://docs.djangoproject.com/en/3.1/ref/middleware/#django.middleware.security.SecurityMiddleware) A middleware that hardens security. Security checks should happen as early in the request as possible, so the advice is to have that at the start of the middleware. [See here](https://dev.to/djangodoctor/hacking-django-websites-30f) for our deep dive into this middleware and videos demonstrating the hacks your website is vulnerable to without it.

[`CommonMiddleware`](https://docs.djangoproject.com/en/3.1/ref/middleware/#django.middleware.common.CommonMiddleware) As the name implies, this performs common operations we expect Django to do such as redirecting according to [`APPEND_SLASH`](https://docs.djangoproject.com/en/3.1/ref/settings/#std:setting-APPEND_SLASH) and [`PREPEND_WWW`](https://docs.djangoproject.com/en/3.1/ref/settings/#std:setting-PREPEND_WWW) setting. If Django is redirecting based on the URL, we want that to happen as soon as possible, hence this middlware comes at the start. The middleware also sets content-length, which other middlwares may rely on.

[`LocaleMiddleware`](https://docs.djangoproject.com/en/3.1/ref/middleware/#module-django.middleware.locale) This handles internationalization of content. It customizes content for each user. We would not want any part of our website to miss that language-specific and user-specific customization and have the header in English the footer in Spanish. _no, muévelo cerca del principio_.

### Near the end

There are two built in fallback middlewares that perform some operation if _all else fails_:

[`RedirectFallbackMiddleware`](https://docs.djangoproject.com/en/3.1/ref/contrib/redirects/#django.contrib.redirects.middleware.RedirectFallbackMiddleware) This middleware handles 404s by redirecting somewhere according to redirect records set in Django admin. We would not want this to happen at the start otherwise database records would take precedence over code in urls.py, and also the database lookup would slow down the response that do not need a fallback.

[`FlatpageFallbackMiddleware`](https://docs.djangoproject.com/en/3.1/ref/contrib/flatpages/#django.contrib.flatpages.middleware.FlatpageFallbackMiddleware) Very similar to [`RedirectFallbackMiddleware`](https://docs.djangoproject.com/en/3.1/ref/contrib/redirects/#django.contrib.redirects.middleware.RedirectFallbackMiddleware) but it serves flat pages instead of redirecting the user somewhere.

### Relative to each other

And then the spider web begins:

[`UpdateCacheMiddleware`](https://docs.djangoproject.com/en/3.1/ref/middleware/#django.middleware.cache.UpdateCacheMiddleware) before [`SessionMiddleware`](https://docs.djangoproject.com/en/3.1/topics/http/sessions/)
[`UpdateCacheMiddleware`](https://docs.djangoproject.com/en/3.1/ref/middleware/#django.middleware.cache.UpdateCacheMiddleware) before [`GZipMiddleware`](https://docs.djangoproject.com/en/3.1/ref/middleware/#django.middleware.gzip.GZipMiddleware)
[`UpdateCacheMiddleware`](https://docs.djangoproject.com/en/3.1/ref/middleware/#django.middleware.cache.UpdateCacheMiddleware) before [`LocaleMiddleware`](https://docs.djangoproject.com/en/3.1/ref/middleware/#module-django.middleware.locale)
[`SessionMiddleware`](https://docs.djangoproject.com/en/3.1/topics/http/sessions/) before [`LocaleMiddleware`](https://docs.djangoproject.com/en/3.1/ref/middleware/#module-django.middleware.locale)
[`GZipMiddleware`](https://docs.djangoproject.com/en/3.1/ref/middleware/#django.middleware.gzip.GZipMiddleware) before [`ConditionalGetMiddleware`](https://docs.djangoproject.com/en/3.1/ref/middleware/#django.middleware.http.ConditionalGetMiddleware)
[`SessionMiddleware`](https://docs.djangoproject.com/en/3.1/topics/http/sessions/) before [`AuthenticationMiddleware`](https://docs.djangoproject.com/en/3.1/ref/middleware/#django.contrib.auth.middleware.AuthenticationMiddleware)
[`SessionMiddleware`](https://docs.djangoproject.com/en/3.1/topics/http/sessions/) before [`MessageMiddleware`](https://docs.djangoproject.com/en/3.1/ref/contrib/messages/)
[`CsrfViewMiddleware`](https://docs.djangoproject.com/en/3.1/ref/csrf/) before [`RemoteUserMiddleware`](https://docs.djangoproject.com/en/3.1/ref/middleware/#django.contrib.auth.middleware.RemoteUserMiddleware)
[`FetchFromCacheMiddleware`](https://docs.djangoproject.com/en/3.1/ref/middleware/#django.middleware.cache.FetchFromCacheMiddleware) before [`SessionMiddleware`](https://docs.djangoproject.com/en/3.1/topics/http/sessions/)
[`FetchFromCacheMiddleware`](https://docs.djangoproject.com/en/3.1/ref/middleware/#django.middleware.cache.FetchFromCacheMiddleware) before [`GZipMiddleware`](https://docs.djangoproject.com/en/3.1/ref/middleware/#django.middleware.gzip.GZipMiddleware)
[`FetchFromCacheMiddleware`](https://docs.djangoproject.com/en/3.1/ref/middleware/#django.middleware.cache.FetchFromCacheMiddleware) before [`LocaleMiddleware`](https://docs.djangoproject.com/en/3.1/ref/middleware/#module-django.middleware.locale)

### Does your codebase order middleware correctly?

Nearly 1 in 10 of the devs reading this probably do. It’s easy to miss something during code review. I can check that for you at [django.doctor](https://django.doctor), or can [review your GitHub PRs](https://github.com/marketplace/django-doctor/):

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/d10epulva9d373jgldhu.png)

Or try out [Django refactor challenges](https://django.doctor/challenge).