← Back to Show Notes

Transcript: Middleware

Will Vincent

Hello and welcome to another episode of Django Chat, a weekly podcast on the Django Web Framework.

This week we're going to be talking about middleware.

My name is Will Vincent, and I'm joined as always by Carlton Gibson.

Hi, Carlton.

Carlton Gibson

Hello, Will.

Will Vincent

And this talk, uh this chat is based on the talk you just gave at DjangoCon US, which will be up shortly, and we'll link to that in the show notes, uh, all about middleware.

And in many ways, middleware is sort of the secret sauce of Django, but I think it's poorly understood.

So let's maybe dive in and talk about what it is and why it's important to Django.

Carlton Gibson

Yeah, I mean it's it's a source of a lot of the power.

I think when you say understood, misunderstood, I think people are a bit scared of it.

Um because when do we

Will Vincent

Yeah, it does it sounds scary.

Carlton Gibson

Right, and what do we see?

We see we we've got in our settings and we know there's this middleware setting with this list of import paths in it, which are all a bit arcane and mysterious, and and sometimes we have to insert a middleware in there, and it's like, oh make sure it's at the very top, or make sure it's at the very bottom, or make sure it's in there, but just after this one or before that one, and it's like what

Will Vincent

Right, right.

And why does the order matter?

It's definitely very scary, and and it's yeah, it's it's automatically generated with the um start project command.

Um yeah, I mean I would say for years I was definitely in that boat of I see it there, I don't want to touch it, I hold my breath when I have to put in you know white noise or something.

And and yet it is not just some random setting, it is you could argue kind of what Django is in a core load.

Carlton Gibson

Oh like so um request.user.

So let's start with the request.user.

So you access the user, right?

The request, the the Django HTTP request object, that doesn't have a user attribute.

So when you're writing a unit test and you get, you go have ref factory request equals factory get, and you create a request object, and then you go request.us, and it goes, no attribute error.

You haven't got that's because you didn't you you have to manually in the test, you have to manually set a user attribute.

But that's what Django's auth middleware does does for you.

It provides the user stuff.

Will Vincent

Yeah, so let's back up a sec.

Let's let's let's tee up what it is, and then we can get into this uh the the onion.

Yeah.

So so just as a definition, so the middleware is a callable, so that's anything that you can

take a request and a response, just like

Will Vincent

a view.

And so that's something that basically just to like make this super simple in Python, that's anything within parentheses, so you can pass in parameters often a function.

Uh and the, I mean, the technical definition, which I don't think is that helpful actually, is from the docs is a framework of hooks into Django's request response processing, a light low-level plugin system for globally altering Django's inputs.

Carlton Gibson

That's a middleware.

Now, a middleware is a callable that takes a request and it returns a response.

It's exactly the same as a view, except a teeny bit different.

Will Vincent

Right.

So it goes, so if you think of uh what is the process of going to a web page?

Because again, for for beginners or people who haven't thought about this for a while, so you go to a URL that takes you to middleware, wrapped around a view, which connects you with a model and a template, and then you get something back.

So that's request response.

And yeah, middleware is wrapped around the view, so you can access things before it gets to the view or after it comes to the view, which we'll get to.

And I think also maybe talking about WISGI is helpful here, right?

Which in your talk you did a nice job on this.

Do you want to explain why WISGI matters?

Carlton Gibson

Python's uh stand web service gateway interface.

It's like the standard for um app servers to talk to application servers.

So Apache's got Mod WISGI Express, um, Garnicorn everybody uses, or UWISGI are the servers that you put behind something like Nginx.

Um and they they a Whiskey application is a callable that takes a Whiskey environment, which is like information about the request, like you know, the method and the request path and the query string and all these things.

Will Vincent

And then it takes sorry just to interrupt.

I mean it it imports the settings.py file, loads all the middleware, resolves the URL to the view, and then uh returns the request object back.

That's kind of what a WSGI handler does.

Well, no, but yeah, but it's another degree of abstraction on top of it.

Carlton Gibson

Yeah, and it it it takes this this whiskey environment, the the information about the request, and this this thing called start response, which isn't really that interesting.

And then, but it takes this whiskey environment and it processes that and it returns a response.

So any function, any callable, so that can be a class with a call or a function that takes a whiskey environment and returns a response, which is just an iterable containing the response body, really.

Um that's a whiskey application.

So every Django application is a whiskey app, it has a Whiskey handler, which is the the um the Whiskey application.

But Flask, that's also Whiskey, and so are all the other um Python frameworks out there.

Will Vincent

Right.

And again, this is just you know why you need this is because the application, so Django, and then the web server that is serving it are separate things, and Whiskey is a way that uh abstracts any Python-based environment so you don't have to deal with again whether you're using Unicorn or UWSKY.

Carlton Gibson

So yeah, I think when we had Russell Keith McGear and he was talking about the pre-WISG days, I think.

I think it was him anyway.

Will Vincent

Yeah, well, and and it's and we've mentioned that go ahead.

Carlton Gibson

Well, the point is you had to do you had to deploy um your web framework with your particular server.

Right?

Whereas now you can choose any server and mix it with any web framework and it'll all it'll all work.

And that's been the case for a long time now.

Will Vincent

And it comes at the cost though, of unless you have a discrete reason to dive into all this, you just see it there and you don't really need to understand it.

The cool thing about uh Django's history where WISGI uh it came before WISGE is that uh it plugs into WISGI.

So now with ASGI, which we've talked about the new async stuff, Django is uh it's easier for Django to switch to async things than, for example, Flask in its current iterations is WISGI.

Um there's some projects to work on that, but uh it's gonna be a little bit easier for Django, I think, than Flask.

Carlton Gibson

Yeah, it's kind of amazing.

Like when you look in your Django project, there's this Whiskey.py file, and in there there's just this callable that's getting.

Never look at it.

Yeah, never look at it.

Yeah, yeah, yeah.

Don't go in there.

Carlton Gibson

There's nothing in

well, you know,

Carlton Gibson

you might sometimes um you know, you might when have I edited that?

I've edited that when

Will Vincent

For Heroku you have to go in there and change a line and hold your breath.

Carlton Gibson

Um but I you know when I was um if say I was working with um a third-party dependency, so I've done this in a path work working with a first third party dependency that was um broken, like the

the the

Carlton Gibson

release version was broken.

So what I've had to do is import a fork of that into my, you know, next to my project, say on the server.

And then I've just adjusted the Python path in the Whiskey file to make sure that it was all set up right to import the the overridden version of my dependency rather than the broken one from PyPy Pype i.

Will Vincent

Right.

And Python path, that's also scary.

Carlton Gibson

That's always exactly, but unless you're doing something a bit uh don't go in the whiskey, but in there there's just this little getWSGI application function, and all that is is a wrapper which instantiates the the this thing called Whiskey handler.

Um and that it's just two lines, and it's like, well, why is it there?

It's there because just in case we need to swap something out.

And so 10 years later or whatever, along comes ASCII, which is the asynchronous um version of Whiskey.

And it's very easy because there's this kind of um indirection layer to for Andrew to switch that in.

And so you know it that's that that's proven prescient after all this time.

Yeah.

Will Vincent

It's nice.

Yeah, it's it's sort of like technical debt that helps rather than hurts for a change.

Carlton Gibson

Well, it's it's like

Will Vincent

two lines.

Carlton Gibson

Why don't we just inline it?

Will Vincent

Like, you know.

It's nice to see a decision that turns out to be quite helpful rather than harmful, which is often the the focus is on things that are harmful rather than helpful.

Yeah.

Carlton Gibson

Um, inside your WISGI application, right?

You your WISGI application gets a WISGI environment.

It's like a res uh it's like a request, but it's not, it's a Python dictionary with all these weird keys in it that you don't know anything about.

And what Django does, the first thing Django does is convert that into an HTTP request, a Django HTTP request that we know and love that's got you know the the access to the get, access to the post, the meta.

The meta is the original um whisky dictionary.

Um so if you get access request.meta, that's the wit, that's basically what your whiskey application gets.

Django inserts a couple more keys in there, but it's essentially what the Whiskey server gave you in its raw form.

And but what else does the we get headers, we get, you know, we're able to read the remote.

Will Vincent

Yeah, I mean the important thing is we want to get to middleware, but that's what Whiskey is when it's related.

Yeah.

Carlton Gibson

And then that, once we've got that request, we pass it to your to your view, right?

Your view to your standard Django view takes a request in and returns a response.

And all middleware do is they do exactly the same thing, but they sit outside your view.

So they wrap it.

And you can have them wrapped one inside the other or inside the other.

And that's in your settings file, that list from top to bottom is sort of from outside to in as they're wrapping each other.

Will Vincent

Well, yeah, and there is, I think And

Carlton Gibson

that's what they call the middleware.

Will Vincent

Five different yeah, and there's five different types of middleware.

There's request middleware, so that's processing a request before it comes to the URL.

Uh in view section, there's a view middleware where you know the view and the URL parameters.

There's exception middleware where what do you do if there's an exception?

There's a template response middleware.

I know I'm going down the list here, response middleware.

Anyways, there's there's a couple, you know, five built-in types.

The more interesting thing is what Django gives us, which if you peek at the start project, you know, if you s uh peek at the middleware setting, you see, you know, there's a list, uh, you know, security middleware, session middleware.

And the interesting thing is what those are and why the order matters.

Why does the order matter, Carlton?

Why don't you why does order matter?

Right?

Carlton Gibson

So they're called.

You've got to imagine right.

So the the key, the sort of the way to imagine it is that the request comes in and it dives all the way through all of these middleware in order, and then it finally gets to your view.

And then

as the

response gets returned back, it goes all the way back out.

Now any of these going down can interrupt and return a response early, and it never gets to the one below.

So for instance, CSRF, that cross-site request forgery, right, where you didn't have the little token in your post data, so it says it CSRF invalid.

Well, that is actually executed just before your view.

So it uses a hook called process view, which so it's kind of like I'm gonna let all the other middleware do their thing, and then just before the view gets executed, I'm gonna check that the C SR CSRF was was in place.

And if it wasn't, I'm gonna return a response, an error response there and then, and your view never even gets to see the request because it's exited early.

Um, but like for instance, authentication, request.user we were talking about just before, right?

That requires

the session.

Carlton Gibson

Because if the session's not in place, then it it would break.

So session middleware has to be before authentication middleware, otherwise it breaks.

So this is where the ordering comes in.

And in the docs, there's a whole section in the the middleware reference about which middlewares need to go before what or where or after.

Will Vincent

Right.

And this, I mean, the authentication middleware, this adds the built-in user object so that you know that uh who the user is, if someone's logged in, if they're not.

Uh so it makes sense if you think about it enough that you need to throw that on before it hits the actual view, before you you can't search on user if there's no user added in.

Um yeah, so middleware really is the secret sauce of Django.

This is where a lot of Django's power.

I mean, there's the ORM, um, but this is kind of where a lot of the magic happens.

Carlton Gibson

Uh you get all like the security headers that you get set, the allowed host checking, the uh I don't know.

Will Vincent

And again, because it's because before it hits the view, you're checking all these things to make sure is this is this what we want to do?

Does it have the user?

Uh does it have sessions?

I mean, maybe so common middleware is an interesting one.

I you know, the the name sort of uh that's the one actually when I just look at it, I go, I actually I don't know which one that is, because the other ones all kind of say what they are.

Carlton Gibson

Yeah, because like security is obvious, sessions obvious, CSRF is obvious.

What's in the comments?

Yeah.

Will Vincent

And the honest answer is maybe we need to we probably need to go look at the dog.

Let's go and look at the dogs.

Will Vincent

Yeah.

Well, yeah.

So this is, you know, let's just so everyone's listening.

So the the Django fellow and you know, I teach this and we're like

Carlton Gibson

Well, okay, so what's in common middleware, right?

Uh without looking.

Oh to be honest, I can't remember.

We have to look at it.

We can look at it.

Will Vincent

We can edit it to sound better.

Carlton Gibson

No, let's leave it live.

Will Vincent

Um so what are we doing?

We're going to the Django docs where we go all the time.

Um, and it just says that it adds so it adds some.

I like this, it adds a few conveniences for perfectionists.

So Right.

Carlton Gibson

Well, no, I'm looking in the source code, so I'm having a look at what's going on.

Oh, right.

Will Vincent

You had to one up me like that.

Okay.

Carlton Gibson

Well, you know.

So um

Will Vincent

these are the

two places.

So okay, right.

Carlton Gibson

So in in common middleware, we can forbid access to disallowed user agents.

So if you don't like people who use Chrome, you can disallow the user Chrome user agent in.

You wouldn't.

Will Vincent

Right.

You can append slash and prepend yeah

or you can perform rewrites in the URL.

Carlton Gibson

Append slash is so redirect, so rewrite if um the append slash isn't at the end.

Will Vincent

What else?

So it is just a grab bag of other stuff we need, but maybe isn't worthy of its own middleware on its own.

So yeah, right.

Carlton Gibson

And well, this is common.

Well, but also this is where you can start to think, well, you know, do I do I need this?

If you're like for your base project, it's fine.

But like, you know, if you're really trying to squeeze every last ounce, you can start tribbing some of these off.

You may not need common middleware.

You so you could get rid of it.

You might not need security middleware, right?

Well, okay, so is what's that gonna check that you were serving um um HTTPS?

You might not want that check because you might know that you're serving HTTPS.

You might have Nginx configured

to enforce that.

Will Vincent

The tricky thing, you know,

Carlton Gibson

I wouldn't recommend this unless you really know what you're doing, but going through the middleware and starting to strip them out, and then if you need that high throughput API endpoint, you can run that in a separate service, separate service which has a stream trim-down middleware, which is grease lightning, you know.

Will Vincent

Well, and this is uh we've done some interviews with some large Django sites at scale that we're gonna release soon.

I mean, this brings up fighting the framework, you know, because I the danger is you can go and do in this, do these things, but then you need to really be sure you need to do it because this is really the internals of Django.

So maybe there's a tiny performance benefit, but this isn't you know, this is pretty core Django,

which I always get a little

Will Vincent

uneasy to touch because there's updates to Django all the time, and you know, you don't really want to eject from it unless you really, really have to.

In which case, maybe you would do, as you said, set up a separate server

Carlton Gibson

just for the one particular thing.

Yeah, it's just

Will Vincent

add a degree of caution.

Like it's fun to play with it, but don't jump off the rails of Django unless you really, really have to.

Carlton Gibson

Right, but y if you're not using sessions, if you're not using authentication, if you're not using the mess messages middleware.

Yeah.

And you need a speedy endpoint, you can trim those those layers out.

And yeah.

Will Vincent

And that would be an interesting experiment to do, you know, and probably you would find it's faster.

Um but for general.

Right, for general

Carlton Gibson

users, right?

As soon as you want the sessions or users or you know, the the messages frame, what does the messages framework do?

That that enables you to say a um say a user saves a form, right?

Or saves it saves an object.

That enables you to set a message on the ROM request and they get redirected to a fresh page, right?

And then it comes up with a little um message at the top saying, hey, you you successfully created

you know

your new blog post, like it does in the admin if you create a um a record.

You kind of want that.

Carlton Gibson

That's great.

So don't get rid of it.

Will Vincent

Yeah.

Well, Django is eminently customizable, uh, but as I tell people, be sure you know what you're doing.

Um and I do want to get to so this all leads in, so your talk, um your talk was about using Django as a microframework, and I will we'll link to it.

I thought it was great.

Will Vincent

You sort of showed that Django gets a bad rap for being bloated and not being as concise as Flask or Express or some of these things.

But in fact, and you gave an example which we'll link to, I I tossed up a repo yesterday of uh how many lines is that 12-line hello Django file, where using especially the middleware and the whiskey handler, you can actually not use the middleware, using the whiskey handler, you can um treat Django just as lightweight as any of these other things, because of course you would never use Flask just the seven-line version.

That's just a a demo.

Carlton Gibson

Um yeah, no, the like the how the hello world from any of these microframework sites, they all look great.

Um, but Django doesn't do that.

Django has the whole start project, and here's the views file, and here's the templates over here, and it's all a bit like wow, this is big and bulky.

It's not bulky at all.

What and what the point of my talk was to walk everybody through down to the base handler, which is where we get, we you know, we fund them.

Will Vincent

That's really the point.

Carlton Gibson

Yeah, we take in the web requests, we process it in our view, and we send back the the response with like the web problem.

This is what all the frameworks are doing.

And that that core base handler um class is like a hundred and something odd lines, 150 lines long, 160 lines long.

It's not, and you know, and that includes all the exception handling and all the the ability to load the middleware chain and you know, all these all these things that it does that is the core framework, but it's not 160 line.

There's no room for it to be clunky, there's no room for it to be slow, there's no room for it to be, you know, it's it's it's lightweight.

It's the same as any other web framework out there because we're all doing the same thing.

We're all taking requests, returning them to responses.

And that core bit is as fast as anything you want.

Will Vincent

Yeah, and I'm just looking up the um the actual location of that.

Is that the whiskey org?

Or where is the because I want to link in the show notes to the

actual file file.

Carlton Gibson

So if you go into Django Core Handlers base, the base handler um in there, the base handler class in there is well what?

It's a hundred and um twenty lines long.

Okay, yeah, base base.

140 lines long.

Carlton Gibson

It's 140 lines long, right?

Will Vincent

100 base wait.

Django core handlers base.py.

Carlton Gibson

Django core handlers base.py, yeah.

And the the the class isn't it one of the things.

Will Vincent

Oh, the overall file is 166, but the same thing.

Carlton Gibson

Yeah, like like what else have we got going on down there?

We've got yeah, a couple of utility functions um outside of the code.

Will Vincent

So I'm gonna put this in the show notes so folks can take a look and see it's not as scary as it may sound.

Carlton Gibson

Yeah, I mean, and the the idea of the idea of my talk was just to s like break open the box a little bit and point people to these core handlers and say, look, they're not there's not actually that much going on.

Um Right.

Will Vincent

And once you see that, once you see how the handler works, then you see why this Hello Django example is so concise uh and that a lot of the I was gonna say cruft, a lot of the additional things Django gives you is it does give you all this middleware and it pre-builds out uh a structure that makes more sense for a larger site, not just one with a couple routes, which is quite nice because otherwise we'd all be arguing about the proper way to structure our Django apps, which is what happens in um Flask and Express.

And instead we have the opposite issue of when you get really, really big and people say, Oh, Django doesn't do exactly what I want.

It's like, well, that's because once you get to that size, everything is custom anyways, and where do you put the view, you know, the logic?

You know, those are good problems to have.

No one can solve all those for you.

Carlton Gibson

Yeah, right.

Exactly.

Will Vincent

But that was actually at Django Boston, I keep bringing this up.

There was there was a discussion before my my talk before I gave a preview of my DjangoCon talk at Django Boston, and the question was, what do you least like about Django?

And I think the top one was saying it doesn't scale from zero to a hundred all the way, but uh you know nothing could possibly do that.

Um I think it gets you a lot of the way there, and then you know, at scale, applications are different, you know, there's no way to do that.

So I tried not to get too defensive about it.

But uh, you know, it's like, yeah, I'd love if somebody smarter than me figured out all my problems I'm gonna have in advance, but you know, maybe my application has lumpy traffic.

You know, how does that traffic look?

That's gonna change how I structure things, you know.

So it, you know, I think it takes you pretty far up to the point where when you start complaining about you know the view logic in Django, it's like good, now you're you've got good problems.

Carlton Gibson

This is my point about you can customize the middle mass middleware stack.

If you're gonna do it.

Yes, and you can.

Will Vincent

Yeah, if you want to, you can

Carlton Gibson

when you get, when you suddenly find, not suddenly fine, but when you've when you sort of see coming up, you know, over a course of months as your web application grows, you see that you're you're coming up to performance problems.

You know, it's not like something that happens overnight, it's something that you realize, okay, we can scale up another worker, and okay, well, fine, but actually we're gonna have to kind of address this.

And then you start looking into the structure and you're like, well, actually, we could just rip this bit out and we could serve these busy endpoints from a special from you know a different um application instance over here, which is optimized for those endpoints.

You can do all of these kind of things.

No, they're not beginner things, but they are all available, and all you all you've really got to do is dig down and understand how the framework's put together.

Um and the point of the talk was it there's only 160, 200 lines to understand.

It's not that complex.

Will Vincent

Right.

And and that and I think the thing is we've talked with folks about the popularity of Flask, which has many great attributes, but but one of the pressures is that you inevitably want something custom.

And I think if I might put words in your mouth, the point of your talk was you can do that with Django, and this is how you don't have to spin up something else in Express or Flask or whatever.

You can do it just with Django.

Carlton Gibson

Yeah, I mean, uh I would you know there might be some really niche embedded thing where Flask isn't gonna help me.

I'm gonna need Rust or Go, or you know, I'm gonna need something really hyper-performant.

But if I'm if I'm still using Python, there's no reason at all what I would ever stop using Django.

Will Vincent

Right.

And again, I mean, uh, you know, we were talking with David Hennemeyer Hansen.

I mean, I I agree with his comment that it's never really the language's fault that you're fighting, it's always the algorithm.

And then, okay, maybe if you're Google, the language matters or in these tiny cases rewrite something in C or Rust, but you know,

Carlton Gibson

it's these 0.001% case, these one in a million companies.

There's 10 companies that need to do this seriously, you know, they talk about all that's not web scale.

What are you talking about?

Carlton Gibson

There are three companies in the world that are web scale.

Will Vincent

Right, right, right.

Um okay, well, I think that hits the points of what we want to talk about middleware.

So, you know, don't just gloss over it when you see it in the settings.py file.

Take a look at Carlton's talk, take a look at this repo just to see how you can use Django as a microframework.

Uh and it's just really interesting.

I mean, it's I think this is the more you start to understand Django, the more you see that it's not that complicated.

And at the same time, it gives you the power to monkey around with the internals if you want to.

It also helps you appreciate that maybe I just want to kind of let it be unless I really, really, really, really have to.

But I could if I wanted to.

Carlton Gibson

Yeah, like, you know, there might be some apps where you don't want the admin in.

You don't want this, you don't want that.

But, you know, uh there's some, not many.

It depends, right?

That's our tagline.

Yeah, it depends.

Yay!

Welcome to Django Chat.

Yeah, we got it in.

We got it in.

Will Vincent

Um okay.

Well, thank you everyone for listening.

As always, episodes are on DjangoChat.com.

We have an email newsletter if you prefer to get emails when episodes are released, and we're at Chat Django on Twitter.

We'll see you all next time.

Carlton Gibson

All right, bye bye.

Thank you.