Python for Entrepreneurs Transcripts
Chapter: Web design foundations
Lecture: Cache busting: the solution

Login or purchase this course to watch this video and the rest of the course contents.
0:00 First of all, if we switch this to run in dev mode, we'll have less of a problem, the caching will be less aggressive and things like that,
0:08 but again, the real problem is what do you do for your users, so like I said, let's fix this for everybody.
0:14 The problem is, let's just do a "view source" really quick here, the problem is the system sees this, when we load this,
0:21 the caching is turned on and so it says: "Look, we are going to tell the browser to hold onto this
0:27 and don't come and get it again for the next however long."
0:30 I think the default will be just an hour, but I don't recall if I have changed that in the site. Nonetheless, we want this to change when we change it,
0:38 so the easiest way to make this change is if we had a different URL, so over here, we can see our CSS with our color we put back,
0:46 the easiest way to sort of trick the browser is you come over here and you can put some query string on the end
0:53 and you say "?whatever", it doesn't affect the web server at all, so we can say things like "cacheId=42"
0:59 and it will reload that because hey it's never seen "site.css?cacheId=42", it's only seen site.css, so if we can somehow make this thing go on the end
1:11 and make this number change if and only if the contents of this file changes,
1:15 well, then we can create a way that we'll always have a new URL for new files but then if it's tied to the contents,
1:23 like the same contents always generate the same number there, it won't generate different numbers for the same content,
1:28 which means they won't keep redownloading it. So once it gets cached, it will have the right effect for us, so let's see how we do that.
1:37 We are not going to need to do anything to the site.css file, but we are going to need to understand the contents of it.
1:43 Now over here in the views, what we would normally do is we would normally just return the model like this.
1:50 But down at the bottom, I've written a function called extend_model that lets us add things, the view, the templates,
1:56 so in this case the index.pt, the box model.pt, for Chameleon templates or page template, for the extension, need to accomplish its job.
2:06 So that lets us isolate that common code down here, now we are just giving the dictionary and returning it back,
2:12 so we are not extending it yet but we are going to. Next on this little tour, let's check out this utils file we've added here,
2:19 and now this is where it gets interesting, I said what we need is we need a number or some kind of short-ish signature that we can stick on the end
2:27 there that has to do with the contents of the file. Well, you know what's perfect for that? A very simple and fast hashing algorithm,
2:33 so we can just go and import a standard library hashlib and get the md5 hash out of it and just apply the md5 hash to the text
2:43 that is the content of the file, this works for text files, by basically treating them as binary, so "rb",
2:50 so what are we going to do? We are going to say: "I am looking for a file, like the site.css, full path to it, let's create an md5."
2:57 And we are going to open this in a "with" block, so it gets closed straight away, we'll do a full read to just read all the data out of the file,
3:04 update our hash and then we are going to return a hexdigest. So this is a short hexadecimal string that we can stick into that cache id.
3:14 Now, this works perfect if there are two criteria met. First, that this is a full local file name path, not a web URL path, right,
3:25 we need to pull this off our hard drive, not off the web, second, that had better exist or this is going to throw an error.
3:32 So up here we have a little bit of error checking and juggling to make sure that's the case,
3:36 so we are going to be pass a URL, we have to somehow convert this URL into a full file path, so here is the trick that makes this super easy:
3:44 Every module in Python has a dunder file (__file__), and this dunder file is the full path to whatever file it is you are working in,
3:53 so in this case we have "util", so if I say "copy file path", this is what comes out. This is the value of dunder file.
4:01 What we want to do is we want to say: "I would like to take that and just in case this is not an absolute path, it should be,
4:06 we'll convert it to an absolute path, and then I want to strip off the file name part and just get the directory
4:11 where that file lives." That is our root directory, right, it's here, there is the directory, we can use it.
4:18 And so when we say things like /static/css/site.css well, guess what, if we append this directory to it,
4:27 then we have the full local path, right so full path here, check for the file exiting, get the hash, kick it out.
4:36 Now, if you didn't totally follow along with that, that's fine, just this is code that you stick in your web app
4:42 and you just basically forget about it. There is another step here that I am skipping as well, in production,
4:47 you don't want to do this recomputing over and over and over again, that would be not terribly expensive, but it would be inefficient,
4:54 especially if you have lots of images lots of JavaScript, lots of CSS. So what we do is we would store this hash in a dictionary,
5:02 and only computed if we haven't seen it already since our process started up. There is a few more nuance bits around there so in the final app
5:11 that you get, it will have that version of this built cache id but the one we have now is just going to recompute it every time.
5:17 OK, great, so I have this method, how do I somehow use it over here? That's where our extend, our little extend thing comes from, our extend_model
5:28 so let's go over here and we'll say "import", now because this is a package, I can't say "import utils.whatever",
5:36 I need to say the full package name and that's designable_web.utils and then down here, we are going to have method.
5:44 So, anything that I put in this dictionary is going to be accessible to the views, so let me put that function in there so it can be used,
5:51 let's do this we'll say "model dict" and just put a value in there for a second,
5:57 we want to say build_cache_id and we are not going to call that function, we are going to pass that function so it could be used
6:04 as many times as needed by the view. So if we put it here like this, when we get to our view, we can just call this function,
6:10 all right, last step, let's put it over here. So let's apply to these two. So this is fine and then we want to say "?cacheId"
6:18 or you can put whatever you want to, it doesn't matter, "=" and then I need to call that function and put the hash value of theme.css.
6:26 So we are going to say "${" to tell Chameleon: "Hey I want to execute some code, the code that I want to execute is this built_cache_id"
6:34 So I want to do this and then we need to give it well that file here. So let's do this, we just pass it like that,
6:42 it looks little ugly on this end but it saves so much trouble and it's totally worth it.
6:48 Now, I would do this to all the CSS and all the JavaScript on this page, but for now, let's just do it on these two.
6:55 First of all, let's see that hey it still looks styled, this is a good sign, and if we go and view source again, it's not there,
7:03 and if we view source here, notice now we have this cacheId, site.css cachId and so on.
7:10 So, if we change this file, I'll leave this open and put it on the end here, and I'll go and make some kind of change to it, first of all,
7:19 if I refresh, refresh, view page source, notice as I flip back and forth, these are not changing, right, those values don't change,
7:28 but if for whatever reason something here changes, like this becomes #222 and this becomes yellow, I can come over here and I just click it,
7:41 remember, this wasn't working before, boom, instantly changed, if I do a view page source, you can see now the cacheId totally changes.
7:50 So my browser has an old version of site.css and a new one but because the HTML, it only uses the new one.
7:56 This is beautiful, this means we will never have to worry about this caching problem either in a development mode or in a production mode


Talk Python's Mastodon Michael Kennedy's Mastodon