Full Web Apps with FastAPI Transcripts
Chapter: View models and services
Lecture: Adding a view model to the home/index view
Login or
purchase this course
to watch this video and the rest of the course contents.
0:00
Welcome to chapter five. Let's get started working on these two patterns view models and services So, as you can see here,
0:07
I've made a copy of what we completed in chapter four and that's what we're starting with in chapter five.
0:12
Let's go ahead and open it up and over here we're gonna focus on this view right here. Let's just run it and remind ourselves what it looks like.
0:21
So it's this page here that shows a couple of things, and we're gonna add something else that's gonna be interesting that we weren't able to do
0:28
easily before. Here, we've got the number of projects, the number of releases, the number of users and then the most recent projects.
0:39
So what we're gonna do is we're gonna create a view model that provides this page, this template, that data.
0:46
Now we're gonna start simple here because we're not exchanging data. We're not accepting data yet. Later,
0:52
we're going to write a login and a register bit of functionality. This is gonna let us do many things,
0:57
work with HTML forms and validation and all that. That's when you'll see these concepts of view models really shine. But I wanna, you know,
1:04
make progress down that road until we can get to the user section in the coming
1:08
chapters. What we're gonna do is we're gonna create a view model that just provides
1:11
data to this page, and we're gonna have some services that work with projects and users. Let's go and create a "service"s folder.
1:21
And like I said, we're probably gonna have to. I'll go ahead and just write it
1:24
here, package_service. Again, this is not web service in the traditional sense of
1:30
the API. This is a thing that bundles functionality and think of it as a layer between your actual data layer and the rest of your application.
1:38
It knows how to do all the queries to SQLAlchemy. It knows how to interact with external APIs that you might need for,
1:45
say, sendgrid or mailchimp or something like that, using either of those services. While the user service,
1:50
here, the user service might know how to verify passwords with cryptography. In addition, it's not just data access layer,
1:57
that's no what. It's why I'm not calling it that. OK, so we're gonna need a couple of things in order to do that, to make these useful.
2:04
But let's go ahead and do our view models, now recall that we have some really cool naming conventions that allow me to say, well, I'm looking at this.
2:13
Let's say I'm looking at this function, this view method. I want to know where's the template. I don't have to guess what it's called or like
2:22
track it down. I go. OK, so it's home index. So it's home index. We're gonna follow exactly the same pattern for view models.
2:30
That way, if you're in the view model, you know where the function is. That is the view function. You know where where the template is.
2:37
It's really nice and organized. So I'm gonna go, create a directory called viewmodels. And in there we're gonna make a directory called
2:45
home, and at home, we're really just gonna probably need one view model. We're also gonna need to have a common base class.
2:53
I'm gonna create something called shared, and I'll put, I'm gonna calle it viewmodel_base in here.
3:02
Maybe just a few models. Here we go, and we'll have a class. Now, it might seem silly like, why do I need this base class? What is its job to be?
3:10
There's a couple of things that we want to make sure every single page has all the time. For example, when we do user management stuff,
3:18
we wanna have it be the job of these view models to tell you what user is logged in and potentially provide you with that user and
3:25
so on. If you're in a form, they always are gonna be able to provide an error message if something goes wrong with
3:30
the form. So there's a couple of things like that that are gonna be part of this base model. The other one is, we need ways to easily provide the
3:37
fields of the class as a dictionary. So those are the two rules here. So a ViewModelBase, let's call it. And down here its gonna have a
3:48
couple of things so we'll have an error, which is an Optional, we're gonna need some typing here, string, which is None. And let's have ah user_id,
3:59
which is an Optional integer, which is also None. So those were the two core shared pieces of data. We're probably gonna pass around some more.
4:08
It's often helpful to have access to the request that comes in as you'll see for, like, cookie management and stuff like that. So let's go and add that
4:18
in here as well, and PyCharm will gladly add that. Now wouldn't it be cool if it typed that for me?
4:25
OK, so it'll have this stuff and then, in order to pass these things back we're just gonna take advantage of the fact that when you do this,
4:32
what it's really doing is putting an entry in the class dictionary. So we'll say def to_dict, gonna return a dictionary. And what's gonna be in here,
4:45
we're gonna do is just return self.__dict__. So this is looking good. This is gonna be something common to all of our
4:52
view models. We're probably never going to touch it again. And then, now let's go. Remember, we are in the index, and in the home
5:01
I'll say, indexviewmodel. Add a class IndexViewModel like that. I'ts donna derive from our base class, which we import. Thank you,
5:13
PyCharm. And it's going to need, yes, it'll need a constructor. Alright
5:18
And PyCharm says there's one that requires something passed in so well let PyCharm write all that code for us. Thank you, thank you. Super cool.
5:27
So let's go back. Now that we've got our structure in place, Let's go back up here to our home view and say,
5:32
What were we doing before? we were coming up with all these elements,
5:37
this dictionary that has a package_count, a release_count, user_count and a list of packages.
5:41
I'm gonna copy this over. And this will give us a hint on what we're going to need in our indexviewmodel. Over here tells you that we're probably gonna
5:49
need a self.package_count, which is an integer, and I'm just gonna put None, I'll put zero for a minute.
5:55
We're gonna come up with a better answer in a moment, and we need a release, release_count and a user_count.
6:06
And then it is the order here we're gonna need packages. Which is gonna be a list of something.
6:18
We don't know what goes in the list yet because we don't have a class for it, we will in a minute. And we'll just say like that.
6:23
OK, so let me go and comment this out and see if we can now swap this out to be our view model. And I'll just put 1, 2 and 3.
6:34
So we have some little big data, it's just so you can tell actually, something is flowing from one place to the other.
6:40
So instead of this. What we're gonna do is we're gonna say vm for view model. It's one of these. We've gotta,
6:47
of course, import that as above. And then we have to pass in the request. PyCharm'll help us get that close.
6:56
close. We've gotta type that in. FastAPI uses the type hint here to know that what you want to pass in is the request. So this is all we have to do,
7:08
and then it'll start passing it over. And then again, if we don't pass anything,
7:12
watch what happens. We get a crash and the crash is NameError somewhere. The NameError is right here.
7:21
package_count. You're supposed to give me a package_count, and you didn't. So let's provide the data from here,
7:26
which will be to_dict. It was basically like before. It's gonna build up that dictionary like we saw. Not as much data, but close.
7:35
Yes! Look at that 3, 1, 2. Maybe we could've changed the order to go 1, 2, 3 but still cool, right?
7:39
So it's provided this information. It's gonna get it from somewhere else in a minute, but it's provided this information,
7:45
and it's given us an empty list of new releases. We're gonna need to get them from somewhere again.
7:50
Pretty awesome, right? So this is how we're going to pass data over to our template. Now let's go back and look real quick.
7:58
Suppose that we want to make sure that the request is not None. We want to make sure that you know some data that we're pulling back is valid
8:07
here or if we pass in more things like we're passing a form that the form contains the elements that we expect.
8:13
It's really, really easy to write a unit test against that class right there and do that validation without doing any web test infrastructure,
8:22
which is always kind of a pain around unit testing web applications.
8:25
So it allows you to really carefully test the exchange between the template and this thing
8:29
You could even actually use the template engine to directly try to render a test instance of one of these things.
8:36
So that's pretty cool. It's also going to keep this method extremely simple. For real
8:41
ones, it's gonna be slightly more complicated than that but not a lot.