Creating an Inclusive Django Community with Kenya Phelps
Published July 15, 2026
This video features Felipe Lee at DjangoCon US 2019 in San Diego, California, USA.
DjangoCon 2019 - Generic View? What is that and why would I use it? by Felipe Lee
In this talk I'll discuss Django's generic class-based views (CBVs). I'll go into detail on what they are, how they compare to function-based views, and pros/cons for using them. I plan to go deeper into certain aspects of CBVs, explaining some of the internals of how django defines them.
This talk was presented at: https://2019.djangocon.us/talks/generic-view-what-is-that-and-why-would/
LINKS:
Follow Felipe Lee 👇
On Twitter: https://twitter.com/felipeleeg
Follow DjangCon US 👇
https://twitter.com/djangocon
Follow DEFNA 👇
https://twitter.com/defnado
https://www.defna.org/
Intro music: "This Is How We Quirk It" by Avocado Junkie.
Video production by Confreaks TV.
Captions by White Coat Captioning.
Django’s generic class-based views package repeated CRUD patterns into reusable classes built from mixins, while `as_view()` turns a class into the request-to-response callable expected by URL routing. Felipe Lee explains how `View`, `dispatch()`, `setup()`, context and template-response mixins, and HTTP-method handlers fit together, then demonstrates `TemplateView`, `RedirectView`, `ListView`, `DetailView`, `FormView`, `CreateView`, `UpdateView`, and `DeleteView`. Class-based views offer reuse, inheritance, and cleaner method handling, but their control flow is less explicit and decorators require extra care; the practical advice is to use a generic view when it closely matches the need, override only a small part when necessary, and fall back to `View` or `TemplateView` when extensive customization would make the abstraction harder to follow.
Summarised automatically from the transcript.
Automatically transcribed, so expect mistakes in names and technical terms.
Hi everyone. My name is Philippe, as I was just introduced. My talk is going to be about generic views and class-based views in general. I do want to start by saying thank you to all the organizers for putting on an amazing Django Con. It has been great. I don't know about y'all anyways, but I've had an amazing time. Oh slide. There we go. Now we're back. Wait, no. Not back. There we go. Okay. Um All right, so a little bit about me. I am a software engineer at UT Austin. I was actually trained there at UT because we have an amazing program to train people that have no background. in technol in technology to be software developers. If you have any questions about that, you can ask one of the many UT
people that are here. And we use Django for a lot of our websites, so that is also why there are many of us here. A bit about not some helpful knowledge going into my talk is uh just having a basic understanding of Python classes, uh URL routing in Django, uh, and function-based views. Also a little bit of forms, but that's not really vital. And then hopefully you'll walk away from this talk uh with an understanding of class-based views and specifically uh generic class-based views within Python, or within Django, sorry. And then some pros and cons to class-based views as well as some examples of good and bad use cases. A lot of the
I'll have code samples throughout my slides and they'll be in Python 2, Django, or Python 3, 7, Django 2. 2. And then I also have an example repo that has some of the class-based use usage. And the in there I also have function-based views that like mirror the usage so you can kind of see what they're like trade-offs. Um and they'll be labeled. The slides will be either say sample they'll say sample if it's from this repo or if it's from Django, it'll have the little Django icon. Alright, so getting into class-based views. Um so first a little bit of history. There's actually an interesting history that led to this. So one thing that we have a lot with web apps is a lot of them are just kind of crud.
You do a lot of crowd patterns with it and that repeats a lot. So Django, we wanted to make something that would make it a little bit easier for us so you don't end up copy-pasting all the time. And so a solution was to do function-based generic views, which I mean what they did is they abstracted a bunch of logic and you would just pass it a few arguments to the function and it would handle it. So basically you would maybe pass it like a template name or like the form that you want to use. But a problem with that is that they're limited. You can't really extend or customize them easily. So if your use case was even slightly different, you basically had to recreate the view yourself. Because of how functions are. So that's where we got the idea for class-based views, because Python classes are meant to provide functionality that's easy to extend and override.
So then the question became, well, how do we actually implement class-based views in Django? So one of the things we need to keep in mind is how do you deploy them, how do you use them? And then how does URL resolver actually handle them? Because it's it won't be the same as with functions, or it could be, but that's what we'll talk about. How easy is it to subclass them and override whatever functionality you care about or need to change? And then thread safety. So you want to make sure that every request that comes in is its is on its own. It doesn't interact with any other request. How easy is it to test? Like do you need to do anything special for when you want to test them? And how easy is it to decorate it? Because if you want to use decorators, we want to make sure that it's still easy when you switch over to class-based views.
Um so really quickly, let's look at an example of URLs. py with a function. So the second argument that you have here is a function. Um and we just pass it the function without inst without calling it or anything. The URL resolver will take care of calling it with your request and it will pass any args or quargs that it needs or takes. And so in essence, what this thing is, the second argument is you want it it needs to be a callable that will take in an HTTP request and will return an HTTP response. Oh, typo there. We'll return an HTTP response. Um and that's in essence what you need there. But there's a few problems when you start thinking about how classes work because you
Uh with classes, when you instanti when you call them, you don't normally return something that isn't an instance of it. So uh yeah, so that's one thing to keep in mind. Another thing to keep in mind is Your URLs. py runs when you start your server. So if you were to instantiate a class right here, that's what that would happen when you start the server versus when every request that comes in. So that causes some issues that we'll get into A little bit. Yeah, so view instantiation and thread safety. I'm gonna go over this a little bit quickly, mostly because this isn't directly the meat of my talk or the reason for my talk it just kind of explains some of the reasons why it looks how it does now. So one of the ideas was or I'm going to go over some ideas of what
was considered before we got what we where we are actually now. I actually also have a link that has the article in case you're interested in reading more in depth about all the reasons of pros and cons and all that. So one of the ideas was storing the request. or storing state on the request. Um because like I mentioned, if you instantiate it in the URLs, that same instance is going to be used across all your requests. So you can't really store State on the uh view because that'll be shared. So the one of the ideas was let's just store it on the request because that gets put in fresh every time. Uh but obviously that has some cons in that you can't well in that you can't store any state on the class itself on the instance because of the bleeding over. So that's one issue. Another idea was with call.
So like basically you would put it in there and then whenever you call the instance, it would make a shallow copy of itself. But that's also weird. Uh in uh like one of the cons is that it is weird. It's not what you would expect a class to do when you call it. So That's one issue. Uh another one is new, so this is like just when you instantiate the class. So you would just put it basically just the class name. You wouldn't actually instantiate anywhere else. Um The issues with this is that you can't pass anything to in it. So like if you want to pass any arguments to it, you can't really do that easily. There's a way around that, but you'd have to go do that other thing. So um so that was a big con to it So another an idea was brought up to say, hey, let's define a method on a class, and this method will take care of actually creating
um our class-based view and handling everything as it needs to. The c one of the cons with this though was that you also cannot pass arguments to it as is. So there was a class method too. And this one you would actually call this class method. And what this lets you do is uh pass arguments to it. And if you are familiar at all with class-based views or generic views, you can see that that's actually what we went with, but um but there's two more. So one more is we're HTTP response subclass. So this one's a little bit weird. Um So this one, they the idea was that you would make a view a constructor that return that like creates an HTTP response. Um It's weird in that it makes a view
and HTTP response be tied together in an object-oriented way that we kind of don't really want it to be because we don't want view to be a response. We want view to return a response eventually. So some weird things there. And the other one, the final one, was URL resolver. So another idea was instead of messing around with any of that, let's just make URL resolver figure it out on its own. So it'll take in the, or it'll check when you pass it, hey, is this a class or is this a function? And if it's a class, do the special handling to set it all up and then pass it on. But that would require special handling and URL resolver, which we didn't want. And then decorators become a bit of a nightmare to actually decorate your view. So
Like I mentioned before, as view is the way we went. Um so as view, the way you use it is you so this is we just have a create to do list view. Um and it's just uh a class-based view. And we don't instantiate it, as I mentioned before. We don't do that because it causes some issues. Uh we call as view, and as view will handle Setting everything up that we need. I'm gonna go into how that is handled, but for now just know that it set us sets everything up that we need, and here we'll be able to take a request and return a response. I have this diagram again just to show it, and it also has the same typo that I didn't fix on the second one. It returns a response, not a request. Um All right, so at this point we now have class-based views, they work.
Um but we want to add some functionality, so we start getting into mix-ins. So the idea was that any functionality you want to add. We should do it in little bits and chunks so that you can kind of mix and match however you want. If you care only about this very specific piece, you can easily grab it without having to either recreate it or break something up So mix-ins were the plan and so we would work with class-based views with uh generic class-based views would be built up through inheritance. So for example, here on the top right we have view, and that's the view, the class-based view that just enables everything And then we have two mix-ins. One of them is context mix-in, one of them is template response mix-in. And so these two add some functionality, which we'll go into later.
But What we want or what we do with it is we combine all three and that'll make template view. So now we have a generic class-based view that Django provides. Um yeah. So Let's go into a sample use case, like why would you even want to use generic class space use, right? So Just creating creating a new instance of a model. Uh it's something that's very common. Here's a simple uh function-based view that on get will instantiate a form and then Render your template with the form. It's pretty simple. And then if it's a post, uh we'll instantiate the form, pass it the data, and Validate it.
If it's valid, we save the form and then redirect. If it's not valid, we re-render the template with the form with errors, right? Really simple. This is a really short view, doesn't really take much. But like why would you write all that when Django provides a create view, a generic view called create view, and all you have to do is set the template name and form class? And that's it. So this already like does everything that the function-based view did. And then in your URLs, basically the way that would look is this is the function-based view. You pass it the function, right, on the second argument. And the class-based view, you do the create to do list view as view. And that's it. So generic class-based views are great in that they encapsulate a lot of logic that we repeat often.
I'm sure you have to create instances all the time, so why would you want to repeat that type of view for all your models or something when you can just easily s subclass create view? So let's get up to a few pros and cons. So function-based views. Some pros. Explicit code flow is like one of the b biggest pros for function-based views in that With a function-based view, it's like any Python function, as you you can just read it straight through and see what it's doing, assuming you wrote it cleanly. Um So you can see exactly what's going on. There's no wondering what happened or anything. Um another one is decorators are really easy to use, easy meaning. If you know how to use decorators in Python with functions, you know how to use them with function-based views
because it's the same thing. Some cons. They're hard to extend and reuse, so kind of that same issue that we had with the generic views in Django. the generic function-based views in Django that they were hard to extend and reuse, you kind of have that same issue with your own function-based views. And the other one is HTTP methods are handled through conditionals. So that gets a little bit ugly after a while. Uh for class-based use though, so pros, we have all the built-in generic class-based use. Django provides a ton, and they give us a lot of functionality. And then HCP method hand are handled through methods on the class. So it's a little bit cleaner. You can just look for the method that does exact
like if you're doing a get, you can just go straight to the get and say see it w rather than reading through your function logic to figure out when do you check to see if the methods get um And then uh you can use object-oriented techniques, meaning you can uh create mix-ins, do inherit use inheritance to your advantage to try to like piece together what you need and make it easier for yourself. One of the cons though is, and the biggest con, is implicit code flow. So I showed you that example earlier of that create view, but if you don't actually know what create view looks like, like You don't know what it's doing. Um you're just right now taking or unless you're familiar with it, you're taking my word for it that I'm telling you it's doing what that function-based view is doing. It's going in and instantiating the form, rendering the template, and handling
on post, saving the form if needed So that can be a little bit of a of an issue, especially uh when you're new to coding. I know when I first started I had a lot of issues with class-based use because I never knew what was happening. Um and then decorators are They're not as straightforward to use in that classes are different than functions, so you need to do a few things, but thankfully Django actually provides some ways to help you with that. So it's not too bad. Yeah. And then so getting into some actual internals. So earlier we were talking about how our base view that actually enables class-based views
is this this is this is it. Um it's just a class that has an attribute called HTTP method names. What these method names are are basically what's allowed in the class space view or what methods you're allowed to pass in. This is different from what you'll handle, which I'll go into later. But yeah. And the list is cut off because it's long and would be not legible otherwise. You pass it and it will set attributes or set attribute values to what you pass in. It's really simple, but really powerful in ways that I will show you later. Um okay, so you might be wondering, hang on, we don't instantiate our class in the URLs.
Um And just proving that again. Um here's the class-based views in the URLs. We don't instantiate, we call AsView. So the way this works is AsView is handles all this magic for us. So what AsView does is it's a class-only method, meaning it's meant to be called from the class. And it will take init quarks. Um and the name init quarks basically is just telling you they are quargs for your init. And then so what it does, the what we want to be careful though, so that one of the first things we do is we loop through all our init corgs and audit two things. One, we don't want any initquarks to come in and try to set up any uh methods. So we check to make sure that none of the keys are an HTTP method name.
So basically we don't want someone to try to pass like get in there. Um I guess you could maybe do something with Lambda or something, but I don't know. It's weird things. So just avoid it. Be setting new attributes through this, it gets a little messy. I mean, if you really want to set a new method, just go define it in your view and then you can pass it in. Um so just to be safe, we check that. And then after that, so now we get into the really interesting bits of asView. So asView within its definition starts defining a new function called view, uh which look may look familiar. It's just a function based view basically it takes a request args and quarks. Um
and then the first thing it does is it inst this what the first thing this view does rather. is it instantiates our class with our init cords. So here is where our init chords come into play and get eventually into our class. Um the next thing it does is just some Handling to make sure that if you haven't defined head, you kind of make head and get the same thing. Because why not Um and then setup. Uh so setup is actually a pretty neat method that just got added in Djago 2. 2. Um and so what that does, let's We're not done with as view, but we'll go we'll go back to it right now. So what that does is it takes args and requests args and quarks and it sets them on your uh view uh as attributes. And what this means is that in any of your methods you can now add access them pretty easily, uh which is great because then you don't have to worry about defining your methods
uh signature to include request arguments and queries and then worrying about how to get it to them. You can just Know that they're there. Um and one of the useful things about s like Django already did that before in class based in the as you before, but now it it pulled it into setup. in 2. 2. And what that lets you do is if there are any attributes you want to be accessible in all of your uh Sorry, blanking. You want accessible in any of your methods. Um you can set them on here and then just call super the default will set up the request arcs and arcs and you're set. Now you have attributes you can access easily anywhere else. All right, so back to our view function that we're defining within ASVU. So we called setup immediately after we have a little
validation to make sure that we did actually call super if we overwrote it because or super first setup if we overwrote it. So we just checked the requests there. And then at the end, what this view does is return or call dispatch with request arguments and quarks and return what it gets back. So um So views we we'd already said earlier, uh they need to take an HTTP request and return a response. So what we're saying here is we're kind of passing that on to dispatch and saying like, hey dispatch, I need you to return me a response I'm just going to trust you and you can do that. So now we know dispatch, which I haven't covered yet, but I will in a second, uh, is supposed to return a response of some kind. And then after we've finished defining view, uh
we do a few things on it. Uh so view or functions in Python are just any like uh Python object, which means you can actually set attributes on them. However, you want. So in this case, we set view class and view init corgs in case you want to access them later for whatever reason. And then the next thing is kind of neat. Because we're setting up this function, uh this function is actually not our class-based view, obviously. Uh but we we want it to act like it and we won't And we want it to look like it. And we've already s taken care of it acting like it by returning the dispatch and all that. But now to make it look like it, uh we use a funk tool called update wrappers. or update wrapper. And what it does is it takes this view, it takes our class and just kind of takes like the name and the doc string and a few other dunder
attributes and sets them on the view on the function. And then uh the last thing is I haven't gone over decorators really, but decorators are typically put on dispatch and They sometimes set up attributes on the dispatch itself. So we want those two. So we do the same thing again with update wrapper, except this time we pulled them from dispatch. And one example of an attribute that might be set is like CRSR of exempt. And then at the very end of as view, it returns view, as is. Like we've just defined it basically and added a few attributes on it. So what that means is here What this all means with this cla uh class-based view is that when we're calling as view, we expect it to return view, and view is just a function at this point. point. And at that point, we are basically using the same thing as we used with uh function-based views.
Final thing for view is dispatch. So dispatch is uh really simple. All it does is receive request args and quargs, and its job is just to figure out what is going to handle this request that just came in. Uh so it just checks to see if it's if the method of the request is an allowed one. So from that list earlier that I showed you. Um and if it isn't, it returns an a 405. HTTP response not allowed. Um but if it is allowed, then it tries to find the handler for it. So it looks on your view and says, hey, have you defined, for example, get? Um and if you haven't, it once again returns HTTP method not allowed. So that's why I was saying that that list is allowed and handle like the different there's a difference between what it allows and what it can handle um and here's where that gets resolved.
Uh but if it is res if it is defined, so if you do have get on your view, then what this does is it'll take it It'll call it with request args and quargs, and then it will return that. So dispatch is also kind of passing on the responsibility to something else for returning the HTTP response. Um so one thing about view is it doesn't actually define any of the typical methods that return an HTTP response. So you can't just use view and not define anything special on it. You have to define get or post or whatever you care about. It defines a few things, but if you want to do get post, it doesn't define those. Just okay, quick pause because that was a lot of information
and also water. Okay. Okay, so that's a lot of stuff. Um and I don't whether or not you followed. Um I to be honest with you, like there were parts of that that I didn't understand until I was preparing for this talk. Like I've been working in Django for like four years now, and there are parts that I was like, that's just magic. Um, which it's not. It's actually It's not magic, it just takes a little bit to understand. Um but yeah. But it's pretty cool and it'll set up set us up to do some really cool things, making our lives easier, at least. It can. So Django provides a lot of generic uh views. And
like I was mentioning earlier, the way that works is Django's point of view is We provided class-based views through Vue. Now we're going to provide some generic class-based views that you can use to do things. But the way we want to do that is We want to provide a bunch of mix-ins and those mix-ins will each do something like a little bit of functionality that builds up to whatever great thing you are doing with your website. Um so the most basic one is context mix-in So when we normally work render our templates, we pass it some type of context. That's how we pass it the variables that we care about, right? And so what context mix in is it's kind of meant to do that for class-based views. And it defines just one attribute, extra context, and defaults it to none.
And I'll go into that right now. And it only defines one method. This method is getContextData. And what it does is it takes whatever quarks you pass it, and it adds in view. So it adds itself in, which is kind of neat because then that means that you can easily access any attribute of the view. in the uh template. So like if you want to look at your user, you can easily do view. request. user. Or you could access any of the quarks that the view was uh that was in the request for the view. So yeah, so that's pretty neat. And then uh the other thing it does is it takes extra context and if it's been defined, so like if you in any of your methods actually defined it beyond none, it will update the con the quarks with it. Um the intention for that was kind of to make it so that
uh kind of how you I I talked earlier about how you can pass things to AsView and it will eventually make it to init. Which will then set it as an attribute or set the value of the attribute. This means you can kind of take it in your URLs. py, you could pass context. To the template directly. Uh don't know if you want to do that. But what I like about this uh is that in any of your other methods, if you want to put anything into the template context easily, this is what how you can do it. You could just access extra context. Just create the dictionary or add to it if you if you've already created it. And then you don't have to worry about it. Get context data will eventually put it into the context that hopefully makes its way to your template.
So yeah. And then the next one is template response mix in. So this one defines a few attributes. I'm not gonna go over all of them. The most important one is template name. Just point it at the template that you care about. Um and then its important method that it defines, it defines a few, but the most important one is render to response. So this one takes care of As you can see at the top, it takes in context and a few other things. Uh but context is the important one. So it takes in context and it renders your template that you've told it, that you've given it the name. It renders your template with your context. And so this is actually the portion that returns the HTTP response because it's rendering your template. So going to our first
generic class-based view, uh what this is is template view. So it takes in those two or it combines those two mix-ins and that view. uh the base view and all it does on top of that is like I mentioned none of those other ones actually define get. So this one is like, all right, I'll define get. And then I'll use getContextData to get my context, and then I'll pass it to render to response, and I'm done. So this is literally all of template view right here. Um it's really simple. And that's kind of the point of doing mix-ins too is to let your final views like just do the thing that they need to do once they've combined all the functionality. So for example, here's template view. Here's a template view for home. I just define template name and
uh That's it. There's another way you could do this though. You don't even have to define it in your views. py. Because of the fact that you can take advantage of the fact that as view will pass attributes on, you can set template view in your URLs. py and do a home page like this. Um whether or not you like to do that is up to you, but I mean I think this is pretty nice if it's a simple homepage that doesn't need anything else. Uh the next one up is redirect view. So this one provides a few things, the important ones being URL or pattern name. Um and it does exactly what it says. It's just redirects. It's really quick and easy. And so for example, one way, one thing that you could think of is say you have a website, a URL that's show all lists, and then your client says, hey, you know what, instead of show all lists, I want to rename the URL to say list
to do lists. For whatever reason. An easy way to do that is using redirect view. You can create your new new your new path Put the old view there and then in the old path you can just set redirect as view and then pass it the pattern name to your new or to yeah to your new URL and you're set. Um Although you should next one up is list view. So this one's just what it says. Just set a few attributes. Um one of the things that this that's cool about it is kind of sets you up to be able to paginate through data Uh so if you have a lot of data, it makes it pretty easy to do that.
One downside is it doesn't set up an easy way to filter uh your data. So if you need to filter it at all, yeah. I will show you an example though of how you can filter it. So here we have two URLs. They both lead to the same list to do list. I should have chosen different names. Uh list2do list view. Um one of them is just straight to the URL, the other one takes uh captures name search. Um And the view itself, my subclass, is just, or it could just be list view uh setting of the model and the template. If I didn't want to do filtering, that'd be it then, which is really nice. They would then go and list all my instances of to-do list model. Um if I wanted to do pagination, I'd have to set up a few attributes here, but that'd be it, just kind of telling it how many per page and a few other things like that.
But since I want to do filtering, uh we need to do a little bit more. So one of the methods that it defines, that listview defines is get query set. And so that's what it uses to go and get all of your model instances. Um and so what I did here is I just let it let super do its thing and return all the instances. Um and then I just check to see if I need to actually filter it. So here I'm taking advantage of the fact that quargs was set as a self-attribute, meaning I don't actually receive quargs in GitQuery set, but I can easily access it. And then if I need to, I filter the query set and then return it. If not, I just return the full query set. So it's not set up to easily do filtering like through attributes or anything, but you can it's pretty simple to set up just overwriting a git query
set. Okay. Uh another one is detail view. So detail view lets us um Just put out the details of some model instance. Um it's really simple. It's kind of basically implement it's implemented in a similar way to list view except focusing on a single item. Um And so this one, uh same thing, it kind of just needs the template name and the model. Um I took it a little bit further and added another attribute. So By default, display view or dis sorry detail view um sets uh your instance into the template context just as object, which I find weird. Um it makes sense, like for being a generic view, but if you want it to actually make more contextual sense in your template, you can give it a name, and so that's why you can set context object name.
So like I just said this is gonna be a to-do list Um so it's up to you though. You can just use object if you like that. Uh but you might be wondering, hang on, how does it actually know what instance we want the details for? Because you know, I didn't actually define anything here. I just said, hey, here's my detail view. Go figure it out and get something. Um so the way it does it is through uh the URL. And in the URL we capture the integer PK and call it PK, and then it'll pass it as a quarg. Um and the reason this works is because one of the mix-ins that goes into making this uh sets up something called PKURL cord, which is the second to last one on that list. Um and it defaults it to PK URL
Okay, so it's just, I just went with that name. If you really care and want to change it to something else like ID, you can. And that's all you have to do is in your URL capture ID instead and here change this attribute to ID. So pretty simple. Um form view is the next one. So now we're actually getting into being able to do stuff beyond just listing things or showing data. So form view lets us actually render a form and uh handle it, process the form once it gets submitted. Uh and so the way Sorry. I realized I forgot to mention one thing earlier. So I was talking about how
uh The way all this works is we have mix-ins and combine them with views. And Django, to create its generic views, actually takes those mix-ins and makes other mix-ins, so like context mix-in. gets subclassed and added functionality gets added and then like template response mix in also gets subclassed and functionality gets added. So that's why like here on Form View we don't have either of those. We have template response. Oh wait no that's that is the same one. Sorry, that's the wrong thing Sorry, I'm all over the place. Uh but form base form view is basically the same thing. Base form view is view mixed in with other things that kind of eventually makes it to call something called base form view, and then form view just takes that and combines it with template response, mix it in. Um but there are other mixins that just are pure mix-ins. And when the next one comes up, I will pull
point that out. Alright, so Uh one thing about this though is that form view is designed to only handle post submissions, which is not ideal for everything. So if you have a get farm, you need to do a little bit different stuff, but I'll show an example of doing that. So form handling. So if you want to set up uh or what it does for us is it sets up this uh method called getForm. And what it does is it takes a form class. And it instantiates it and passes it a bunch of quarks through a method called getForm quarks. Um and it eventually will make its way to the template just as form, uh which is typically
And then on post it will by default get the form, instantiate it, val using that same get form. So get and post use the same thing to instantiate it, and then the get form quarks is the one that actually handles whether or not there's data. Um and then it validates it and then returns self-valid or self-invalid or self-form invalid. And then so basically what we're saying, what those do is just return some type of response because we're in the post and we need to return some type of form response. Um so if you want to use it, you can easily subclass it and just set a form class and template name and you'd be set. I took it a step further here though and I was like I want to make a form that handles a get form or get submission. So I kind of limited the HTTP method names to get
and options. And so I need to do a little bit more now. So now on get, I check to see if it was a get submission. And if it was, I instantiate the form, validate it, and then return form is valid or form invalid. Um and then if not, it is cut off. But if not, I just return super, which will just render the form on the template brand new. And so another change is on get form quarks. So earlier I didn't show get form quarks because it's pretty simple. All it kind of does is set up like initial prefix. and data. But like I mentioned, it only does data for post submissions. So the reason we need to change it here is just to be able to set data from a get submission. So here we check, hey, was it a get
submission? If so, let's set it in the quarks and then return that. Um and then the final thing that we need to do is just set up what happens on Form Valid. You don't really need to do it here. You could also just set a success URL. But here what I would do is because I want to redirect based on the actual form data, I just define form valid and pull the form data out and redirect accordingly. Okay, so CreateView. CreateView is well actually I already showed you CreateView. But um CreateView, as I showed you earlier, is a really simple way of just creating new model instances. This actually does have an example of a mix-in that was made up of other mix-ins. So s single object template response mix-in
took another mix-in, did stuff to it, and let us add a functionality. Yeah. Okay, so update view is really similar to create view. Honestly, it is so similar that I'm not gonna show you an example of using it because it's basically the same thing. The only difference is it just on the first pass-through will instantiate the form with the instance that you're working with. So it's pretty neat, but Simple. Uh delete view. So this is the last generic view that I'm gonna go over. And so this one is actually interestingly more like detail view than create or update view in that uh it will Uh sub it's sub actually you can see down here it subclasses base
detail view at one point. Um and all it does is add a post handler for deleting the instance. Um Yeah. Uh one weird thing about it is the fact that it does it on post though, not delete. It yeah. Um yeah, so there's a lot more. There uh it it can be kind of hard to keep track of everything that they do. Um one uh term that I heard recently to describe them was ravioli code, uh in that you know that they're good. Um they are they can be really great, but you don't really know what's in them until you go and dig in there. Uh from the outside it's just like this is a nice nice little neat package that provides something for me.
Um so to that end there's this website called And it's really neat. It like lays out all the uh class-based views that Django provides and you can see easy examples of how um how everything got put together. So like it'll show you Let's see. Okay. I was supposed to do screenshots, but I didn't do the screenshots and let's see if this actually works. If not, I'll just go back to the presentation. Uh I can't zoom in though, because I can't see anything. Control plus. Uh okay. Oh there we go. Okay. Okay, zoomed in a little bit too much.
But yeah, so you it defines all of the views. And so for example, you can go to list view. Did I actually click? I did. Cool. And it tells you where they came from. So like it'll show you all the attributes and show you, hey, this attribute came from this mix-in or this view. And then if you scroll farther down, it'll show you all the methods. and tell you where those came from. So like on the side you can see. And then if there's one that came from multiple, it'll show you like what each of those defined. So um it's a really useful site. I honestly have it open all the time when I'm working with class-based use because I forget what class-based use defined things or like how things flow exactly. So it's really useful.
Um yeah. Oh man. What did I do? Hang on. Shouldn't have done that, I guess. This is why people told me to not do that. Mmm , spark There we go. Okay, cool. We'll back. Probably. Okay. So you might be asking yourself, all right, you showed me tons of views, and there are many more. Like I said, I didn't go through I probably went through like maybe a third of them.
So there's tons of them. Which one should I use? Um and so some guidelines that I kind of try to follow is that if there's one that basically does everything that you need, so like create view did everything I needed for my perp for that example Just use it. I mean, why would you want to go define the code that does the exact same thing? Um and then if later your needs change and you need to do more, then you can just change it out. It's not like you invested that much in just Using it and sending a few attributes. Um and then uh if you're uh oh I think I deleted Oh, okay. I switched the slide order eggs accidentally. Okay. Um so
If there are if there's one that you just need to extend and override a few parts, so like for example, my list view, I wanted to filter the query set, but that was just one method that I had to override and even then it wasn't even that much code that I of that I changed on there, then just use that. Um it's more when you get into like when you start overriding a lot of stuff that it kind of becomes Ugh, it it it kind of ruins the point of using a generic view and it gets really hard to keep track of what you're use what you're doing uh because you're kind of overriding this bit over here and then this bit over here and it's like wait but how do those two interact now And so keeping track of all that is a mess. So what I would say at that point is just use view or template view because those like view is just setting you up to be able to use class-based views. And template view is a j
it is a generic view, but it's a very basic generic view that just kind of provides some template loading functionality. So let's say start with those and build your way up. I actually know people that hate most generic class-based views, but they like class-based views in general, like the ideal of them of the idea of them. So they use view or template view as their base class every time and then just write everything else their on their own. Okay, um creating your own view. So I'm gonna go through this a little bit fast because I only have a few minutes left. Um No yeah. Okay. So why should you make one? So this kind of it Mixins, oh clicking on something. Okay, mixins kind of provide all the
encapsulates some of the logic that you need to repeat across reviews. And so that's kind of the same reason why you would want to Make use class-based views so that you can take advantage of those mix-ins. Especially you can take advantage of the pre-existing mix-ins, but you can also make your own mix-ins if you need to repeat something across All of your views. So for example, you have like an authorization type thing that you want to use in all your views. One way to do that is make a mix-in and then just add it to all your views. Um and that handles it pretty easily. So creating your own. I would say that if you you you can create like a base view if you find yourself using the same thing over and over again. And if you you can either create a base view or you can create a mix-in.
It kind of depends on what you're doing. So like if you're doing the same, like everything of that view is basically the same, you're just setting a few different attributes, then yeah, create a class base view that's like a base class ACU for you. If you are doing more like I was mentioning the authorization bit where it's just a bit of added functionality on top of everything else you're doing that's different in each view, then do a mix-in. Um I have so when I first started, um I had to deal a lot with pages where My users wanted to have like six or seven forms on the page. And um at the time it was really annoying that any every view I was defining every time like how to handle all those forms, especially because like the forms themselves
were kind of they were different but they were handled similarly. So I was like, you know what? I'm going to write a class-based view that handles multiple form submissions. Like rendering multiple forms and handles multiple form submissions And uh it worked. It worked great for me. Like I was like, oh, this is amazing. All I have to do is like set a few attributes and it works. But then like six months later I I had to go back to it and I was like, what am I even reading? Like I don't understand what I did. Like I was tra I needed I needed to add another form and like take out one of the previous forms and it was just a mess. I it was so hard to read. Um someone else had to then go back a after me and do the same thing and they also like We're like, I don't know what this happening.
I'm just gonna like cut in right here and kind of stick my code in. And it works now, kind of, but not really. Um so Make sure that if you are going to create your own base classes, uh you do think it think it through, make sure that you're not doing anything too complex in your base classes because If you're doing a lot of complex logic, you might it might be better to just handle it in that specific view and save everything else in your code base from it. Or, you know, break it up into like separate views. It's not like you have to do all of that in one view. Um I am not going to show the code because it is very long and a mess and getting it to show properly on here would be horrible. But it is in that repo, in case you're curious.
Um if you want to go read it. It it I have a lot of documentation on it, which Was good I guess because I could then figure it out, but I had to sit for like half an hour to figure out how to add a new form. Okay. So an example of a possibly good class-based view to do is uh one thing we do a lot is we have a lot of cases where our users need to search through a bunch of our data and then like list out a bunch of attributes for that data, but then they might not need to keep filtering the list. Um and so we actually decided to create a combination of like a form view and a list view because we found that we were either starting with form view and adding all the functionality that list view added or starting with list view and adding all the form view functionality. So we created a class that does that And that is also
linked in here. I'm also not going to show it because it's it's not it 's much simpler and cleaner than the other view, but it's still wordier than what I would be nice to show on these screens. Okay. So just really quick to cut to kind of finish up. We covered intro to class-based views, so I kind of explained how we got to where we are. And I like I said I linked the article if you're inter interesting it interested in reading more in detail what happened. Um I went over some pros and cons. I went over the internals, uh which was a little bit I mean I guess it's the intention of today, right? Deep dive. But I yeah, if you have any questions about that, you can ask me later. And then I talked about some of the generic views that I think are pretty useful
and At least they can be really useful, so if you find uses, you might as well stick them in. Um I have a bunch of resources. And Uh one thing before I finish. Uh there are more slides actually. My talk was really long. I can talk for a really long time. So I actually have a few more slides on like mixins and decorators. So if you're curious, you can look at the at those slides later. Which are like, you know, just going past the end of the current end. Just wanted to let you know. So if you want to look at those. But um but yeah, so that's it for me. Thank you, everyone.
Call the class’s `as_view()` method in `urls.py` rather than instantiating the class. `as_view()` builds a callable function that accepts the request and returns the response expected by Django’s URL resolver.
Discussed at 8:54Generic class-based views encapsulate common CRUD logic—such as creating model instances, rendering forms, validating submissions, saving, and redirecting—so you avoid repeating the same code. They can also be subclassed and customized when your needs differ slightly.
Discussed at 11:05Function-based views have explicit, easy-to-follow control flow and straightforward decorators, but they are harder to extend and typically handle HTTP methods with conditionals. Class-based views provide reusable generic views, method-based HTTP handling, inheritance, and mixins, but their control flow is more implicit and decorators require extra care.
Discussed at 11:57It creates a function-based wrapper, instantiates the view for each request, runs setup, and delegates handling to `dispatch()`. It also copies useful metadata and decorator-related attributes onto the wrapper before returning it.
Discussed at 15:51It checks whether the request method is allowed and whether the view defines a handler such as `get()` or `post()`. If not, it returns HTTP 405; otherwise, it calls the handler and returns its response.
Discussed at 21:26Mixins package small pieces of functionality that can be combined through inheritance. For example, `ContextMixin` supplies template context and `TemplateResponseMixin` renders a template, while `TemplateView` combines them with the base view and connects those pieces in its `get()` method.
Discussed at 23:44Override `get_queryset()`, call `super()` to obtain the normal queryset, inspect the URL arguments stored on the view, and apply a filter when the relevant search value is present. Otherwise, return the original queryset.
Discussed at 30:29The URL captures an identifier, conventionally named `pk`, and passes it to the view as a keyword argument. `DetailView` uses that value to retrieve the object; the argument name can be changed by setting the appropriate URL-kwarg attribute.
Discussed at 31:41Use a generic view when it already does what you need, or when you only need to override a small part such as `get_queryset()`. If you are overriding many pieces and the behavior becomes difficult to follow, start with `View` or `TemplateView` instead.
Discussed at 41:35Note: We understand that names change, people change, and bodies change. We respect each individual's journey and privacy. If you have any concerns about a video or need us to remove content, please don't hesitate to contact us. We will handle your request with care and promptly address any issues.
Published July 15, 2026
Published July 15, 2026
Published July 15, 2026
Published July 15, 2026
Published July 15, 2026
Published July 14, 2026