Adding a CMS to Your Flask Web App Transcripts
Chapter: Appendix: Using SQlAlchemy
Lecture: Working with package details

Login or purchase this course to watch this video and the rest of the course contents.
0:00 The last demo driven part we're actually going to write during this chapter is what happens when you click here.
0:07 Right now, it's a little underwhelming. So notice, we don't even have a link. But if I were to, you know, hack it in there
0:13 project/flask or something like that it just says details for flask. Let's compare that against the real one.
0:27 Huh, well, those are not quite the same, are they? I mean, we've done pretty well on the homepage here going back and forth
0:35 but certainly not on the details. And if we click it, it doesn't even go somewhere. So that's what we're going to focus on in this lecture here.
0:41 Well, if we go to the homepage, the index this is easy to change. This is going to be /project/{{ r.package_id }} Let's just get that working now.
0:52 I can click it and it at least takes us to where we intend it to go. Now, it turns out the HTML here is quite complicated.
1:00 We've spent a lot of time already putting the design in there and this is just a variation on that design. We have the heroes, we have Bootstrap
1:07 all the kind of stuff. So I'm not going to go over it again. I'm just going to copy some over and we can just review it really quickly.
1:14 We're going to focus on getting the data back and delivering it to that template. So, towards that, let's start over here on this page.
1:22 And right now we just say package details for some package name, but what we really want is we want to get the package from the package service.
1:31 And we'll do something like get_package_by_id or pass package_name.strip().)lower(). Okay, well, that's not so incredible.
1:44 I mean, maybe we even want to do a little check here. So if not package name just so that doesn't crash
1:52 we might do a return flask.abort. Status equals 404. Something like that. Okay, but let's assume this is working.
2:04 And down here now. And we can go to a query. It still might not be found. So we might say, if not package, again, not found.
2:14 Right? They could be they asked for a package, abc one, two, three, it doesn't exist. So we don't let that to crash.
2:21 Now, let's go and have PyCharm write this function. It's going to be package_id, which is going to be a str. It's going to turn in optional package.
2:31 We're going to import that from typing. It's optional 'cause, like I said you could ask for a package that doesn't exist in the database. Super.
2:39 Well, how's it start? How do all of them start? They all start like this. And somewhere we say db_session.close probably.
2:46 And in the middle, we do things like get us the package. And the package is going to be, again, one of these sessions. We're going to create a query
2:53 a lowercase query of package filter and what we want to do is say package.id == package_id. And again, maybe this one would want to do that test.
3:06 Actually something like this. It's a bit of a duplication but let's go package_id.
3:23 Instead of returning abort, we'll return none which will see it as missing then it will abort it.
3:27 And then here we'll just say package_id equals package_id. That's true. Okay. It's a little bit of data protection
3:38 because that is user input right there. All right, so we're going to get our package. Now, if we do it like this, we get a query set back.
3:45 Not what we wanted. All right, we don't a want a query set. What we want is, we actually want one package. So we'll go over here and we'll say first.
3:52 And that's either going to return the package or nothing hence, the optional right there. Then we return package, like so. And we should be good.
4:03 We can just do a really quick test here. And let's just do package. So this will show that we're either going to get a 404
4:12 or we'll get it back and will show its name when we click on the homepage there. Let's try. Put down, click on boto. Details for boto, woo!
4:21 We got that from the database. It's pretty cool, right? And so super easy. I mean, seriously, like that is easy.
4:29 However, our little package details page actually needs more information than what we have here. So we go look through this.
4:37 You can see we're adding a new style sheet to the top of the page. And we're having our hero section, it has a id and package this and package that
4:44 but it also has a handful of other things. So it wants to work with the releases. Now this is going to cause a tiny issue
4:51 that we're going to catch and then improve. So we're going to have latest version is going to be zero.zero.zero to start, okay?
5:02 We're also going to have latest release is going to be None. And we'll have to say is latest equals true. So the page adapts on whether or not
5:13 you have the latest version. We're just going to say it is for now. We need to actually have the instance that is the latest release, if it exists
5:20 and also the text of the version. So we'll say this, if package.releases remember this is sorted in the order of newest first.
5:30 So we can say, latest release is package.releases of zero and latest version is going to be latest release version text.
5:44 And we'll just leave is latest is true. Now the other thing we want to do instead of just returning the string
5:50 is we want to go over here and say, remember to this? And we said, response, this was from long ago. And what was it? Template file is going to be
6:00 it's going to be where is it in this folder? It's going to be packages slash details. So packages slash details.html.
6:09 And then for this part, we don't return that. We return a dictionary of stuff. And there's a bunch of stuff that I got to put I here.
6:16 So I'm just going to copy this over. There. So we have our package, we want to hand that off. Latest version, latest release
6:23 whether or not it's the latest. Let's make this a little bit more obvious. Pass it through. And of course, a lot of this
6:29 could be computed in the template. That would be wrong. The template is about taking data and turn it to HTML and not doing all this logic.
6:36 It's best to get this as much ready for the view as possible. Here, we're going to talk about patterns that make this better later
6:42 but right now it's already pretty good. Let's just rerun it to make sure we're all good. Over here and refresh. Now, what happened? Why did this crash?
6:54 Well, if I didn't do that close inside here my package service, it wouldn't have crashed. So you might say, Well, just don't do that.
7:03 Again, this means that like database query operations and lazy loading is leaking into our template. So one option is, we'll let it leak
7:13 and everything will work. The other one is, well, what do we do up here, we add in one of these joined loads.
7:20 We kind of basically need the same thing but in reverse. Let's put the dot here. And not there. So instead of saying
7:32 I want to go to the release and load the package I want to go to the package and load the releases, plural.
7:38 It should've reloaded when I saved, and ta-da. How cool is that? Look, it's already working. Yes, I copied over the HTML and the CSS.
7:48 But that's not the hard part, is it? I mean, maybe it's hard at some point but that's not really the essence of this data-driven app.
7:55 So here we've got our pip install boto. Here's the version. Is it the latest version? Yes, that's why it's green.
8:00 You can go, here's a project description the release history. If I want to go to the homepage click on that, it takes me to the Boto3 homepage.
8:08 Right? All this stuff. Let's see what we get if we put Flask up here. We have Flask, and we have all sorts of stuff like here's the license.
8:16 We go to the homepage, we go to Pallets, and so on. And we don't have every bit of details in here that the main one does, but good enough
8:24 for our demo app, right? This is cool, huh? We did some query against our database filtered by the ID, got the first one
8:33 but then realized, oh, we're trying to navigate that relationship. So instead of doing the in plus one interactions
8:38 with the database and, you know, leaking and lazy loading let's explicitly catch that by closing it. And then do a joined load
8:47 to eager load it all in one query. That's pretty awesome. So now things are going really, really well.
8:53 There might be times when you don't always want to do this and you might have to have a little flag you pass on whether or not you do this
8:59 just because if you don't want it it's a little bit extra overhead on the database but generally, given a package, we want its releases.
9:06 So I'm pretty happy to just put this right into the main method. All right? That's it. We have our data-driven package page
9:14 and our homepage up and running. I'm really happy with the way the site is coming along.


Talk Python's Mastodon Michael Kennedy's Mastodon