So now we talked about cookies and how the server can set cookies in the browser and how the browser has to give it back. Now we're going to actually do something useful with it, and that is we're going to build sessions. And sessions is a place on the server where we record things like this user, such and so user, has logged in. So let's take a look at this. So inside the server there is some code that we've enabled in Django called session middleware. And what it basically does is it kind of grabs every incoming request right before it comes in to urls.py and it sort of injects itself before urls.py runs. And what it does is it uses the particular cookie value, maybe 3e comes in as a cookie, and then it actually grabs the particular session and associates it with our request, and so by the time you're coming into one of your urls.py, one of your views from urls.py, what you'll find is that cookies have all been set, the session has been set up. It's made a session if necessary, it's looked up an old session if necessary. And so there's a whole bunch of sessions and these sessions are stored in the database, or on files, or other kind of places. And there's pretty much one session object for each distinct browser that's out there. And we look them up by knowing what the cookie value was that we set. And so one of the things that session middleware does is if it doesn't see a cookie coming in, it actually, like, "Oh, well, I'll pick a large random number and then I'll send the cookie back. I will create a new session and I'll send the cookie back, and then I'll be able to look that session up on all of the future requests." So usually we just go ahead and start sessions when we meet a new browser, it's simpler. I mean, you can sort of sometimes delay it to save a little bit of resources. But often for most applications right away you start using sessions, and then later you log the person in. You are going to mark each browser with some unique random number, and then when that cookie's sent back to us, then we can reassociate the session with the incoming request. So Django middleware handles the creation, deletion, the inserting of data, the deleting of data, and the updating of data in the sessions. The session identifier is a large random number that we put in a browser cookie the first time we meet a browser, and then we store using that same number a bit of data on the server, and then later when that cookie comes back in on an upcoming request, we basically look up the session data and then reassociate it with the request before we go through urls.py and into our views. So we have to enable this, and if you used Django admin to create your project, this is already there, you can go ahead and look in your settings.py, and you'll see that it's there. And you'll also notice that by now you've probably done a bunch of makemigrations and migrates and you see it making a session table. So there's all kind of defaults that are set up so that most of your first Django applications are set up to a, support sessions, and b, store sessions in the database, which is a fine way to go for small to medium-sized sites. So like I said, they're going to be stored in the database. You do this migration and you see that it's creating a sessions table for you in your db.sql3 database. So here we go. We have, as I said, out there we've met these browsers, we've made a session object in our database, and we've put a cookie in each one. So there's some kind of a cookie that they're all named the same. So it will name these cookies sessid or something. So we've picked random numbers and we've marked them. And so what happens is that a browser sends a request in and they send their cookie along with it, the Django middleware looks among all the sessions and then connects it up and then it does the request. So there's many browsers, each with a different number, and then there's many sessions, each with a different number, and part of reconnecting is creating it. Now if we look at this from the point of view of one browser and one session object, one session storage area, at some point we come in and it reassociates the session, and we're doing some work, and we're writing some stuff into the session. And then we respond. We go to another request. We can read what we wrote. So we write stuff into the session, we can read it from another one, and then here we can read that same information. And then here we get a POST, we read a bunch of information but we write some more information. And so you can kind of think ultimately just sort of at some level relax about all the detail and realize that this session is a variable that lasts across many request-response cycles. The cookie variable sort of also lasts across many request-response cycles. The GET and the POST data, they vanish. So the GET data for each one, you use it and you consume it, or you store it in the database. But the GET data from one request is not available on the next request. So we have to use things like sessions sometimes to store little bits of information so that in a later request we can get it back. So the request object has this little attribute called request.session, which is basically a dictionary. We can put keys in it, we can delete those keys, we can update those keys, we can call .get and retrieve a key to see if it's there, etc., etc. And so in a sense we just take request.session and treat it as a magical dictionary. Now we have to remember that each browser has its own dictionary, but when we're in a view function, we're only dealing with one browser. And so that session is the one associated with that browser. So it's this persistent data that lasts across all these things. So here's a real tiny view function. And you can see in this view function what we're going to do is request.session. This is where request.session is where you see the session data. It's basically a dictionary. So we can say .get, then we have a key, and we have 0 as the default, num_visits is the key, 0 is the default value, and then we're going to get that and add one to it, and then store that, and this is kind of like how we do counting. If we get it, if it was 4 before, we're going to go to plus 1 and get to 5. If it's not there, we just set it to 0, so we set it to 1. So somehow num_visits is either 1 or one more than what was previously there. And so then what we see is we see the line that actually just stores it back into the session. That's it, it's a dictionary. It's a magic dictionary. It existed before it came in and we're just going to leave it there, and somehow magic things take care of updating all this stuff. So the other thing that we're going to do is we're going to have this go up by one and if it gets over, over 4, then we're going to wipe it out. So this will count 1, 2, 3, 4, 1, 2, 3, 4 Well, yeah, 1, 2, 3, 4, 1, 2, 3, 4. And so this del is just the standard Python syntax to remove an entry from a dictionary. And then we just kind of print out the number of visits in our little string, in our response. And so if we go, we start, we have no cookie, that means that we also then have no session. And then we go into the session code and you see that it has set a session cookie, right? So we see a session cookie called sessionid. It's got an expiration date, which is not a expire when the browser goes away session, and it's got some big long random number. And so that is basically the session ID until we get a new session. And as a side effect of that, we've also stored the value 1 inside the session in the server and printed it out. So we came in, we established a session. We didn't do any of that, right? If we look at our view here, we didn't establish the session, all we did is grab something out of it, and that's because the establishment of the session happens in the middleware that's kind of outside of us. And so the middleware happens before our code starts and after our code is done, and so the session stuff is just taken care of when we do that. So view count is 1, and then what happens is when we just hit refresh, it's going to send the cookie in for that session ID, it's going to load up the session that's gj2233, and then our code is going to add one to that number and store it back into the session, and then it's going to be 2. And if we kept hitting refresh, it would say 3, 4, then it would do a reset and be 1. And so in this code we just kind of say request.session and put stuff in it and read stuff out of it, and the cookie is the thing that looks that up. Now if we wanted to take a look at what's in the session table, it's really just a session and you can see that it gets created by your migrate and your makemigrations. So we can go right into the database, we can ask for the tables, we can see the django_session. And then we can say SELECT star FROM django_session, and so that will show us the data that's there. And so what we're going to see is the key, which is that session key, and then a time. And that's used to expire the session because these sessions don't last forever. The Django middleware kind of cleans these up after a while, otherwise you'd have sessions that just lasted forever and ever and ever. And then the actual data is this big long string. So what this is is this is actually an encoded string, and if you really want to look at it, it's encoded using a technique called Base64. And there's a base64 parsing library. Base64 is a way of taking arbitrary data and encoding it in basically letters and numbers, upper and lower case. It's a little less dense, it kind of expands. It's not like a compression, it's the opposite of compression. It expands the data when it's encoded into Base64, but it also means that then you can store it. You don't have to worry about any special characters because sometimes when you're going like pasting, single quotes and double quotes mess up. Now all that kind of stuff, by saying, "Here's this string, I'm going to encode it in Base64," I basically am guaranteed that there will be no weird characters that will cause some kind of problem farther on down the line. So if we take a look at our thing and we grab the little thing that's the Base64 encoded variable, if you decode this, we're going to base64 decode it, you see that ultimately it's just kind of like a little key-value pair that looks pretty much like a dictionary. It's a serialized version of a dictionary. It's a dictionary that has been put into a serialized form. And it's in also JSON format and so we can actually sort of tear this apart and use the json library to load it up and see what we've got. So that's there. You don't have to worry too much about that, it's just somehow this big, long thing is being read and written and read and written on every request-response cycle that it's certainly read on every request-response cycle, and it's written when you modify the data in the session. So this has been a quick set of lectures. We talked about cookies, a way of marking each browser with a big random number, and then sessions, which are a bit of data that's stored in a database indexed by that large random number. And then each request comes in and we get the cookie back and then we look up the session. The session data, key-value pairs, basically a dictionary, is all stored in there. And so we talked a little bit about how we do request.session in Django to access session capabilities in our Django applications. [MUSIC]