Python-powered chat apps with Twilio and SendGrid 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
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.