Mixins13:09 with Kenneth Love
Mixins, small classes that add or augment a single feature, are an excellent way to customize and modify your views.
When you work with classes, 0:00 often the easiest way to customize a class is to just extend it and 0:02 remove, override or add the attributes or method that you don't want. 0:05 That works fine most of the time. 0:09 Sometimes, though, you need to be able to do this manipulation in lots of places. 0:11 So you bring in another class because you don't wanna repeat yourself, right? 0:14 These little classes are called mixins. 0:18 You probably remember me showing you them back in object-oriented Python. 0:21 Well, they're coming back. 0:24 Django provides a lot of mixins for use in its class-based views. 0:26 Django also provides some mixins for handling authentication in your CBVs. 0:30 It's also pretty easy to make your own mixins if you need them, and, of course, 0:34 the Django community has provided some mixins, too. 0:37 Come over to Workspaces with me and 0:40 learn how to build your views from some smaller blocks. 0:42 So in the last video, I mentioned that CreateView was looking for 0:45 the self.object thing that it couldn't find. 0:50 So how do I know that? 0:55 Well, I've spent a lot of time with class-based views, but 0:56 also there is this absolutely amazing website, ccbv.co.uk. 1:00 I will put a link to it in the teacher's notes. 1:04 And on this site, there is really, really great documentation for 1:07 all of the different class-based views that Django provides, and 1:11 also all of the mixins. 1:16 So, for example, I can look through here, I can see the classes and 1:17 mixins that end up creating CreateView. 1:22 I can see all of the attributes that CreateView has, 1:25 what their default arguments are, and where they were defined. 1:27 And then I can also look at any individual method. 1:33 If there's also versions of that method, 1:35 you get to see each of the places where that method is defined. 1:37 And then I can look in here and I can see that there is the self.object = None, 1:40 and that's the one that created it, which is what we wanted, so awesome. 1:45 I highly, highly recommend using the site constantly. 1:50 I use it myself all the time. 1:52 So I mentioned mixins, there's all these mixins up here like ModelFormMixin. 1:54 And so mixins are small classes that will handle specific little bits and 2:01 pieces that you need to have added to your classes sometimes. 2:06 So, for instance, the ModelFormMixin is a mixin that provides a way to show and 2:11 handle a model form and a request. 2:15 So this handles instantiating model forms, putting data into them, 2:16 sending them out to the template, validating them and 2:20 handling what happens if they are valid or if they are invalid. 2:24 I suggest that you read through these methods and 2:28 you will see exactly how that works. 2:30 It's surprisingly straightforward. 2:32 One of the things that I wanna do in my views over here, though, 2:35 is I don't wanna use Django's mixins to be like, well, 2:38 let's make CreateView do this thing where it selects a bunch of records or whatever. 2:41 That's easy, that's ordinary and that you and I were better than that. 2:46 What I wanna do, I don’t wanna add some extra features. 2:52 I wanna add the requirement that the CreateView, 2:56 the UpdateView and the DeleteView, 3:01 they all require you to be logged in whenever you are trying to view them 3:03 because only logged in users should be able to create, update or delete teams. 3:09 And I also wanna make it easier to set this page title. 3:15 I have this really long block of template level logic, and 3:18 I'd rather have this in a view, then have this in the template. 3:22 So two things I wanna implement with mixins. 3:26 So the first thing to do is to make this to where it requires login. 3:28 And this is actually pretty easy to do because Django provides 3:35 a mixin called the LoginRequiredMixin. 3:40 Cool thing, this mixin and these other mixins that are here under Auth Mixins 3:43 are based on a code that a friend and I wrote. 3:48 So it's neat getting to see code very similar to my own. 3:51 So I'm gonna copy this, which is the import statement, and 3:56 I'm gonna bring it back over here to my views.py. 4:00 And as contrib comes before core, that's gonna go at the top. 4:04 And then on CreateView, 4:08 I'm going to add LoginRequiredMixin. 4:11 And I'm gonna add it to the left of CreateView because I want 4:16 the LoginRequired to happen first. 4:20 If a user isn't logged in, 4:22 I wanna kick them out before the CreateView ever really gets started. 4:24 So let me make sure that my server is running, And 4:28 then I will come over here to an incognito window. 4:34 And if I try to go to /teams/create, I get this 404. 4:41 And I get a 404 because Django is trying to redirect me to this accounts login, 4:48 which is the default login page. 4:52 That doesn't exist. 4:54 I'm not gonna build that because auth isn't part of this course, but 4:55 you are certainly welcome to try and figure that out and go ahead and build it. 4:59 Other than that, keep your eyes open for other courses about how to do auth. 5:03 But we know that it works, right? 5:08 You can see here that I was given this 404 because I'm not logged in. 5:09 I'm being sent to a login page, and it will redirect me to this teams/create. 5:13 So the login thing that I wanted to have work worked, okay. 5:18 So I'm gonna go ahead and add that to these other two views as well, 5:24 LoginRequiredMixin and LoginRequiredMixin. 5:30 All three of those views are now login required. 5:35 So great, that's really easy to handle. 5:39 Now if we're gonna do this kind of thing, it doesn't make a lot of sense to have 5:43 these update and create things on these other pages. 5:48 They all need to be wrapped with this is_authenticated thing or just removed. 5:53 I would probably just remove them, but 5:58 again, I'll leave that up to you to do if you want. 6:00 Okay, so I talked about using Django's mixins, right? 6:03 We have this LoginRequiredMixin that you've used. 6:09 How about when you wanna make your own mixins? 6:12 So let's make a mixin. 6:15 So here inside teams, I'm gonna make a new file. 6:18 I'm gonna call it mixins.py. 6:20 And inside here, I'm gonna make my mixin. 6:23 So what do I want my mixin to do? 6:26 I want my mixin to let me set an attribute on the class called page_title and 6:29 that will get added to the context. 6:33 It will just be this page title that's automatically added. 6:35 Now why do that instead of overriding get_context_data? 6:37 Well, if I wanna set a page title on 20 different views, 6:42 I have to go override get_context_data on 20 different views. 6:46 I'd rather do that not on 20 different views. 6:50 I'd rather just set an attribute. 6:53 But because not every page title is going to be, 6:54 it will be set as straight text that never changes, 6:58 we need to also provide a method that lets users programmatically set a page title. 7:01 So we have two things to accomplish, we have to have an attribute and we have to 7:07 have a method and we need to make sure that the data gets into the context. 7:11 So class PageTitleMixin, and I'm gonna set 7:15 page_title = an empty string, def get_page_title. 7:21 And here, I'm just gonna return self.page_title. 7:29 And I know the self.page_title exists because I did this. 7:33 Okay, easy enough. 7:36 But now, I need to override get_context_data. 7:38 And, if you remember correctly, that takes self and kwargs. 7:42 And we're gonna get whatever the current context is, 7:47 Because we don't know what other mixins have been applied to the view or 7:54 what other views have been applied to the view. 7:58 We don't know what the state of a view is at the point where it gets to this mixin. 8:00 And then I'm gonna set page_title to be equal to self.get_page_title. 8:05 So we get to the get_context_data. 8:11 It's gonna call self.get_page_title in order to get the page title and 8:15 add it to the context. 8:19 That will in turn return whatever this attribute is or 8:21 whatever this function this method ends up being at that point. 8:24 And then return context. 8:29 So this mixin is pretty straightforward. 8:30 This pattern of having an attribute and 8:33 then having a method that all it does is return the attribute is really, really 8:37 common because this gives you two handy ways to get the same data set on a view. 8:42 You can either set it as an attribute if it's static and is never gonna change, or 8:50 you can set it in a method if you need to be able to programmatically calculate what 8:54 this is, or maybe you need conditionally to change certain things, whatever. 8:58 This pattern here is really, really good pattern to adopting it used to. 9:02 Okay, so I think I'm ready to use this in my view. 9:07 So I'm gonna come back over here to views.py, and 9:12 I'm gonna do from .import mixins cuz that's how we do all of this stuff. 9:17 And the two views that have this problem are the CreateView and 9:25 the UpdateView, so those are the two that I wanna change. 9:29 So I'm gonna leave LoginRequiredMixin as the first because, 9:33 again, I wanna kick them out if they're not in. 9:36 And then in the CreateView, 9:39 I wanna just add mixins.PageTitleMixin. 9:43 And on this one, 9:48 I can actually just set the attribute because it's not going to change. 9:49 So page_title = "Create a new team". 9:54 But on TeamUpdateView, which I also want to add the mixins.PageTitleMixin too, 10:01 I don't know what the team name is gonna be, so I wanna use the team name. 10:09 So I'm gonna override get_page_title, and it just takes self. 10:16 And I'm gonna use another method called get_object, 10:21 which gets the object that's currently being edited, and 10:26 I'm gonna return Update blank and I'll format that with obj.name. 10:31 Okay, so I'm using the mixin in 10:37 both of the ways that I've just talked about it being usable, right? 10:39 I'm setting it here as a static attribute that's never gonna change. 10:43 And here, I'm programmatically building it. 10:48 I'm creating it through code. 10:52 So cool, that's very handy. 10:55 Now the cool thing is that both of these two views use the same template. 10:57 So to actually output this, I only have to change one thing. 11:01 So I can delete all of that and I can just print out page_title, and I can hit Save. 11:05 So again, I'm gonna restart my server. 11:11 I was having some issues with the server, it was restarting constantly. 11:16 So if you aren't having those issues, 11:18 don't feel like you have to constantly restart your server. 11:20 So let's hit Edit on the Adders here. 11:24 I'm gonna edit them. 11:27 Okay, cool, so it says, Update Adders. 11:28 And if I look over here at my view, it should say Update and 11:30 then the team name, which it does, okay? 11:35 And if I go to add a new team, I now get Create a new team, 11:38 and that is what I set right here. 11:43 So that's pretty cool. 11:46 I saved myself a lot of time and trouble 11:48 by just creating a mixin that does this little tiny bit of work that I need done. 11:51 You can make mixins like this that handle all sorts of small 11:57 little problems that come up on your project so that you 12:00 can make solutions for yourself quickly that you can reuse multiple places. 12:06 We could use this mixin on every single one of our views if we wanted to, right? 12:11 And that way, it's just there for us to use. 12:17 Part of making lives easier, I actually wanna show you, 12:20 A project, this is the one that I made that has the mixins, and 12:28 my friend Chris Jones and I did this together. 12:33 So if you find yourself using class-based views a lot, this is a, I think, 12:36 really good package of mixins to go and look through to find things that you're 12:41 like, I need to handle form valid messages or whatever. 12:46 So I'll put a link to this in the teacher's notes as well. 12:50 Mixins are the real power inside of class-based views. 12:54 And you'll do yourself a big favor to get comfortable with them, 12:56 learn which ones are available and what they do. 12:59 And not to toot my own horn too much, but libraries like django-braces and 13:01 others can save you a lot of time when you needed to tweak how CBVs work. 13:05
You need to sign up for Treehouse in order to download course files.Sign up