Django Chat

Middleware

Episode Summary

Middleware makes Django, well, Django, but is poorly understood. In this episode we discuss how middleware works and why it's so important.

Episode Notes

Episode Transcription

Will Vincent  0:06  

Hello, and welcome to another episode of Django chat, a weekly podcast on the Django web framework. This week, we're gonna be talking about middleware. My name is Will Vincent and I'm joined, as always by Carlton Gibson. Hi, Carlton. Hello, Will. And this talk. This chat is based on the talk you just gave at Django con. Us, which will be up shortly. And we'll link to that in the show notes about middleware. And in many ways middleware is where 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  0:38  

Yeah, I mean, it's, it's a source a lot of the power I think, when you say understood, misunderstood, I think people are a bit scared of it. Because when do we Yeah, it does. It sounds scary. Like what do we see? We see we've got a no 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 We'll make sure it's at the very top, we'll make sure it's at the very bottom, we'll make sure it's in there, but just after this one or before that one, and it's like what? Right, right.

 

Will Vincent  1:07  

And why does the order matter? It's definitely very area. And it's Yeah, it's, it's automatically generated with the start project command. Yeah. 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 Lola. So request dot user. So let's start with a request got user.

 

Carlton Gibson  1:35  

Yeah, you access the user, right, the request 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, refer factory request equals factory get, and you agree, create a request object, and then you go request dot use, and it goes no attribute error. You haven't got this because you didn't. You have this manual in the test, you have to manually set a user attribute, but that's what Django is. Ultimate weight does for you. It provides the user stuff.

 

Will Vincent  2:03  

Yeah. So let's back up a sec. Let's let, let's tee up what it is. And then we can get into this. The, the onion. Yeah. So So just as a definition, so the middleware is a callable. So that's anything that you can request in a response, just like 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 off in a function. And then I mean, the technical definition, which I don't think is that helpful, actually is from the docs is a framework of hooks into changose request response processing, a light low level plugin system for globally altering j s. That's the middleware. Now middleware is a callable that takes a request and it returns a response. It's exactly

 

Carlton Gibson  2:44  

the same as a view except a teeny bit different,

 

Will Vincent  2:47  

right? So it goes so if you think of what is the process of going to a webpage because again, for for beginners, or people 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 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 whiskey is helpful here. Right, which in your talk, okay, so nice job Linus. Do you want to explain why we're always

 

Carlton Gibson  3:22  

matters pythons standard web service gateway interface. It's like the standard for web servers to talk to application server. So Apache has got mod whiskey Express ganache on everybody uses or you whiskey or the service that you put behind something like nginx. And they a whiskey application is a callable that takes a whiskey environment which has like information about the request, like you know, the method and the request path and the query string and all these things.

 

Will Vincent  3:53  

And it right i think what it takes so just interrupt I mean, it imports the settings.py file loads all the middleware resolves the URL to the view, and then returns the request object back. That's kind of what a whiskey handler does. Well, the beauty of it. So it's another degree of abstraction on top of

 

Carlton Gibson  4:10  

Yeah, it takes this, this whiskey environment, the information about the request, and this, this thing called start response, which isn't really that interesting. And then it takes us whiskey environment. And it processes that and it returns response to 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. That's a whiskey application. So every Django application is a whiskey, it has a whiskey handler, which is the the whiskey application but flask that's also whiskey. And so all the other Python frameworks out there,

 

Will Vincent  4:49  

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 abstracts any Python based environment so you don't have to deal with, again, whether using unicorn or you whiskey. So

 

Carlton Gibson  5:06  

yeah, I think when we had Russell Keith McGee and he was talking about the pre whiskey days, I think I think it was his many. Yeah.

 

Will Vincent  5:11  

Well, and and we had a

 

Carlton Gibson  5:14  

good. Well, the point is you had to be you had to deploy your web framework, your particular server, right was now you can choose any server and mix it with any web framework, and it will all it will work. And that's been the case, right.

 

Will Vincent  5:29  

And it comes at the cost 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 Django is history where whiskey, it came before whiskey is that it plugs into whiskey. So now with ASCII, which we've talked about the new async stuff, Django is it's easier for Django to switch to async things than for example, flask and its current iterations is whiskey. There's some projects to work on that but it's going to be a little bit easier for Django. I think then,

 

Carlton Gibson  6:01  

yeah, it's kind of amazing. Like when you look in your Django project, there's this whiskey.py file in there, there's just this callable, let's get never

 

Will Vincent  6:06  

looked at it. Yeah, never look at

 

Carlton Gibson  6:08  

it don't go in it, there's nothing it well, you know, you might sometimes,

 

you know, you might, when have I edited that I've edited that when for Heroku, you have to

 

Will Vincent  6:16  

go in there and change a line and hold your breath.

 

Carlton Gibson  6:19  

But I, you know, when I was, um, if, say I was working with a third party dependency, so I've done this in the past, we're working with a third party dependency that was broken, like the 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 pipe

 

Will Vincent  6:49  

pipe. Yeah, right. And Python path. That's awesome.

 

Carlton Gibson  6:52  

Yeah, that's exactly unless you're doing something a bit. Don't go in the wizard. But in there, there's just this little get whiskey application function. And all it is is a wrapper which instantiates the this thing called whiskey handler. And that it's just two lines. And it's like, well, why is it that it's there because just in case we need to swap something out, and so 10 years later, or whatever along comes it, which is the asynchronous version of whiskey. And it's very easy, because there's this kind of indirection layer to it for Andrew to switch that in. And so it that's, that's proven prescient after all this time.

 

Will Vincent  7:30  

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

 

Carlton Gibson  7:34  

Well, it's it's not even.

 

Will Vincent  7:38  

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

 

Carlton Gibson  7:49  

And then so anyone's, yeah, inside your whiskey application, right? Your whiskey application gets a whiskey environment. It's like a, it's like a request, but it's not. It's a part of One dictionary with all these weird keys in it 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 access to the get access to the post the meta, the meta is the original whiskey dictionary. So we get access requests on metal, that's the width. 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 we get headers we get, you know, we're able to

 

Will Vincent  8:34  

Yeah, things we want to get to middleware, but that's what was given. It's related.

 

Carlton Gibson  8:38  

Yeah. And then that once we've got that request, we pass it to you to view right you 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 inside the other and that's in your settings bar, that list from top to bottom is sort of from outside. slides in as they're wrapping each other.

 

Will Vincent  9:03  

Well, yeah, and there is I think that's cool the middle different. Yeah. And there's five different types of middleware, there's request middleware. So it's processing a request before it comes to the URL. In view section, there's a view middleware, where you know, the view in the URL parameters. There's exception middleware, Where, where, what do you do if there's an exception? There's a template response middleware. I know going down the list here, response middleware. Anyway, 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 prod, if you peek at the middleware setting, you see, you know, there's a list, security middleware session middleware. And the interesting thing is, what those are and why the order matters. Yes.

 

Carlton Gibson  9:48  

Why does order matter Carlton? Why, why does ultimate right so they're called, you've got to write so that the keep this all the way to imagine it is that the red quest comes in and it dives all the way through all Have 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 coming 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 says RF 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 going to let all the other middleware do their thing. And then just before the view gets executed, I'm going to check that the CSL CSRF was was in place. And if it wasn't, I'm going to return a response, an error response there. And then and your view never even gets to see the request because it's re

 

Will Vincent  10:47  

exited early.

 

Carlton Gibson  10:49  

But like for instance, authentication request dot user we were talking about just before, right? That requires the session, because if the sessions not in place, then it would break so session middle 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 middleware reference about which middlewares need to go before what we're after.

 

Will Vincent  11:13  

Right? And this I mean, the authentication middleware, this adds the built in user objects so that you know that who the user is if someone's logged in if they're not. So it makes sense. If you think about it enough that you need to throw that on before it hits the actual view before, so you can't search on user if there's no user added in. So yeah, so middleware really is the secret sauce of Django. This is where a lot of Django is power. I mean, there's the ORM. But this is kind of where a lot of the magic happens. We get like the security headers that you get set,

 

Carlton Gibson  11:46  

the allowed host checking the admin,

 

Will Vincent  11:49  

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 it to do? Does it have the user does obsessions, I mean, maybe it's so common middle Whereas an interesting one I you know that the name sort of that's the one actually when I just looked at 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  12:11  

Yeah cuz like security's obvious sessions obvious CSRF is okay. What's your nickname options?

 

Will Vincent  12:15  

Yeah. Well, what isn't the honest answer is maybe we need to we probably need to go to the dogs. Yeah. Well, yeah, so this is Yeah, let's just so everyone's listening so that the Django fellow and I teach this and we're like,

 

Carlton Gibson  12:29  

Well, okay, so what's in common middleware? Right? Without looking? Oh, to be honest, I can't man we can we can.

 

Will Vincent  12:35  

We can. We can edit the sound better?

 

Carlton Gibson  12:38  

No, let's leave it live like you want.

 

Will Vincent  12:44  

So what are we doing? We're going to the Django Doc's where we go all the time. Okay, and it just says that it adds so add some, I like this. It adds a few conveniences for perfectionist. So now I'm looking in the source code, so I don't know what's going on. Call me either one up me like that. Okay, well, you know. So those are the two places. Okay.

 

Carlton Gibson  13:08  

Right. So in in the common middle where we can forbid access to disallowed user agents. So if you don't like people who use Chrome, you can disallow the use of Chrome user agent.

 

Will Vincent  13:18  

You wouldn't, right? You can append slash and prepend. Yeah. Or you can

 

Carlton Gibson  13:23  

append slashes. So it's a redirect. So rewrite if the append slashes isn't at the end.

 

Will Vincent  13:29  

Well, so there's just a grab bag of other stuff we need but maybe isn't worthy of its own middleware on its own. So

 

Carlton Gibson  13:35  

yeah, right. And well, this whole sermon, but also this is where you can start to sink Well, you know, do I do I need if you look for your base project, it's fine. But like, you know, if you're really trying to squeeze every last ounce, you can start trimming some of these off. You may not need common middleware. You say you could get rid of it. You might not need security. Right. Okay. So is what's that going to check that you were serving? HTTPS, you might not want that checked, because you might know that you're serving HTTPS, you might have nginx.

 

Or the full stack.

 

Will Vincent  14:09  

The tricky thing is,

 

Carlton Gibson  14:10  

I wouldn't assume anything 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 string, trim down middleware, which is really like, you know,

 

Will Vincent  14:26  

well, and this is, we've done some interviews with some large Django sites at scale that we're going to release soon. I mean, this brings up fighting the framework, you know, because I, the danger is you can go and do 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. This is pretty core, Django, which I always get a little 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 do as you said, set up a separate Sir,

 

Carlton Gibson  15:01  

right thing.

 

Will Vincent  15:02  

Yeah. Added 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  15:09  

Right. But if you're not using sessions, if you're not using authentication, if you're not using the message messages middleware, yeah. And you need a speedy endpoint, you can trim those those layers out. And yeah, at that point, you know, I mean, that's

 

Will Vincent  15:23  

an interesting experiment to do, you know, and probably you would find it's faster. Yeah, but for general, ai for general use

 

Carlton Gibson  15:32  

is when you have stuff, right, as soon as you want the sessions or users or you know, the message bank, what's the message framework do that enables you to say, say user saves a form, right, or saves, it saves an object that enables you to set a message on the wrong request, they get redirected to a fresh page, right? And then it comes up with a little message at the top saying, hey, you successfully created you know, your new blog post. Like it doesn't mean if you create a record, you kind of want That's great. So don't get rid of it.

 

Will Vincent  16:01  

Yeah. Well, Django is eminently customizable. But as I tell people be sure you know what you're doing. And I do want to get to so this all leads in. So your talk. Your talk was about using Django as a micro framework. And I will, we'll link to it, I thought it was great. You sort of show 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 tossed up a repo yesterday, of a, how many lines is that 12 line, hello Django file. Were using, especially the middleware and the whiskey handler, you can actually not using the middle using the whiskey handler, you can 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 demo. Ya know, like,

 

Carlton Gibson  16:53  

the Hello World from any of these micro framework sites. They all look great. And but Django doesn't do that. Django has an all star project and here's the views by 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 and

 

Will Vincent  17:11  

that's really the point,

 

Carlton Gibson  17:13  

we take in the web requests, we process it in our view, and we send back the response with like, the web portal is what all the frameworks are doing. And that that core base handler, class is like 100, and something odd lines 150 lines long, hundred 60 lines long. It's not a you know, 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 169. 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 lightweight. It's the same as any other web framework out there. Because we're all doing the same thing rules, taking requests, return them two responses, and that Corbett is as fast as anything you want.

 

Will Vincent  17:55  

Yeah, and I'm just looking up the actual location. Have that is that the whiskey org? Or where is that? So I want to link in the show notes to the

 

Carlton Gibson  18:05  

to the actual file. So if you go into Django core handlers bass, the bass handler, in the bass handler class in there is a what? It's 120 lines.

 

Will Vincent  18:19  

Okay. Yeah. Base based on

 

Carlton Gibson  18:22  

240 lines long by

 

Will Vincent  18:24  

100. Based on weight Django core handlers. base.pi Django cool

 

Carlton Gibson  18:29  

handlers. base.pi. Yeah, and the the class isn't

 

Will Vincent  18:35  

the overall files 166. But

 

Carlton Gibson  18:37  

yeah, like, like, what else? If we got going on down? We've got, yeah, a couple of utility functions.

 

Will Vincent  18:42  

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  18:48  

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

 

Will Vincent  18:59  

Right? Once you see that, once you see how the handler works, then you see why this Hello Django example, is so concise. And that a lot of the housing say craft, a lot of the additional things Django gives you is it does give you all this middleware. And it pre builds out a structure that makes more sense for a larger site, not just one with a couple of 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 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? Yeah, the logic, you know, those are good problems to have no one can solve all those for you.

 

Carlton Gibson  19:43  

Yeah, right. Exactly.

 

Will Vincent  19:44  

That was actually Django. Boston. I keep bringing this up. There was there was a discussion before my, my talk before I gave a preview of my Django con talk at Tango 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. 100 all the way but, you know, nothing could possibly do that. 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 try not to get too defensive about it. But yeah, 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, 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  20:38  

And this is my point about you can customize the Midwest, Midwest stack, if you can slide to UK, 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, fine. But actually, we're going to 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 application instance over here, which is optimized for those endpoints. You can do all of these kinds of things, like they're not beginner things, but they are all available. And all you really got to do is dig down and understand how the frame was put together. And the point of the talk was only 160 200 lines to understand it's not that complex.

 

Will Vincent  21:34  

Right. And, 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 and express her flask, whatever. You can do it just with Django.

 

Carlton Gibson  21:56  

Yeah, I mean, yeah, I mean, I would you know, that might be some really niche embedded thing where flask isn't going to help me I'm going to need rust or go on it, you know, I'm going to need something really high performance. But if I'm if I'm still using Python, there's no reason at all I would ever stop using jack.

 

Will Vincent  22:15  

Right And again, I mean, you know, we were talking with David Hannah Meyer Hanson. I mean, I agree with his comment that it's never really the languages fault that you're fighting. It's always the algorithm. And then Okay, maybe if you're Google, the language matters. All right, in these tiny cases, rewrite something in C or rust, but you know,

 

Carlton Gibson  22:33  

yes, these naught point naught naught 1%. Okay, so yeah, in a million companies, there's 10 companies that need to do this series, you know, where they talk about all that's not web scape. What are you talking about? There are three companies in the world that a website.

 

Will Vincent  22:46  

Right, right, right. Okay, well, I think that hits the point 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 is on my Micro framework. 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 have to, but I could if I wanted to.

 

Carlton Gibson  23:22  

Yeah, like, you know, there might be some apps where you don't want the money. You don't want this. You don't want that. But you know,

 

there's some

 

Will Vincent  23:32  

It depends, right? That's our time. Yeah, it depends. Yay. Yeah, we got it. We got it. Good. Okay, well, thank you everyone for listening. As always, episodes are on Jango chat Comm. We have an email newsletter if you prefer to get emails when episodes are released. And we're at chango on Twitter. We'll see you all next time. Bye bye. Thank you.