Full Web Apps with FastAPI 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.