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