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