Django Views: Functions, Classes, and Generics
Pinkham, Andrew
The goal of this talk is to make views and HTTP as clear as daylight. This talk is for you if you're confused about: how function views compare to class-based views when to use generic class-based views- the difference between class-based views and generic class-based views- or when to use any of these This talk will start with an introduction to HTTP and how Django handles HTTP. We will then look at each kind of view in Django, focusing on how each works and why Django implements it that way. This will allow us to look at the advantages and shortcomings of each type of view. Finally, with a full understanding of Django views, we will be able to easily determine when to use each type of view. Table of Contents: What is HTTP, anyway? Django's HTTP Request/Response Cycle What is a callable? History of View Functions Functions Generics Classes and Generics View Functions (or How I Learned to Stop Worrying and Love Non-Compliance) Class Based Views (or As DRY as the Sahara) Generic Class Based Views (or Oh For The Love of Graph Theory) Enhancing Views (or 1-Size fits no-one) Fixing Your Views When to Use What
 So, as just mentioned, my name is Andrew. I'm a freelance software consultant and also a technical instructor. I teach Django in corporate and startup settings. I have a class coming up at the end of September, which I'll come back to, because perhaps most interestingly, as I also mentioned, I'm the author of Django Unleashed. The book is currently available for pre-order on Amazon. And Pearson is hedging their bets. They're saying that it's going to ship in December. We sort of expected to actually ship at the very end of November, but you didn't hear that from me. So the goal for today is to make it to that by the end of this talk, if you currently can't answer some of these questions, I want to make it so that you look at these questions and you go, oh, you know what? I got this. I know exactly how to answer these questions. And so the goal is to make it really easy to get through all of these. We'll actually come back to the questions themselves. The talk itself is split into three totally unequal parts. We're going to start at the very beginning with the largest section, and it's essentially trying to define the problem and understand the high-level concepts that allow for the solution. We're then going to actually examine the solutions, possible solutions, and see how to interact with them. And then finally, the smallest section is going to be a little bit about the tools that might help you ease the solution process. The fundamentals, right, the problem solution, we're going to look at Python callables. We're going to examine HTTP. And this is going to allow us to step back and look at Django views from a very high-level perspective. Then we'll actually look at views. We'll start with a little bit of a history. And then we'll look at each type of view available in Django at the moment. And finally, we will enhance. We'll look at a couple options that might be useful depending on what your choices are. I typically like to provide slides and code, and eventually I will sit down and write an article with all of this and based on feedback. And so you can find all of that material at this link. Currently, the slides are up online, so if you want to follow along, you can do that. And all of the code that will be appearing, including an IPython notebook, which you can fool around with, is currently posted on GitHub. So we're going to dive straight into it. Let's talk about Python callables. We're used to seeing Python callables all the time, right? The function is sort of the most basic. It takes an input. It gives you output. This might seem like, OK, Andrew, why are you talking about this? This is really, really basic, but I want to make sure we're all on the same page for maybe some of the more advanced stuff. Python comes with anonymous functions, which allows you to sort of define them on the fly. They're interesting, but not really the point here. It should come as no surprise. That methods are also callables, right? A method takes input and it provides output. Maybe a little more surprisingly, however, is the fact that you can see that when I instantiate the class, I'm calling the class. And that is, in fact, I am calling it. It makes it a callable. So some people in the room will go, oh, yes, well, of course, there's the Dunder and Knit method, and we use that to make it so that a class is called. That's where we control initialization. Yes. It turns out that if you look at the Python C code, it's a little bit more complicated than that. But that is, in fact, yes, what makes a class callable. And you'll say, great, so we have functions and we have methods. And actually, it turns out we can also make it so that on top of functions, methods, and classes, you can make objects callable with the Dunder callable method. So what that means is that you have virtually everything in Python that can be a callable given certain requirements. And you can see here, I simply ask Python, hey, can I call this? So now that we all are really, really clear on what a callable is, we can move into the rest of the talk. And we're going to start with HTTP. You've surely seen books about this, articles about this, presentations about this. And we could sort of start when we go, yes, well, it stands for this. It defines how a client and a server communicate. The client will issue a request method. The server does whatever it needs to. And the server is going to return a response. And at that point, we could begin to talk about the different methods available. And we could go through and we outline all the ones that are important. We can then get into a real battle about post and put and the meaning of item potent methods. And I can stand up here and I can really go through this and ye shall not and whatever goes but that really misses the point for us. And the point is this, your website must adhere to HTTP. When you are building a website, the problem you are trying to solve is adherence to HTTP, right? So if I go and build a server and I have the following request methods and then I define the following response codes, not only will my web server not work but I have created a monster and you really need to pull me aside and have a word with me. So I'm going to really emphasize the fact that when you are building a website, your goal first and foremost is to adhere to HTTP. Now I'm also going to assert a little more baselessly that the goal of all software is to solve a problem or to automate behavior. And I admit, look, sometimes it's really not clear which of the two things that's doing. But I'm still going to tell you yes, I am absolutely correct on this. You will take my word for it. That means that in the context of HTTP and Django, HTTP is the central problem that any web framework must solve, right? Everything else is a nicety, it's there to help you but as a website is defined as just something that adheres to the HTTP spec, then that is the first problem it must fix. And it also means that you're the behavior it's automating. It's trying to make it so that you have to do the least amount of work possible to adhere to this, which allows us to move directly into Django. I don't know how many people here have not done the Django tutorial. Who here is really just getting started? Okay. So I'm glad to see that. I just want to talk real quick about what a view is. When you do the tutorial, you're going to see that there's some text that says a view is a type of web page. Russell Keith McGee two years ago at DjangoCon said views are for displaying content. I'm going to go so far as to say that it's dynamic generation of content, right? The Washington Post is a collection of web pages. Some of these web pages are similar, right? There are a whole bunch of articles on the website and they all meet the following structure, right? The articles are all the same thing. And so you typically, if you were building this in Django, would have a view for the articles, right? It becomes a type of web page. So you have your user show up and what's going to happen is they're going to, is that, oh yes, they're going to issue an HTTP request. Your website's going to compute and it's going to get a response back. This is how every website works and we're interested in the internals. In Django, you're going to start by building Django models. You might go ahead and build forms. Oh yes, you generate the database based on the models. You're then going to go ahead and make template files and which allows you to build the views. If your website's really complicated, you might have middleware and context processors at which point you'll then load Django. It will get you the following tools and you can now work with this. Your user is going to, just as before, issue an HTTP request. It goes through the middleware, gets into the dispatch. It will find a URL pattern and then find a view. The view might interact with a model. It might interact with forms and it might go and interact with the templates. It's then always going to return back to the user the opposite way through the middleware and then send it back data. You'll notice that in all of these cases, I said might because the truth of the matter is that this is the only thing that's really important. Everything else is simply a way to try and, I'm glad that got laughs, this is simply, this is the core of Django. This is the only thing that you would really need to be a web framework. Everything else is really useful, phenomenally helpful, but this is the heart of it. Before we go any further, I want to note that that was a simplification. That animation is nice, but it doesn't deal with all sorts of things. Please don't email me about the fact that it's wrong. I know it's wrong. Somewhat wrong, right? We're going to focus on this. In particular, we're going to focus on views. Now because views are so heavily tied to URL patterns, I'm going to have to deal with URL patterns a little bit. The entire goal is going to be to deal with views in the context of HTTP. This is the format of an HTTP method. This is what your server actually expects to receive when it comes in. We have these two systems and they are going to be looking at that request and trying to handle it. The first thing is the URL pattern is primarily interested in handling the path to the resource. It looks at the URL path and it goes, yep, I'm trying to figure out which view to call and maybe it will take that some information from the URL path and hand it to the view. Maybe not. But that means that the view is really interested in the HTTP method. There's nothing else in Django that's going to handle that for us. This allows us to come back to the original question, which is what is a view and we can look at it from a much more technical standpoint now. We accept an HTTP request object at which point we are going to, in the view, generate data based on the HTTP request method, any data that is coming along with the request, and any data that the URL dispatcher is taking from the URL pattern and then handing to our view. At which point the view will always, always, always return an HTTP response object. That should be ringing a few bells. Oh, look, it's, we have to accept and we have to return. The secret to views is that, whoops, the secret to views is that any Python callable can be a view, which sort of raises the question, why do we talk about functions and classes and generics? How do we limit it to this? Let's take a trip down memory lane. Back in 2005, when Django was nothing but a tarball, the official recommendation for building views was to use Django functions. We now know that that's not really because functions are sort of any sort of inherent part of Django, but simply they're the simplest form of Python callable. And so they were what made the most sense to use. Very quickly thereafter, people said, you know what would be great? We are constantly reprogramming all of these webpages again and again and again. Could we just put them in Django so that we can just use them straight out of the box? People said, yeah, sure, that sounds like a great idea. There's a problem with this, right? When you try and have extensible, or you have this behavior and you say, this is almost exactly what I want, right? This is almost exactly the behavior I want. It's just a little bit different. The difficulty there is that if you're using a function, functions are rigid, right? You can't sort of just dig in there and change a little thing. You have to use the function entirely or not at all. That sort of became a problem with the generic views. And they said, can we do this better? Oh, we can try and extend the number of parameters. We can do x, y, and z. And eventually they realized, oh, we're re-implementing object-oriented programming. Well, that's ridiculous. Why don't we simply use a class to instantiate objects that are views? This was a pretty successful idea, right? This is Alex Ganner saying, wow, this would be so useful. I'm sorry if that's not large enough. So useful to have, right? We'd be able to go ahead and just extend it. And so in 2008, Joseph Cochran's, I'm sorry if I'm mispronouncing that, went ahead and opened the ticket. And so the discussion became, well, we're going to fix generic views by allowing them to be extensible. But first, we actually need a class that is a view, right? We need to be able to instantiate just a simple object view. And so they said, well, what do we want for that? Oh, well, we need to make sure that when people are using it, it's really obvious how to use it. We need to make sure that it's extendable because that was sort of the original idea. And we need to make sure that it's thread safe. Turns out, that last one's really hard. And so it took until 2011 to really get it right, to really sit down and say, OK, we're going to work through the entire thing and get it right. And at which point, they released the class-based view along with the generic views. And this is sort of where we ran into a naming problem because we'd started with generic views. And it was obvious what those were, right? Like, oh, it's just behavior that's preprogrammed for us. And now we've introduced this class-based view, right? It's just a view that instantiates an object view, or it's a class that instantiates an object view, excuse me. And they said, well, we'll just add class-based in front of generic. Everyone will understand, right? There'll be no confusion there. Unfortunately, there was a lot of confusion. And there's sort of, there remains a lot of confusion. One of the ways I've started discussing it is to talk about class-based views as object views. Yes, there's a class, but the actual views are the objects that you're instantiating. And that helps a lot of people go, oh, yes, of course. And the other thing is that the main point of the generic views is not that they're class-based or objects. That's certainly incredibly useful for extending behavior and taking control, but that's really not the point. The point of the matter is that they're generic views. And that leaves us. The state of the pony, as of Django 1.3, oh, for all the beginners in the room, the state of the pony is a joke, a long-standing Django joke where we talk about people saying, no, you can't have that pony in terms of new Django features. And so you will regularly hear people say the state of the pony to refer to the state of Django. I did not think about that inside joke. Sorry about that. So we currently have three options, right? The function views simply because it's a callable, right? We can use any callable. And so naturally, you can use a function view. And then the object views or the class-based views are there and useful because they put three years of time into really making sure it was safe and usable. And so people don't create their own because it's a lot of work to do that. And why wouldn't I just use these? And then the generic views are simply preprogrammed views for you to use. And so not really in the same category. And that means that we can now move into looking at each one. So the function views, we now know, even though they're considered the original, it's simply that they follow what it means to be a view and they're callables, right? So we're going to begin by setting up a little project. This is a model. It's really uninspiring, but you get the point. It's got a name and a slug. Because I can't get away from building views without a URL pattern, I'm going to go ahead and build a URL pattern. It's going to call my view and it takes in a single parameter called the slug. This allows us to program this. And this is sort of your stereotypical view. For all of the beginners in the room, this is sort of how we think of views. I take in some data. I fetch something from the database. And then I return something via the template. This is not a great example, unfortunately, because it means that I'm using all of these other subsystems when I meant to just focus on one thing. And the only thing that really matters is you can see the first parameter I'm taking in is the request and the render is using that to return an HTTP response. And so the idea here is that we're doing that. Can anyone tell me what's missing from our stereotypical view? Does anyone see something that should maybe be in there? Feel free to actually shout this out, but I'm actually asking you a question. The method, yes. We haven't bothered to handle the HTTP method at all. It's not even in our code. There are many ways we can do this. It's fairly easy. I can just add an if condition and say, look, if it's the get method, do the following. And if it's not the get method, please return an HTTP response not allowed and tell them that the only thing we accept is the get method. This is horrible. You're not going to program this. Come on. That's not great. Thankfully, Django introduces the HTTP decorator. I'm not going to get that out. To help that. And so here we simply say, look, this view only accepts get and head. And everything else, it will return an HTTP 405 method on or return an HTTP response 405 error code. There we are. Turns out there's a shortcut for get and head called require safe. And so we can simply move that over. And at which point we can actually see all the changes to our code by using a tool called telnet. You can actually write the HTTP request directly in your command line if you're running a server. This is actually kind of fun, right? So I'm actually typing in get a path and it is returning this data to me. And I can see, oh, yeah, it expects that and it gives that stuff back to me. If I give it a method that is not expecting like options, it's going to say, nope, I have no idea what this is. I'm not programmed to handle this. And what I can tell you is that I can handle get and head. You can see it on the third line from the bottom. You'll notice that throughout this talk. I'm going to avoid post, even though it's commonly used because the CSRF middleware is going to get in the way and simply kind of interject itself and go, hi, by the way, you're not being secure. If you were to disable it, you would get a four or five error. Please don't disable it unless you really, really, really know what you're doing. We're going to go through and we're just going to create another view just to see a slightly different case. So here is just another URL pattern and here is a view and you'll go, oh, look, this is for handling forms and we say, oh, okay, so if it's a post, I behave a specific way and if it's not a post, you know, I expect to get and I behave a different way. That's like showing up at your 24 hour diner and 90% of the time, you're going to say, yes, I would like the scrambled eggs and you're going to, so people are going to ask for scrambled eggs 90% of the time and so you're just going to give them scrambled eggs. But you're also, for 10% of the time, giving the people who are asking for hamburger or the hash browns scrambled eggs. That's really frustrating and you're probably not going to do well with that crowd and so even though you're handling post, you're not actually handling any of the other HGP methods, right? You can see that it's, I sort of brought a laser and that's not working. You can see that the topmost condition there, the else, simply says else, doesn't check for any other HGP method and that's not so great. So even if you're partially handling the HGP method, you really do want to think about whether you're handling all of them and that's how you should deal with function views in Django. We can now turn to class based views and the key advantage to class based views is the fact that they're classes, you're dealing with object oriented programming and it's a really powerful way, not the only way, but a very powerful way to adhere to dry, which is don't repeat yourself in Python. So once again, we're going to convert the last two views that we built into class based views. I have to deal with the URL pattern. I can't go into, I don't have enough time to go into detail as to why I'm changing this. There's a lot of documentation and I cover this in great detail in my talk at DjangoCon 2013. The bottom line is you'll have to believe me for the moment that I have to make this change for this to work. We can then actually look at our code and the first thing I'm going to do is get rid of the decorator. It's gone. I don't need it. The next thing I'm going to do is change the name of this function to get and I'm going to add self in anticipation of having this as a class. I indent and I put it under a class. That is the only difference, right? It is exactly the same thing except it is now, it now has a class that it belongs to and is now a method. There is however a huge amount of beauty to this because it makes explicit the problem you are trying to solve. This code only works if an HTTP get method is used and everything else is not handled or rather will return to 405 error. Almost everything. As it turns out, class based views are kind of neat. If you give them a get method, they will automatically give you head method handling and it will also always give you option handling which is really, really cool and much better than what you are getting with the function views. The same thing is sort of similar when we come back to our form view and we say, oh, okay, well, we need to do a little bit more here because what we actually wanted was get and post and so we can go ahead and create two methods for the class based views and we are going to go ahead and define a bunch of attributes. The get method is completely uninteresting, right? I take input, I provide output to a page. The code is not really the point input output just the get method and with post, it is sort of the same thing. You can handle the form however you need to but the bottom line is that this is behavior that is defined only for the post method and of course you are getting options and head because of the way we built this. This is very different from what we had originally. One of the things that I found with beginners is if you look at this as a beginner, it is kind of a lot to take in. You go, well, there is an if condition but then there is a second if condition and there is this implicit return that has multiple behavior and when I ask people taking my class, how many behaviors do you think is in here? The answers I typically get are either two or four. When the truth, if you look here, is that there are three and that becomes much easier to see in this context. So CBVs, despite the fact that we say, or class-based views, despite the fact that we say are more complicated and take a little bit more code, can actually be used in certain contexts in really interesting, very helpful ways. So part of this, if you are totally new, you may not know why I am defending these quite so much. There is a certain, when they were introduced because of the confusion around them, a lot of people said, well, they are not worth using at all or ever and so part of my position is wait, these are a tool and tools do have purposes and can be used in certain contexts as long as you understand what the tool does and when those contexts are. So I am just trying to provide when and the context. This allows us to sort of look at the odd view set in the game which are the generic class-based views and I am just going to dive right in because there is so much here and you can see that this is all of model detail now. I have completely removed the get method. It is nowhere. I am just sort of invocating this. And this feels awful because you are looking at this and you are like, well, wait, this is like a game of mad libs. How do I know what to fill in or how to fill it in? And this gets even worse with the model create. I have removed get and I have removed post but the attributes are exactly the same as they were before. And I mean, at least you have some small comfort in saying, well, it is exactly the way it worked before. Right, Andrew? No, it is not. No, and that is sort of the problem is suddenly on our new form we now have the put verb which has been instantiated. And you go, okay, well, hold on. Let me sit back and go through this. What does this look like? That is the actual graph of how all of the generic views are related. It is really kind of insane. And when I gave my talk at JangoCon 2013, this is the image that I presented. You feel, you take so much time going, oh, I have no idea what I am doing. I don't understand. The point really wasn't that it is a terrible idea because if you start using generic views, it turns you into a real powerhouse. I mean, you can become a super coder. You will leave websites in your wake. The problem is that you spend so much time doing stuff that doesn't make any sense to try and get there that it can be really frustrating. There are tools that are very helpful and we will come back to this one. But the idea here is that if you were a beginner, the idea was that by having these be classes, we would be able to go ahead and extend them. And by overcomplicating them, it has become a bit of a problem because beginners go, well, how do I extend them? How do I learn how to go about them? And unfortunately, my advice is that if you're a beginner, don't try and use them. If you see that there is a generic class-based view that does exactly what you want, use it. See how you just get it to do exactly what it was built for. If you then, once you've become comfortable with that, then begin to go, oh, okay, well, maybe I can begin to look at the methods. There's this thing that happens. You can see it on the mailing list. I see it a lot in my classes where people go, oh, I would like to use the following generic view to do X, Y, and Z. And the answer is always, well, yes, you can do that, but there are better options for how you can go about building that. I really thought that was going to get more laughs. Really, it's nice to see a little contingency over there. Okay. And so that's the thing, is that with generic views, yes, you can absolutely customize them to do whatever it is that you want, but maybe it's not always the best idea to do that. And unfortunately, the only way to figure that out is to get familiar with them, and that's sort of unfortunate. So now that we understand really how all of these work, how do we sort of tackle the problem of using and building views? For the function views and all of that jazz, I think it's fairly straightforward. I do want to take a quick look at classic class-based views, because last time I presented this, and the last few times I've given this, or similar talks, the most people go, wait, could you show the tool? How does this actually work? So you're going to show up on this website, and it's going to show you all of the generic views at the top level, and you can click on any of them. And so I'm going to click on Detail View, and it's going to show me all of the classes that are related that this view inherits, as well as it provides a link directly to the documentation. And below this, there are the attributes. These are all of the attributes that I can override, including their current defaults, so that I can see exactly what is going on. This is really where you want to start, right? If you decide, oh, I'm going to use a generic view, I'm going to go ahead and I'm going to try and figure out which attributes I need to define. Once you're comfortable with defining the attributes and going, OK, yeah, I can get that behavior by changing just attributes, you can begin to look at the methods, right? This is where you go, yep, totally comfortable with the attributes, but I need to just tweak this one thing. This allows you to see all of the methods that are being used. You'll typically want to start with the methods that the Class Base View uses, right? Get, post, put. So right here, I can just click on get and it will show me the implementation as well as tell me where it's actually defined, because it's not actually defined in detail view. If you look all the way to the right, you can see it's defined in base detail view. And so that's Class Base, they're Classy Class Base Views and sort of the go-to tool for trying to get through generic views. I'm also, when I was writing my book, when I was compiling my book, I found that I spent a lot of time writing decorators in Django to get it to do what I wanted. And I'm slowly going to be taking them and putting them out onto the internet. And so I've started a project called Django Decorator Plus. I'm a little burnt out from book writing to be perfectly honest with you. And so I haven't gotten as much work done on this. But I do have my replacement for the required decorator for function views, because I think it's silly that the Class Base Views gets you options and head out of the box, but that the decorator doesn't. So I fixed that, and I've gone ahead and recreated the decorator. These are two shortcuts for the decorator, and they're equivalent to just get and get posts. But again, I say get, but that's actually get head options, and get post is get post head options. So I'm hoping that that will provide the basis for adhering to HTTP methods or adhering to the HTTP spec in function views. Sorry, I keep getting distracted by the timer. Which brings us to our conclusion. We can come back to these questions that I was hoping you would find easy at this point, make hopefully these are sort of tacklable, if that's a word. So Django handles HTTP for me. Why do I need to worry about it? Well, as we now know, it doesn't handle it for you. It will translate the HTTP into a nice Python object, and allows you to manipulate all of that data and to easily use that in Python. But it's not handling it for you. You are still taking care in the URL patterns of the URL path to the resource. And in views, you really do want to be considering at all points what HTTP method is being used and how you react to it. Because otherwise, you're building an API that is only using part of the information, and some user on the other end is going to be really unhappy with you. Then is Django deprecating function views? It's not, right? The idea behind a view is, you know, accept specific input, provide specific output, and any callable can be that. And so function views are not anything inherent to Django, and they're not going anywhere. Aren't all class-based views generic? No. Hopefully, the walk-through history helps split the difference, right? The idea is we have generic views, and that is very much its own concept, and then we have object views, and that is very much its own concept. And we... There is some discussion about whether each one solves the problem it was designed to solve. And those are valid conversations to have, but it's difficult to have that conversation if people continue to confuse the two. Finally, how do I choose what kind of view to use? This is easily the hardest question on here, and I have a set of questions that I ask myself whenever I'm building a view. And the first is, is there a generic view that does exactly what I want or almost what I want, and can I simply plug into it? If yes, use a generic view, right? That's... You know, it's therefore just that. If there isn't, you're sort of left with the choice between a class-based view and a function-based view, but we now know that they're essentially equivalent. The only reason that you might want to use a class-based view is if you have behavior that is shared across multiple views, at which point using object-oriented programming is incredibly helpful, but if you don't, it's entirely up to your preference, right? You could use function views or class-based views. It doesn't really matter. Which brings me to sort of the key takeaways. The view is Django's solution to handling HTTP. All views are callable, or Python callables. Doesn't matter. Please use the require HTTP methods if you are using function methods, or at least consider how you're handling HTTP methods. And finally, please think of the two concepts of generic views and class-based views as very different, very separate. Thank you very much all for coming. I hope this was helpful. Again, all of the related material is at that first link. My book is currently available for pre-order, and it's currently discounted. Amazon is in charge of that, and they won't give me an answer as to whether the discount remains after or if that's simply a pre-order thing, but it's currently discounted. And finally, at the end of September, as I mentioned at the beginning of October, rather, I'm going to be teaching a class in Django locally. As a thank you for all coming to this, that is a promo code that you can use for 20% off. Questions? I'm also, if we're out of time, I'm happy to take questions in the hallway. I have 40 seconds. I'm sorry I cut this so close and that we started late. Are there any questions? And again, feel free to just grab me throughout the conference if you do at any point. I think there's a mic. Based on the flexibility of a class-based view, doesn't it, and the fact that it gives you all those methods to define kind of for free, doesn't it make sense to always use a class-based view over a function view because you'll need to deal with the other methods? It's sort of your, honestly, is really your preference because at that point, you know, it will get you head and options, but let's say that you're using the decorators from Decorator Plus, you get that same behavior in a function view for just calling return. And so there's really very little difference if it's really a very, very simple view. Is there possibly like a performance optimization overhead for, or performance hit for you? Or are you using a class method over a function view, a class view over a function view? There might be a small performance hit, but that's, I mean, that's not really where your performance problems are going to be, right? Typically your performance problems are going to be in IO. Okay. So. Cool. Thanks. No. Hi. So I'm wondering about, you know, let's say for example you have a model or an object of a model such as like a task and you know, you can perform different modifications on it, right? So I guess you would use like an update view or something like that as a class based view. If you wanted to modify it in different ways at different stages of time, do you have a recommendation on how you would do that? So like, you know, let's say at one point the task is unassigned and then you post that it's been assigned to a particular person. I'm thinking of, you know, a sort of simple ticketing system, right? Sure. And then the person updates it and so they post, you know, the status of it and then eventually it gets closed. Could you handle all of that in a single class or would you split it into different URLs? Do you have any thoughts on that? That depends entirely on how you want to handle it. You certainly could have a single edit view where you can change all of this, all of the fields on the model. You certainly could have multiple, right? You might just have one where you click on it and it immediately updates and changes a status flag. So it's sort of up to you. I may be misunderstanding the question though. I'm not super clear on all the details. I'm happy to talk about it afterwards. Thank you all very, very much for coming. I hope that was helpful. Feel free to grab me during the conference if you have any questions. Thank you again. Thank you.
 So, as just mentioned, my name is Andrew.  I'm a freelance software consultant and also a technical instructor.  I teach Django in corporate and startup settings.  I have a class coming up at the end of September, which I'll come back to, because perhaps most  interestingly, as I also mentioned, I'm the author of Django Unleashed.  The book is currently available for pre-order on Amazon.  And Pearson is hedging their bets.  They're saying that it's going to ship in December.  We sort of expected to actually ship at the very end of November, but you didn't hear  that from me.  So the goal for today is to make it to that by the end of this talk, if you currently  can't answer some of these questions, I want to make it so that you look at these questions  and you go, oh, you know what?  I got this.  I know exactly how to answer these questions.  And so the goal is to make it really easy to get through all of these.  We'll actually come back to the questions themselves.  The talk itself is split into three totally unequal parts.  We're going to start at the very beginning with the largest section, and it's essentially  trying to define the problem and understand the high-level concepts that allow for the  solution.  We're then going to actually examine the solutions, possible solutions, and see how to interact  with them.  And then finally, the smallest section is going to be a little bit about the tools that  might help you ease the solution process.  The fundamentals, right, the problem solution, we're going to look at Python callables.  We're going to examine HTTP.  And this is going to allow us to step back and look at Django views from a very high-level  perspective.  Then we'll actually look at views.  We'll start with a little bit of a history.  And then we'll look at each type of view available in Django at the moment.  And finally, we will enhance.  We'll look at a couple options that might be useful depending on what your choices are.  I typically like to provide slides and code, and eventually I will sit down and write an  article with all of this and based on feedback.  And so you can find all of that material at this link.  Currently, the slides are up online, so if you want to follow along, you can do that.  And all of the code that will be appearing, including an IPython notebook, which you can  fool around with, is currently posted on GitHub.  So we're going to dive straight into it.  Let's talk about Python callables.  We're used to seeing Python callables all the time, right?  The function is sort of the most basic.  It takes an input.  It gives you output.  This might seem like, OK, Andrew, why are you talking about this?  This is really, really basic, but I want to make sure we're all on the same page for maybe  some of the more advanced stuff.  Python comes with anonymous functions, which allows you to sort of define them on the fly.  They're interesting, but not really the point here.  It should come as no surprise.  That methods are also callables, right?  A method takes input and it provides output.  Maybe a little more surprisingly, however, is the fact that you can see that when I instantiate  the class, I'm calling the class.  And that is, in fact, I am calling it.  It makes it a callable.  So some people in the room will go, oh, yes, well, of course, there's the Dunder and Knit  method, and we use that to make it so that a class is called.  That's where we control initialization.  Yes.  It turns out that if you look at the Python C code, it's a little bit more complicated  than that.  But that is, in fact, yes, what makes a class callable.  And you'll say, great, so we have functions and we have methods.  And actually, it turns out we can also make it so that on top of functions, methods, and  classes, you can make objects callable with the Dunder callable method.  So what that means is that you have virtually everything in Python that can be a callable  given certain requirements.  And you can see here, I simply ask Python, hey, can I call this?  So now that we all are really, really clear on what a callable is, we can move into the  rest of the talk.  And we're going to start with HTTP.  You've surely seen books about this, articles about this, presentations about this.  And we could sort of start when we go, yes, well, it stands for this.  It defines how a client and a server communicate.  The client will issue a request method.  The server does whatever it needs to.  And the server is going to return a response.  And at that point, we could begin to talk about the different methods available.  And we could go through and we outline all the ones that are important.  We can then get into a real battle about post and put and the meaning of item potent methods.  And I can stand up here and I can really go through this and ye shall not and whatever  goes but that really misses the point for us.  And the point is this, your website must adhere to HTTP.  When you are building a website, the problem you are trying to solve is adherence to HTTP,  right?  So if I go and build a server and I have the following request methods and then I define  the following response codes, not only will my web server not work but I have created  a monster and you really need to pull me aside and have a word with me.  So I'm going to really emphasize the fact that when you are building a website, your  goal first and foremost is to adhere to HTTP.  Now I'm also going to assert a little more baselessly that the goal of all software is  to solve a problem or to automate behavior.  And I admit, look, sometimes it's really not clear which of the two things that's doing.  But I'm still going to tell you yes, I am absolutely correct on this.  You will take my word for it.  That means that in the context of HTTP and Django, HTTP is the central problem that any  web framework must solve, right?  Everything else is a nicety, it's there to help you but as a website is defined as just  something that adheres to the HTTP spec, then that is the first problem it must fix.  And it also means that you're the behavior it's automating.  It's trying to make it so that you have to do the least amount of work possible to adhere  to this, which allows us to move directly into Django.  I don't know how many people here have not done the Django tutorial.  Who here is really just getting started?  Okay.  So I'm glad to see that.  I just want to talk real quick about what a view is.  When you do the tutorial, you're going to see that there's some text that says a view  is a type of web page.  Russell Keith McGee two years ago at DjangoCon said views are for displaying content.  I'm going to go so far as to say that it's dynamic generation of content, right?  The Washington Post is a collection of web pages.  Some of these web pages are similar, right?  There are a whole bunch of articles on the website and they all meet the following structure,  right?  The articles are all the same thing.  And so you typically, if you were building this in Django, would have a view for the  articles, right?  It becomes a type of web page.  So you have your user show up and what's going to happen is they're going to, is that, oh  yes, they're going to issue an HTTP request.  Your website's going to compute and it's going to get a response back.  This is how every website works and we're interested in the internals.  In Django, you're going to start by building Django models.  You might go ahead and build forms.  Oh yes, you generate the database based on the models.  You're then going to go ahead and make template files and which allows you to build the views.  If your website's really complicated, you might have middleware and context processors  at which point you'll then load Django.  It will get you the following tools and you can now work with this.  Your user is going to, just as before, issue an HTTP request.  It goes through the middleware, gets into the dispatch.  It will find a URL pattern and then find a view.  The view might interact with a model.  It might interact with forms and it might go and interact with the templates.  It's then always going to return back to the user the opposite way through the middleware  and then send it back data.  You'll notice that in all of these cases, I said might because the truth of the matter  is that this is the only thing that's really important.  Everything else is simply a way to try and, I'm glad that got laughs, this is simply, this  is the core of Django.  This is the only thing that you would really need to be a web framework.  Everything else is really useful, phenomenally helpful, but this is the heart of it.  Before we go any further, I want to note that that was a simplification.  That animation is nice, but it doesn't deal with all sorts of things.  Please don't email me about the fact that it's wrong.  I know it's wrong.  Somewhat wrong, right?  We're going to focus on this.  In particular, we're going to focus on views.  Now because views are so heavily tied to URL patterns, I'm going to have to deal with URL  patterns a little bit.  The entire goal is going to be to deal with views in the context of HTTP.  This is the format of an HTTP method.  This is what your server actually expects to receive when it comes in.  We have these two systems and they are going to be looking at that request and trying to  handle it.  The first thing is the URL pattern is primarily interested in handling the path to the resource.  It looks at the URL path and it goes, yep, I'm trying to figure out which view to call  and maybe it will take that some information from the URL path and hand it to the view.  Maybe not.  But that means that the view is really interested in the HTTP method.  There's nothing else in Django that's going to handle that for us.  This allows us to come back to the original question, which is what is a view and we can  look at it from a much more technical standpoint now.  We accept an HTTP request object at which point we are going to, in the view, generate  data based on the HTTP request method, any data that is coming along with the request,  and any data that the URL dispatcher is taking from the URL pattern and then handing to our  view.  At which point the view will always, always, always return an HTTP response object.  That should be ringing a few bells.  Oh, look, it's, we have to accept and we have to return.  The secret to views is that, whoops, the secret to views is that any Python callable can be  a view, which sort of raises the question, why do we talk about functions and classes  and generics?  How do we limit it to this?  Let's take a trip down memory lane.  Back in 2005, when Django was nothing but a tarball, the official recommendation for  building views was to use Django functions.  We now know that that's not really because functions are sort of any sort of inherent  part of Django, but simply they're the simplest form of Python callable.  And so they were what made the most sense to use.  Very quickly thereafter, people said, you know what would be great?  We are constantly reprogramming all of these webpages again and again and again.  Could we just put them in Django so that we can just use them straight out of the box?  People said, yeah, sure, that sounds like a great idea.  There's a problem with this, right?  When you try and have extensible, or you have this behavior and you say, this is almost  exactly what I want, right?  This is almost exactly the behavior I want.  It's just a little bit different.  The difficulty there is that if you're using a function, functions are rigid, right?  You can't sort of just dig in there and change a little thing.  You have to use the function entirely or not at all.  That sort of became a problem with the generic views.  And they said, can we do this better?  Oh, we can try and extend the number of parameters.  We can do x, y, and z.  And eventually they realized, oh, we're re-implementing object-oriented programming.  Well, that's ridiculous.  Why don't we simply use a class to instantiate objects that are views?  This was a pretty successful idea, right?  This is Alex Ganner saying, wow, this would be so useful.  I'm sorry if that's not large enough.  So useful to have, right?  We'd be able to go ahead and just extend it.  And so in 2008, Joseph Cochran's, I'm sorry if I'm mispronouncing that, went ahead and  opened the ticket.  And so the discussion became, well, we're going to fix generic views by allowing them  to be extensible.  But first, we actually need a class that is a view, right?  We need to be able to instantiate just a simple object view.  And so they said, well, what do we want for that?  Oh, well, we need to make sure that when people are using it, it's really obvious how to use  it.  We need to make sure that it's extendable because that was sort of the original idea.  And we need to make sure that it's thread safe.  Turns out, that last one's really hard.  And so it took until 2011 to really get it right, to really sit down and say, OK, we're  going to work through the entire thing and get it right.  And at which point, they released the class-based view along with the generic views.  And this is sort of where we ran into a naming problem because we'd started with generic views.  And it was obvious what those were, right?  Like, oh, it's just behavior that's preprogrammed for us.  And now we've introduced this class-based view, right?  It's just a view that instantiates an object view, or it's a class that instantiates an  object view, excuse me.  And they said, well, we'll just add class-based in front of generic.  Everyone will understand, right?  There'll be no confusion there.  Unfortunately, there was a lot of confusion.  And there's sort of, there remains a lot of confusion.  One of the ways I've started discussing it is to talk about class-based views as object  views.  Yes, there's a class, but the actual views are the objects that you're instantiating.  And that helps a lot of people go, oh, yes, of course.  And the other thing is that the main point of the generic views is not that they're class-based  or objects.  That's certainly incredibly useful for extending behavior and taking control, but that's really  not the point.  The point of the matter is that they're generic views.  And that leaves us.  The state of the pony, as of Django 1.3, oh, for all the beginners in the room, the state  of the pony is a joke, a long-standing Django joke where we talk about people saying, no,  you can't have that pony in terms of new Django features.  And so you will regularly hear people say the state of the pony to refer to the state  of Django.  I did not think about that inside joke.  Sorry about that.  So we currently have three options, right?  The function views simply because it's a callable, right?  We can use any callable.  And so naturally, you can use a function view.  And then the object views or the class-based views are there and useful because they put  three years of time into really making sure it was safe and usable.  And so people don't create their own because it's a lot of work to do that.  And why wouldn't I just use these?  And then the generic views are simply preprogrammed views for you to use.  And so not really in the same category.  And that means that we can now move into looking at each one.  So the function views, we now know, even though they're considered the original, it's simply  that they follow what it means to be a view and they're callables, right?  So we're going to begin by setting up a little project.  This is a model.  It's really uninspiring, but you get the point.  It's got a name and a slug.  Because I can't get away from building views without a URL pattern, I'm going to go ahead  and build a URL pattern.  It's going to call my view and it takes in a single parameter called the slug.  This allows us to program this.  And this is sort of your stereotypical view.  For all of the beginners in the room, this is sort of how we think of views.  I take in some data.  I fetch something from the database.  And then I return something via the template.  This is not a great example, unfortunately, because it means that I'm using all of these  other subsystems when I meant to just focus on one thing.  And the only thing that really matters is you can see the first parameter I'm taking  in is the request and the render is using that to return an HTTP response.  And so the idea here is that we're doing that.  Can anyone tell me what's missing from our stereotypical view?  Does anyone see something that should maybe be in there?  Feel free to actually shout this out, but I'm actually asking you a question.  The method, yes.  We haven't bothered to handle the HTTP method at all.  It's not even in our code.  There are many ways we can do this.  It's fairly easy.  I can just add an if condition and say, look, if it's the get method, do the following.  And if it's not the get method, please return an HTTP response not allowed and tell them  that the only thing we accept is the get method.  This is horrible.  You're not going to program this.  Come on.  That's not great.  Thankfully, Django introduces the HTTP decorator.  I'm not going to get that out.  To help that.  And so here we simply say, look, this view only accepts get and head.  And everything else, it will return an HTTP 405 method on or return an HTTP response 405  error code.  There we are.  Turns out there's a shortcut for get and head called require safe.  And so we can simply move that over.  And at which point we can actually see all the changes to our code by using a tool called  telnet.  You can actually write the HTTP request directly in your command line if you're running a server.  This is actually kind of fun, right?  So I'm actually typing in get a path and it is returning this data to me.  And I can see, oh, yeah, it expects that and it gives that stuff back to me.  If I give it a method that is not expecting like options, it's going to say, nope, I have  no idea what this is.  I'm not programmed to handle this.  And what I can tell you is that I can handle get and head.  You can see it on the third line from the bottom.  You'll notice that throughout this talk.  I'm going to avoid post, even though it's commonly used because the CSRF middleware is  going to get in the way and simply kind of interject itself and go, hi, by the way, you're  not being secure.  If you were to disable it, you would get a four or five error.  Please don't disable it unless you really, really, really know what you're doing.  We're going to go through and we're just going to create another view just to see a slightly  different case.  So here is just another URL pattern and here is a view and you'll go, oh, look, this is  for handling forms and we say, oh, okay, so if it's a post, I behave a specific way and  if it's not a post, you know, I expect to get and I behave a different way.  That's like showing up at your 24 hour diner and 90% of the time, you're going to say,  yes, I would like the scrambled eggs and you're going to, so people are going to ask for scrambled  eggs 90% of the time and so you're just going to give them scrambled eggs.  But you're also, for 10% of the time, giving the people who are asking for hamburger or  the hash browns scrambled eggs.  That's really frustrating and you're probably not going to do well with that crowd and so  even though you're handling post, you're not actually handling any of the other HGP methods,  right?  You can see that it's, I sort of brought a laser and that's not working.  You can see that the topmost condition there, the else, simply says else, doesn't check  for any other HGP method and that's not so great.  So even if you're partially handling the HGP method, you really do want to think about  whether you're handling all of them and that's how you should deal with function views in  Django.  We can now turn to class based views and the key advantage to class based views is the  fact that they're classes, you're dealing with object oriented programming and it's  a really powerful way, not the only way, but a very powerful way to adhere to dry, which  is don't repeat yourself in Python.  So once again, we're going to convert the last two views that we built into class based  views.  I have to deal with the URL pattern.  I can't go into, I don't have enough time to go into detail as to why I'm changing this.  There's a lot of documentation and I cover this in great detail in my talk at DjangoCon  2013.  The bottom line is you'll have to believe me for the moment that I have to make this  change for this to work.  We can then actually look at our code and the first thing I'm going to do is get rid  of the decorator.  It's gone.  I don't need it.  The next thing I'm going to do is change the name of this function to get and I'm going  to add self in anticipation of having this as a class.  I indent and I put it under a class.  That is the only difference, right?  It is exactly the same thing except it is now, it now has a class that it belongs to  and is now a method.  There is however a huge amount of beauty to this because it makes explicit the problem  you are trying to solve.  This code only works if an HTTP get method is used and everything else is not handled  or rather will return to 405 error.  Almost everything.  As it turns out, class based views are kind of neat.  If you give them a get method, they will automatically give you head method handling and it will  also always give you option handling which is really, really cool and much better than  what you are getting with the function views.  The same thing is sort of similar when we come back to our form view and we say, oh,  okay, well, we need to do a little bit more here because what we actually wanted was get  and post and so we can go ahead and create two methods for the class based views and  we are going to go ahead and define a bunch of attributes.  The get method is completely uninteresting, right?  I take input, I provide output to a page.  The code is not really the point input output just the get method and with post, it is sort  of the same thing.  You can handle the form however you need to but the bottom line is that this is behavior  that is defined only for the post method and of course you are getting options and head  because of the way we built this.  This is very different from what we had originally.  One of the things that I found with beginners is if you look at this as a beginner, it is  kind of a lot to take in.  You go, well, there is an if condition but then there is a second if condition and there  is this implicit return that has multiple behavior and when I ask people taking my class,  how many behaviors do you think is in here?  The answers I typically get are either two or four.  When the truth, if you look here, is that there are three and that becomes much easier  to see in this context.  So CBVs, despite the fact that we say, or class-based views, despite the fact that we say are more  complicated and take a little bit more code, can actually be used in certain contexts in  really interesting, very helpful ways.  So part of this, if you are totally new, you may not know why I am defending these quite  so much.  There is a certain, when they were introduced because of the confusion around them, a lot  of people said, well, they are not worth using at all or ever and so part of my position  is wait, these are a tool and tools do have purposes and can be used in certain contexts  as long as you understand what the tool does and when those contexts are.  So I am just trying to provide when and the context.  This allows us to sort of look at the odd view set in the game which are the generic  class-based views and I am just going to dive right in because there is so much here and  you can see that this is all of model detail now.  I have completely removed the get method.  It is nowhere.  I am just sort of invocating this.  And this feels awful because you are looking at this and you are like, well, wait, this  is like a game of mad libs.  How do I know what to fill in or how to fill it in?  And this gets even worse with the model create.  I have removed get and I have removed post but the attributes are exactly the same as  they were before.  And I mean, at least you have some small comfort in saying, well, it is exactly the way it  worked before.  Right, Andrew?  No, it is not.  No, and that is sort of the problem is suddenly on our new form we now have the put verb which  has been instantiated.  And you go, okay, well, hold on.  Let me sit back and go through this.  What does this look like?  That is the actual graph of how all of the generic views are related.  It is really kind of insane.  And when I gave my talk at JangoCon 2013, this is the image that I presented.  You feel, you take so much time going, oh, I have no idea what I am doing.  I don't understand.  The point really wasn't that it is a terrible idea because if you start using generic views,  it turns you into a real powerhouse.  I mean, you can become a super coder.  You will leave websites in your wake.  The problem is that you spend so much time doing stuff that doesn't make any sense to  try and get there that it can be really frustrating.  There are tools that are very helpful and we will come back to this one.  But the idea here is that if you were a beginner, the idea was that by having these be classes,  we would be able to go ahead and extend them.  And by overcomplicating them, it has become a bit of a problem because beginners go, well,  how do I extend them?  How do I learn how to go about them?  And unfortunately, my advice is that if you're a beginner, don't try and use them.  If you see that there is a generic class-based view that does exactly what you want, use  it.  See how you just get it to do exactly what it was built for.  If you then, once you've become comfortable with that, then begin to go, oh, okay, well,  maybe I can begin to look at the methods.  There's this thing that happens.  You can see it on the mailing list.  I see it a lot in my classes where people go, oh, I would like to use the following generic  view to do X, Y, and Z.  And the answer is always, well, yes, you can do that, but there are better options for  how you can go about building that.  I really thought that was going to get more laughs.  Really, it's nice to see a little contingency over there.  Okay.  And so that's the thing, is that with generic views, yes, you can absolutely customize them  to do whatever it is that you want, but maybe it's not always the best idea to do that.  And unfortunately, the only way to figure that out is to get familiar with them, and  that's sort of unfortunate.  So now that we understand really how all of these work, how do we sort of tackle the problem  of using and building views?  For the function views and all of that jazz, I think it's fairly straightforward.  I do want to take a quick look at classic class-based views, because last time I presented  this, and the last few times I've given this, or similar talks, the most people go, wait,  could you show the tool?  How does this actually work?  So you're going to show up on this website, and it's going to show you all of the generic  views at the top level, and you can click on any of them.  And so I'm going to click on Detail View, and it's going to show me all of the classes  that are related that this view inherits, as well as it provides a link directly to  the documentation.  And below this, there are the attributes.  These are all of the attributes that I can override, including their current defaults,  so that I can see exactly what is going on.  This is really where you want to start, right?  If you decide, oh, I'm going to use a generic view, I'm going to go ahead and I'm going  to try and figure out which attributes I need to define.  Once you're comfortable with defining the attributes and going, OK, yeah, I can get  that behavior by changing just attributes, you can begin to look at the methods, right?  This is where you go, yep, totally comfortable with the attributes, but I need to just tweak  this one thing.  This allows you to see all of the methods that are being used.  You'll typically want to start with the methods that the Class Base View uses, right?  Get, post, put.  So right here, I can just click on get and it will show me the implementation as well  as tell me where it's actually defined, because it's not actually defined in detail view.  If you look all the way to the right, you can see it's defined in base detail view.  And so that's Class Base, they're Classy Class Base Views and sort of the go-to tool for  trying to get through generic views.  I'm also, when I was writing my book, when I was compiling my book, I found that I spent  a lot of time writing decorators in Django to get it to do what I wanted.  And I'm slowly going to be taking them and putting them out onto the internet.  And so I've started a project called Django Decorator Plus.  I'm a little burnt out from book writing to be perfectly honest with you.  And so I haven't gotten as much work done on this.  But I do have my replacement for the required decorator for function views, because I think  it's silly that the Class Base Views gets you options and head out of the box, but that  the decorator doesn't.  So I fixed that, and I've gone ahead and recreated the decorator.  These are two shortcuts for the decorator, and they're equivalent to just get and get  posts.  But again, I say get, but that's actually get head options, and get post is get post  head options.  So I'm hoping that that will provide the basis for adhering to HTTP methods or adhering to  the HTTP spec in function views.  Sorry, I keep getting distracted by the timer.  Which brings us to our conclusion.  We can come back to these questions that I was hoping you would find easy at this point,  make hopefully these are sort of tacklable, if that's a word.  So Django handles HTTP for me.  Why do I need to worry about it?  Well, as we now know, it doesn't handle it for you.  It will translate the HTTP into a nice Python object, and allows you to manipulate all of  that data and to easily use that in Python.  But it's not handling it for you.  You are still taking care in the URL patterns of the URL path to the resource.  And in views, you really do want to be considering at all points what HTTP method is being used  and how you react to it.  Because otherwise, you're building an API that is only using part of the information,  and some user on the other end is going to be really unhappy with you.  Then is Django deprecating function views?  It's not, right?  The idea behind a view is, you know, accept specific input, provide specific output,  and any callable can be that.  And so function views are not anything inherent to Django, and they're not going anywhere.  Aren't all class-based views generic?  No.  Hopefully, the walk-through history helps split the difference, right?  The idea is we have generic views, and that is very much its own concept, and then we  have object views, and that is very much its own concept.  And we...  There is some discussion about whether each one solves the problem it was designed to  solve.  And those are valid conversations to have, but it's difficult to have that conversation  if people continue to confuse the two.  Finally, how do I choose what kind of view to use?  This is easily the hardest question on here, and I have a set of questions that I ask myself  whenever I'm building a view.  And the first is, is there a generic view that does exactly what I want or almost what  I want, and can I simply plug into it?  If yes, use a generic view, right?  That's...  You know, it's therefore just that.  If there isn't, you're sort of left with the choice between a class-based view and a function-based  view, but we now know that they're essentially equivalent.  The only reason that you might want to use a class-based view is if you have behavior  that is shared across multiple views, at which point using object-oriented programming is  incredibly helpful, but if you don't, it's entirely up to your preference, right?  You could use function views or class-based views.  It doesn't really matter.  Which brings me to sort of the key takeaways.  The view is Django's solution to handling HTTP.  All views are callable, or Python callables.  Doesn't matter.  Please use the require HTTP methods if you are using function methods, or at least consider  how you're handling HTTP methods.  And finally, please think of the two concepts of generic views and class-based views as very  different, very separate.  Thank you very much all for coming.  I hope this was helpful.  Again, all of the related material is at that first link.  My book is currently available for pre-order, and it's currently discounted.  Amazon is in charge of that, and they won't give me an answer as to whether the discount  remains after or if that's simply a pre-order thing, but it's currently discounted.  And finally, at the end of September, as I mentioned at the beginning of October, rather,  I'm going to be teaching a class in Django locally.  As a thank you for all coming to this, that is a promo code that you can use for 20% off.  Questions?  I'm also, if we're out of time, I'm happy to take questions in the hallway.  I have 40 seconds.  I'm sorry I cut this so close and that we started late.  Are there any questions?  And again, feel free to just grab me throughout the conference if you do at any point.  I think there's a mic.  Based on the flexibility of a class-based view, doesn't it, and the fact that it gives  you all those methods to define kind of for free, doesn't it make sense to always use  a class-based view over a function view because you'll need to deal with the other methods?  It's sort of your, honestly, is really your preference because at that point, you know,  it will get you head and options, but let's say that you're using the decorators from  Decorator Plus, you get that same behavior in a function view for just calling return.  And so there's really very little difference if it's really a very, very simple view.  Is there possibly like a performance optimization overhead for, or performance hit for you?  Or are you using a class method over a function view, a class view over a function view?  There might be a small performance hit, but that's, I mean, that's not really where your  performance problems are going to be, right?  Typically your performance problems are going to be in IO.  Okay.  So.  Cool.  Thanks.  No.  Hi.  So I'm wondering about, you know, let's say for example you have a model or an object  of a model such as like a task and you know, you can perform different modifications on  it, right?  So I guess you would use like an update view or something like that as a class based view.  If you wanted to modify it in different ways at different stages of time, do you have a  recommendation on how you would do that?  So like, you know, let's say at one point the task is unassigned and then you post that  it's been assigned to a particular person.  I'm thinking of, you know, a sort of simple ticketing system, right?  Sure.  And then the person updates it and so they post, you know, the status of it and then eventually  it gets closed.  Could you handle all of that in a single class or would you split it into different URLs?  Do you have any thoughts on that?  That depends entirely on how you want to handle it.  You certainly could have a single edit view where you can change all of this, all of the  fields on the model.  You certainly could have multiple, right?  You might just have one where you click on it and it immediately updates and changes  a status flag.  So it's sort of up to you.  I may be misunderstanding the question though.  I'm not super clear on all the details.  I'm happy to talk about it afterwards.  Thank you all very, very much for coming.  I hope that was helpful.  Feel free to grab me during the conference if you have any questions.  Thank you again.  Thank you.
DjangoCon_US_2015_-_Django_Views__Functions__Classes__and_Generics_by_Andrew_Pinkham_BJiOERA49ZQ_0_155.png DjangoCon_US_2015_-_Django_Views__Functions__Classes__and_Generics_by_Andrew_Pinkham_BJiOERA49ZQ_156_287.png DjangoCon_US_2015_-_Django_Views__Functions__Classes__and_Generics_by_Andrew_Pinkham_BJiOERA49ZQ_288_395.png DjangoCon_US_2015_-_Django_Views__Functions__Classes__and_Generics_by_Andrew_Pinkham_BJiOERA49ZQ_396_515.png DjangoCon_US_2015_-_Django_Views__Functions__Classes__and_Generics_by_Andrew_Pinkham_BJiOERA49ZQ_516_839.png DjangoCon_US_2015_-_Django_Views__Functions__Classes__and_Generics_by_Andrew_Pinkham_BJiOERA49ZQ_840_1331.png DjangoCon_US_2015_-_Django_Views__Functions__Classes__and_Generics_by_Andrew_Pinkham_BJiOERA49ZQ_1332_3995.png DjangoCon_US_2015_-_Django_Views__Functions__Classes__and_Generics_by_Andrew_Pinkham_BJiOERA49ZQ_3996_4103.png DjangoCon_US_2015_-_Django_Views__Functions__Classes__and_Generics_by_Andrew_Pinkham_BJiOERA49ZQ_4104_6671.png DjangoCon_US_2015_-_Django_Views__Functions__Classes__and_Generics_by_Andrew_Pinkham_BJiOERA49ZQ_6672_6863.png DjangoCon_US_2015_-_Django_Views__Functions__Classes__and_Generics_by_Andrew_Pinkham_BJiOERA49ZQ_6864_7607.png DjangoCon_US_2015_-_Django_Views__Functions__Classes__and_Generics_by_Andrew_Pinkham_BJiOERA49ZQ_7608_7835.png DjangoCon_US_2015_-_Django_Views__Functions__Classes__and_Generics_by_Andrew_Pinkham_BJiOERA49ZQ_7836_8447.png DjangoCon_US_2015_-_Django_Views__Functions__Classes__and_Generics_by_Andrew_Pinkham_BJiOERA49ZQ_8448_9083.png DjangoCon_US_2015_-_Django_Views__Functions__Classes__and_Generics_by_Andrew_Pinkham_BJiOERA49ZQ_9084_9215.png DjangoCon_US_2015_-_Django_Views__Functions__Classes__and_Generics_by_Andrew_Pinkham_BJiOERA49ZQ_9216_10259.png DjangoCon_US_2015_-_Django_Views__Functions__Classes__and_Generics_by_Andrew_Pinkham_BJiOERA49ZQ_10260_10379.png DjangoCon_US_2015_-_Django_Views__Functions__Classes__and_Generics_by_Andrew_Pinkham_BJiOERA49ZQ_10380_11783.png DjangoCon_US_2015_-_Django_Views__Functions__Classes__and_Generics_by_Andrew_Pinkham_BJiOERA49ZQ_11784_12119.png DjangoCon_US_2015_-_Django_Views__Functions__Classes__and_Generics_by_Andrew_Pinkham_BJiOERA49ZQ_12120_13691.png DjangoCon_US_2015_-_Django_Views__Functions__Classes__and_Generics_by_Andrew_Pinkham_BJiOERA49ZQ_13692_13775.png DjangoCon_US_2015_-_Django_Views__Functions__Classes__and_Generics_by_Andrew_Pinkham_BJiOERA49ZQ_13776_14315.png DjangoCon_US_2015_-_Django_Views__Functions__Classes__and_Generics_by_Andrew_Pinkham_BJiOERA49ZQ_14316_14651.png DjangoCon_US_2015_-_Django_Views__Functions__Classes__and_Generics_by_Andrew_Pinkham_BJiOERA49ZQ_14652_17567.png DjangoCon_US_2015_-_Django_Views__Functions__Classes__and_Generics_by_Andrew_Pinkham_BJiOERA49ZQ_17568_17615.png DjangoCon_US_2015_-_Django_Views__Functions__Classes__and_Generics_by_Andrew_Pinkham_BJiOERA49ZQ_17616_20255.png DjangoCon_US_2015_-_Django_Views__Functions__Classes__and_Generics_by_Andrew_Pinkham_BJiOERA49ZQ_20256_24551.png DjangoCon_US_2015_-_Django_Views__Functions__Classes__and_Generics_by_Andrew_Pinkham_BJiOERA49ZQ_24552_24803.png DjangoCon_US_2015_-_Django_Views__Functions__Classes__and_Generics_by_Andrew_Pinkham_BJiOERA49ZQ_24804_25355.png DjangoCon_US_2015_-_Django_Views__Functions__Classes__and_Generics_by_Andrew_Pinkham_BJiOERA49ZQ_25356_25847.png DjangoCon_US_2015_-_Django_Views__Functions__Classes__and_Generics_by_Andrew_Pinkham_BJiOERA49ZQ_25848_26039.png DjangoCon_US_2015_-_Django_Views__Functions__Classes__and_Generics_by_Andrew_Pinkham_BJiOERA49ZQ_26040_26819.png DjangoCon_US_2015_-_Django_Views__Functions__Classes__and_Generics_by_Andrew_Pinkham_BJiOERA49ZQ_26820_30551.png DjangoCon_US_2015_-_Django_Views__Functions__Classes__and_Generics_by_Andrew_Pinkham_BJiOERA49ZQ_30552_31211.png DjangoCon_US_2015_-_Django_Views__Functions__Classes__and_Generics_by_Andrew_Pinkham_BJiOERA49ZQ_31212_32123.png DjangoCon_US_2015_-_Django_Views__Functions__Classes__and_Generics_by_Andrew_Pinkham_BJiOERA49ZQ_32124_32699.png DjangoCon_US_2015_-_Django_Views__Functions__Classes__and_Generics_by_Andrew_Pinkham_BJiOERA49ZQ_32700_34451.png DjangoCon_US_2015_-_Django_Views__Functions__Classes__and_Generics_by_Andrew_Pinkham_BJiOERA49ZQ_34452_36755.png DjangoCon_US_2015_-_Django_Views__Functions__Classes__and_Generics_by_Andrew_Pinkham_BJiOERA49ZQ_36756_38123.png DjangoCon_US_2015_-_Django_Views__Functions__Classes__and_Generics_by_Andrew_Pinkham_BJiOERA49ZQ_38124_38303.png DjangoCon_US_2015_-_Django_Views__Functions__Classes__and_Generics_by_Andrew_Pinkham_BJiOERA49ZQ_38304_39647.png DjangoCon_US_2015_-_Django_Views__Functions__Classes__and_Generics_by_Andrew_Pinkham_BJiOERA49ZQ_39648_39971.png DjangoCon_US_2015_-_Django_Views__Functions__Classes__and_Generics_by_Andrew_Pinkham_BJiOERA49ZQ_39972_40115.png DjangoCon_US_2015_-_Django_Views__Functions__Classes__and_Generics_by_Andrew_Pinkham_BJiOERA49ZQ_40116_40211.png DjangoCon_US_2015_-_Django_Views__Functions__Classes__and_Generics_by_Andrew_Pinkham_BJiOERA49ZQ_40212_40367.png DjangoCon_US_2015_-_Django_Views__Functions__Classes__and_Generics_by_Andrew_Pinkham_BJiOERA49ZQ_40368_42755.png DjangoCon_US_2015_-_Django_Views__Functions__Classes__and_Generics_by_Andrew_Pinkham_BJiOERA49ZQ_42756_43211.png DjangoCon_US_2015_-_Django_Views__Functions__Classes__and_Generics_by_Andrew_Pinkham_BJiOERA49ZQ_43212_44147.png DjangoCon_US_2015_-_Django_Views__Functions__Classes__and_Generics_by_Andrew_Pinkham_BJiOERA49ZQ_44148_47303.png DjangoCon_US_2015_-_Django_Views__Functions__Classes__and_Generics_by_Andrew_Pinkham_BJiOERA49ZQ_47304_47891.png DjangoCon_US_2015_-_Django_Views__Functions__Classes__and_Generics_by_Andrew_Pinkham_BJiOERA49ZQ_47892_47987.png DjangoCon_US_2015_-_Django_Views__Functions__Classes__and_Generics_by_Andrew_Pinkham_BJiOERA49ZQ_47988_54587.png DjangoCon_US_2015_-_Django_Views__Functions__Classes__and_Generics_by_Andrew_Pinkham_BJiOERA49ZQ_54588_55295.png DjangoCon_US_2015_-_Django_Views__Functions__Classes__and_Generics_by_Andrew_Pinkham_BJiOERA49ZQ_55296_56087.png DjangoCon_US_2015_-_Django_Views__Functions__Classes__and_Generics_by_Andrew_Pinkham_BJiOERA49ZQ_56088_58655.png DjangoCon_US_2015_-_Django_Views__Functions__Classes__and_Generics_by_Andrew_Pinkham_BJiOERA49ZQ_58656_58703.png DjangoCon_US_2015_-_Django_Views__Functions__Classes__and_Generics_by_Andrew_Pinkham_BJiOERA49ZQ_58704_58751.png DjangoCon_US_2015_-_Django_Views__Functions__Classes__and_Generics_by_Andrew_Pinkham_BJiOERA49ZQ_58752_58823.png DjangoCon_US_2015_-_Django_Views__Functions__Classes__and_Generics_by_Andrew_Pinkham_BJiOERA49ZQ_58824_58919.png DjangoCon_US_2015_-_Django_Views__Functions__Classes__and_Generics_by_Andrew_Pinkham_BJiOERA49ZQ_58920_58920.png
So, as just mentioned, my name is Andrew. I'm a freelance software consultant and also a technical instructor. I teach Django in corporate and startup settings. I have a class coming up at the end of September, which I'll come back to, because perhaps most interestingly, as I also mentioned, I'm the author of Django Unleashed. The book is currently available for pre-order on Amazon. And Pearson is hedging their bets. They're saying that it's going to ship in December. We sort of expected to actually ship at the very end of November, but you didn't hear that from me. So the goal for today is to make it to that by the end of this talk, if you currently can't answer some of these questions, I want to make it so that you look at these questions and you go, oh, you know what? I got this. I know exactly how to answer these questions. And so the goal is to make it really easy to get through all of these. We'll actually come back to the questions themselves. The talk itself is split into three totally unequal parts. We're going to start at the very beginning with the largest section, and it's essentially trying to define the problem and understand the high-level concepts that allow for the solution. We're then going to actually examine the solutions, possible solutions, and see how to interact with them. And then finally, the smallest section is going to be a little bit about the tools that might help you ease the solution process. The fundamentals, right, the problem solution, we're going to look at Python callables. We're going to examine HTTP. And this is going to allow us to step back and look at Django views from a very high-level perspective. Then we'll actually look at views. We'll start with a little bit of a history. And then we'll look at each type of view available in Django at the moment. And finally, we will enhance. We'll look at a couple options that might be useful depending on what your choices are. I typically like to provide slides and code, and eventually I will sit down and write an article with all of this and based on feedback. And so you can find all of that material at this link. Currently, the slides are up online, so if you want to follow along, you can do that. And all of the code that will be appearing, including an IPython notebook, which you can fool around with, is currently posted on GitHub. So we're going to dive straight into it. Let's talk about Python callables. We're used to seeing Python callables all the time, right? The function is sort of the most basic. It takes an input. It gives you output. This might seem like, OK, Andrew, why are you talking about this? This is really, really basic, but I want to make sure we're all on the same page for maybe some of the more advanced stuff. Python comes with anonymous functions, which allows you to sort of define them on the fly. They're interesting, but not really the point here. It should come as no surprise. That methods are also callables, right? A method takes input and it provides output. Maybe a little more surprisingly, however, is the fact that you can see that when I instantiate the class, I'm calling the class. And that is, in fact, I am calling it. It makes it a callable. So some people in the room will go, oh, yes, well, of course, there's the Dunder and Knit method, and we use that to make it so that a class is called. That's where we control initialization. Yes. It turns out that if you look at the Python C code, it's a little bit more complicated than that. But that is, in fact, yes, what makes a class callable. And you'll say, great, so we have functions and we have methods. And actually, it turns out we can also make it so that on top of functions, methods, and classes, you can make objects callable with the Dunder callable method. So what that means is that you have virtually everything in Python that can be a callable given certain requirements. And you can see here, I simply ask Python, hey, can I call this? So now that we all are really, really clear on what a callable is, we can move into the rest of the talk. And we're going to start with HTTP. You've surely seen books about this, articles about this, presentations about this. And we could sort of start when we go, yes, well, it stands for this. It defines how a client and a server communicate. The client will issue a request method. The server does whatever it needs to. And the server is going to return a response. And at that point, we could begin to talk about the different methods available. And we could go through and we outline all the ones that are important. We can then get into a real battle about post and put and the meaning of item potent methods. And I can stand up here and I can really go through this and ye shall not and whatever goes but that really misses the point for us. And the point is this, your website must adhere to HTTP. When you are building a website, the problem you are trying to solve is adherence to HTTP, right? So if I go and build a server and I have the following request methods and then I define the following response codes, not only will my web server not work but I have created a monster and you really need to pull me aside and have a word with me. So I'm going to really emphasize the fact that when you are building a website, your goal first and foremost is to adhere to HTTP. Now I'm also going to assert a little more baselessly that the goal of all software is to solve a problem or to automate behavior. And I admit, look, sometimes it's really not clear which of the two things that's doing. But I'm still going to tell you yes, I am absolutely correct on this. You will take my word for it. That means that in the context of HTTP and Django, HTTP is the central problem that any web framework must solve, right? Everything else is a nicety, it's there to help you but as a website is defined as just something that adheres to the HTTP spec, then that is the first problem it must fix. And it also means that you're the behavior it's automating. It's trying to make it so that you have to do the least amount of work possible to adhere to this, which allows us to move directly into Django. I don't know how many people here have not done the Django tutorial. Who here is really just getting started? Okay. So I'm glad to see that. I just want to talk real quick about what a view is. When you do the tutorial, you're going to see that there's some text that says a view is a type of web page. Russell Keith McGee two years ago at DjangoCon said views are for displaying content. I'm going to go so far as to say that it's dynamic generation of content, right? The Washington Post is a collection of web pages. Some of these web pages are similar, right? There are a whole bunch of articles on the website and they all meet the following structure, right? The articles are all the same thing. And so you typically, if you were building this in Django, would have a view for the articles, right? It becomes a type of web page. So you have your user show up and what's going to happen is they're going to, is that, oh yes, they're going to issue an HTTP request. Your website's going to compute and it's going to get a response back. This is how every website works and we're interested in the internals. In Django, you're going to start by building Django models. You might go ahead and build forms. Oh yes, you generate the database based on the models. You're then going to go ahead and make template files and which allows you to build the views. If your website's really complicated, you might have middleware and context processors at which point you'll then load Django. It will get you the following tools and you can now work with this. Your user is going to, just as before, issue an HTTP request. It goes through the middleware, gets into the dispatch. It will find a URL pattern and then find a view. The view might interact with a model. It might interact with forms and it might go and interact with the templates. It's then always going to return back to the user the opposite way through the middleware and then send it back data. You'll notice that in all of these cases, I said might because the truth of the matter is that this is the only thing that's really important. Everything else is simply a way to try and, I'm glad that got laughs, this is simply, this is the core of Django. This is the only thing that you would really need to be a web framework. Everything else is really useful, phenomenally helpful, but this is the heart of it. Before we go any further, I want to note that that was a simplification. That animation is nice, but it doesn't deal with all sorts of things. Please don't email me about the fact that it's wrong. I know it's wrong. Somewhat wrong, right? We're going to focus on this. In particular, we're going to focus on views. Now because views are so heavily tied to URL patterns, I'm going to have to deal with URL patterns a little bit. The entire goal is going to be to deal with views in the context of HTTP. This is the format of an HTTP method. This is what your server actually expects to receive when it comes in. We have these two systems and they are going to be looking at that request and trying to handle it. The first thing is the URL pattern is primarily interested in handling the path to the resource. It looks at the URL path and it goes, yep, I'm trying to figure out which view to call and maybe it will take that some information from the URL path and hand it to the view. Maybe not. But that means that the view is really interested in the HTTP method. There's nothing else in Django that's going to handle that for us. This allows us to come back to the original question, which is what is a view and we can look at it from a much more technical standpoint now. We accept an HTTP request object at which point we are going to, in the view, generate data based on the HTTP request method, any data that is coming along with the request, and any data that the URL dispatcher is taking from the URL pattern and then handing to our view. At which point the view will always, always, always return an HTTP response object. That should be ringing a few bells. Oh, look, it's, we have to accept and we have to return. The secret to views is that, whoops, the secret to views is that any Python callable can be a view, which sort of raises the question, why do we talk about functions and classes and generics? How do we limit it to this? Let's take a trip down memory lane. Back in 2005, when Django was nothing but a tarball, the official recommendation for building views was to use Django functions. We now know that that's not really because functions are sort of any sort of inherent part of Django, but simply they're the simplest form of Python callable. And so they were what made the most sense to use. Very quickly thereafter, people said, you know what would be great? We are constantly reprogramming all of these webpages again and again and again. Could we just put them in Django so that we can just use them straight out of the box? People said, yeah, sure, that sounds like a great idea. There's a problem with this, right? When you try and have extensible, or you have this behavior and you say, this is almost exactly what I want, right? This is almost exactly the behavior I want. It's just a little bit different. The difficulty there is that if you're using a function, functions are rigid, right? You can't sort of just dig in there and change a little thing. You have to use the function entirely or not at all. That sort of became a problem with the generic views. And they said, can we do this better? Oh, we can try and extend the number of parameters. We can do x, y, and z. And eventually they realized, oh, we're re-implementing object-oriented programming. Well, that's ridiculous. Why don't we simply use a class to instantiate objects that are views? This was a pretty successful idea, right? This is Alex Ganner saying, wow, this would be so useful. I'm sorry if that's not large enough. So useful to have, right? We'd be able to go ahead and just extend it. And so in 2008, Joseph Cochran's, I'm sorry if I'm mispronouncing that, went ahead and opened the ticket. And so the discussion became, well, we're going to fix generic views by allowing them to be extensible. But first, we actually need a class that is a view, right? We need to be able to instantiate just a simple object view. And so they said, well, what do we want for that? Oh, well, we need to make sure that when people are using it, it's really obvious how to use it. We need to make sure that it's extendable because that was sort of the original idea. And we need to make sure that it's thread safe. Turns out, that last one's really hard. And so it took until 2011 to really get it right, to really sit down and say, OK, we're going to work through the entire thing and get it right. And at which point, they released the class-based view along with the generic views. And this is sort of where we ran into a naming problem because we'd started with generic views. And it was obvious what those were, right? Like, oh, it's just behavior that's preprogrammed for us. And now we've introduced this class-based view, right? It's just a view that instantiates an object view, or it's a class that instantiates an object view, excuse me. And they said, well, we'll just add class-based in front of generic. Everyone will understand, right? There'll be no confusion there. Unfortunately, there was a lot of confusion. And there's sort of, there remains a lot of confusion. One of the ways I've started discussing it is to talk about class-based views as object views. Yes, there's a class, but the actual views are the objects that you're instantiating. And that helps a lot of people go, oh, yes, of course. And the other thing is that the main point of the generic views is not that they're class-based or objects. That's certainly incredibly useful for extending behavior and taking control, but that's really not the point. The point of the matter is that they're generic views. And that leaves us. The state of the pony, as of Django 1.3, oh, for all the beginners in the room, the state of the pony is a joke, a long-standing Django joke where we talk about people saying, no, you can't have that pony in terms of new Django features. And so you will regularly hear people say the state of the pony to refer to the state of Django. I did not think about that inside joke. Sorry about that. So we currently have three options, right? The function views simply because it's a callable, right? We can use any callable. And so naturally, you can use a function view. And then the object views or the class-based views are there and useful because they put three years of time into really making sure it was safe and usable. And so people don't create their own because it's a lot of work to do that. And why wouldn't I just use these? And then the generic views are simply preprogrammed views for you to use. And so not really in the same category. And that means that we can now move into looking at each one. So the function views, we now know, even though they're considered the original, it's simply that they follow what it means to be a view and they're callables, right? So we're going to begin by setting up a little project. This is a model. It's really uninspiring, but you get the point. It's got a name and a slug. Because I can't get away from building views without a URL pattern, I'm going to go ahead and build a URL pattern. It's going to call my view and it takes in a single parameter called the slug. This allows us to program this. And this is sort of your stereotypical view. For all of the beginners in the room, this is sort of how we think of views. I take in some data. I fetch something from the database. And then I return something via the template. This is not a great example, unfortunately, because it means that I'm using all of these other subsystems when I meant to just focus on one thing. And the only thing that really matters is you can see the first parameter I'm taking in is the request and the render is using that to return an HTTP response. And so the idea here is that we're doing that. Can anyone tell me what's missing from our stereotypical view? Does anyone see something that should maybe be in there? Feel free to actually shout this out, but I'm actually asking you a question. The method, yes. We haven't bothered to handle the HTTP method at all. It's not even in our code. There are many ways we can do this. It's fairly easy. I can just add an if condition and say, look, if it's the get method, do the following. And if it's not the get method, please return an HTTP response not allowed and tell them that the only thing we accept is the get method. This is horrible. You're not going to program this. Come on. That's not great. Thankfully, Django introduces the HTTP decorator. I'm not going to get that out. To help that. And so here we simply say, look, this view only accepts get and head. And everything else, it will return an HTTP 405 method on or return an HTTP response 405 error code. There we are. Turns out there's a shortcut for get and head called require safe. And so we can simply move that over. And at which point we can actually see all the changes to our code by using a tool called telnet. You can actually write the HTTP request directly in your command line if you're running a server. This is actually kind of fun, right? So I'm actually typing in get a path and it is returning this data to me. And I can see, oh, yeah, it expects that and it gives that stuff back to me. If I give it a method that is not expecting like options, it's going to say, nope, I have no idea what this is. I'm not programmed to handle this. And what I can tell you is that I can handle get and head. You can see it on the third line from the bottom. You'll notice that throughout this talk. I'm going to avoid post, even though it's commonly used because the CSRF middleware is going to get in the way and simply kind of interject itself and go, hi, by the way, you're not being secure. If you were to disable it, you would get a four or five error. Please don't disable it unless you really, really, really know what you're doing. We're going to go through and we're just going to create another view just to see a slightly different case. So here is just another URL pattern and here is a view and you'll go, oh, look, this is for handling forms and we say, oh, okay, so if it's a post, I behave a specific way and if it's not a post, you know, I expect to get and I behave a different way. That's like showing up at your 24 hour diner and 90% of the time, you're going to say, yes, I would like the scrambled eggs and you're going to, so people are going to ask for scrambled eggs 90% of the time and so you're just going to give them scrambled eggs. But you're also, for 10% of the time, giving the people who are asking for hamburger or the hash browns scrambled eggs. That's really frustrating and you're probably not going to do well with that crowd and so even though you're handling post, you're not actually handling any of the other HGP methods, right? You can see that it's, I sort of brought a laser and that's not working. You can see that the topmost condition there, the else, simply says else, doesn't check for any other HGP method and that's not so great. So even if you're partially handling the HGP method, you really do want to think about whether you're handling all of them and that's how you should deal with function views in Django. We can now turn to class based views and the key advantage to class based views is the fact that they're classes, you're dealing with object oriented programming and it's a really powerful way, not the only way, but a very powerful way to adhere to dry, which is don't repeat yourself in Python. So once again, we're going to convert the last two views that we built into class based views. I have to deal with the URL pattern. I can't go into, I don't have enough time to go into detail as to why I'm changing this. There's a lot of documentation and I cover this in great detail in my talk at DjangoCon 2013. The bottom line is you'll have to believe me for the moment that I have to make this change for this to work. We can then actually look at our code and the first thing I'm going to do is get rid of the decorator. It's gone. I don't need it. The next thing I'm going to do is change the name of this function to get and I'm going to add self in anticipation of having this as a class. I indent and I put it under a class. That is the only difference, right? It is exactly the same thing except it is now, it now has a class that it belongs to and is now a method. There is however a huge amount of beauty to this because it makes explicit the problem you are trying to solve. This code only works if an HTTP get method is used and everything else is not handled or rather will return to 405 error. Almost everything. As it turns out, class based views are kind of neat. If you give them a get method, they will automatically give you head method handling and it will also always give you option handling which is really, really cool and much better than what you are getting with the function views. The same thing is sort of similar when we come back to our form view and we say, oh, okay, well, we need to do a little bit more here because what we actually wanted was get and post and so we can go ahead and create two methods for the class based views and we are going to go ahead and define a bunch of attributes. The get method is completely uninteresting, right? I take input, I provide output to a page. The code is not really the point input output just the get method and with post, it is sort of the same thing. You can handle the form however you need to but the bottom line is that this is behavior that is defined only for the post method and of course you are getting options and head because of the way we built this. This is very different from what we had originally. One of the things that I found with beginners is if you look at this as a beginner, it is kind of a lot to take in. You go, well, there is an if condition but then there is a second if condition and there is this implicit return that has multiple behavior and when I ask people taking my class, how many behaviors do you think is in here? The answers I typically get are either two or four. When the truth, if you look here, is that there are three and that becomes much easier to see in this context. So CBVs, despite the fact that we say, or class-based views, despite the fact that we say are more complicated and take a little bit more code, can actually be used in certain contexts in really interesting, very helpful ways. So part of this, if you are totally new, you may not know why I am defending these quite so much. There is a certain, when they were introduced because of the confusion around them, a lot of people said, well, they are not worth using at all or ever and so part of my position is wait, these are a tool and tools do have purposes and can be used in certain contexts as long as you understand what the tool does and when those contexts are. So I am just trying to provide when and the context. This allows us to sort of look at the odd view set in the game which are the generic class-based views and I am just going to dive right in because there is so much here and you can see that this is all of model detail now. I have completely removed the get method. It is nowhere. I am just sort of invocating this. And this feels awful because you are looking at this and you are like, well, wait, this is like a game of mad libs. How do I know what to fill in or how to fill it in? And this gets even worse with the model create. I have removed get and I have removed post but the attributes are exactly the same as they were before. And I mean, at least you have some small comfort in saying, well, it is exactly the way it worked before. Right, Andrew? No, it is not. No, and that is sort of the problem is suddenly on our new form we now have the put verb which has been instantiated. And you go, okay, well, hold on. Let me sit back and go through this. What does this look like? That is the actual graph of how all of the generic views are related. It is really kind of insane. And when I gave my talk at JangoCon 2013, this is the image that I presented. You feel, you take so much time going, oh, I have no idea what I am doing. I don't understand. The point really wasn't that it is a terrible idea because if you start using generic views, it turns you into a real powerhouse. I mean, you can become a super coder. You will leave websites in your wake. The problem is that you spend so much time doing stuff that doesn't make any sense to try and get there that it can be really frustrating. There are tools that are very helpful and we will come back to this one. But the idea here is that if you were a beginner, the idea was that by having these be classes, we would be able to go ahead and extend them. And by overcomplicating them, it has become a bit of a problem because beginners go, well, how do I extend them? How do I learn how to go about them? And unfortunately, my advice is that if you're a beginner, don't try and use them. If you see that there is a generic class-based view that does exactly what you want, use it. See how you just get it to do exactly what it was built for. If you then, once you've become comfortable with that, then begin to go, oh, okay, well, maybe I can begin to look at the methods. There's this thing that happens. You can see it on the mailing list. I see it a lot in my classes where people go, oh, I would like to use the following generic view to do X, Y, and Z. And the answer is always, well, yes, you can do that, but there are better options for how you can go about building that. I really thought that was going to get more laughs. Really, it's nice to see a little contingency over there. Okay. And so that's the thing, is that with generic views, yes, you can absolutely customize them to do whatever it is that you want, but maybe it's not always the best idea to do that. And unfortunately, the only way to figure that out is to get familiar with them, and that's sort of unfortunate. So now that we understand really how all of these work, how do we sort of tackle the problem of using and building views? For the function views and all of that jazz, I think it's fairly straightforward. I do want to take a quick look at classic class-based views, because last time I presented this, and the last few times I've given this, or similar talks, the most people go, wait, could you show the tool? How does this actually work? So you're going to show up on this website, and it's going to show you all of the generic views at the top level, and you can click on any of them. And so I'm going to click on Detail View, and it's going to show me all of the classes that are related that this view inherits, as well as it provides a link directly to the documentation. And below this, there are the attributes. These are all of the attributes that I can override, including their current defaults, so that I can see exactly what is going on. This is really where you want to start, right? If you decide, oh, I'm going to use a generic view, I'm going to go ahead and I'm going to try and figure out which attributes I need to define. Once you're comfortable with defining the attributes and going, OK, yeah, I can get that behavior by changing just attributes, you can begin to look at the methods, right? This is where you go, yep, totally comfortable with the attributes, but I need to just tweak this one thing. This allows you to see all of the methods that are being used. You'll typically want to start with the methods that the Class Base View uses, right? Get, post, put. So right here, I can just click on get and it will show me the implementation as well as tell me where it's actually defined, because it's not actually defined in detail view. If you look all the way to the right, you can see it's defined in base detail view. And so that's Class Base, they're Classy Class Base Views and sort of the go-to tool for trying to get through generic views. I'm also, when I was writing my book, when I was compiling my book, I found that I spent a lot of time writing decorators in Django to get it to do what I wanted. And I'm slowly going to be taking them and putting them out onto the internet. And so I've started a project called Django Decorator Plus. I'm a little burnt out from book writing to be perfectly honest with you. And so I haven't gotten as much work done on this. But I do have my replacement for the required decorator for function views, because I think it's silly that the Class Base Views gets you options and head out of the box, but that the decorator doesn't. So I fixed that, and I've gone ahead and recreated the decorator. These are two shortcuts for the decorator, and they're equivalent to just get and get posts. But again, I say get, but that's actually get head options, and get post is get post head options. So I'm hoping that that will provide the basis for adhering to HTTP methods or adhering to the HTTP spec in function views. Sorry, I keep getting distracted by the timer. Which brings us to our conclusion. We can come back to these questions that I was hoping you would find easy at this point, make hopefully these are sort of tacklable, if that's a word. So Django handles HTTP for me. Why do I need to worry about it? Well, as we now know, it doesn't handle it for you. It will translate the HTTP into a nice Python object, and allows you to manipulate all of that data and to easily use that in Python. But it's not handling it for you. You are still taking care in the URL patterns of the URL path to the resource. And in views, you really do want to be considering at all points what HTTP method is being used and how you react to it. Because otherwise, you're building an API that is only using part of the information, and some user on the other end is going to be really unhappy with you. Then is Django deprecating function views? It's not, right? The idea behind a view is, you know, accept specific input, provide specific output, and any callable can be that. And so function views are not anything inherent to Django, and they're not going anywhere. Aren't all class-based views generic? No. Hopefully, the walk-through history helps split the difference, right? The idea is we have generic views, and that is very much its own concept, and then we have object views, and that is very much its own concept. And we... There is some discussion about whether each one solves the problem it was designed to solve. And those are valid conversations to have, but it's difficult to have that conversation if people continue to confuse the two. Finally, how do I choose what kind of view to use? This is easily the hardest question on here, and I have a set of questions that I ask myself whenever I'm building a view. And the first is, is there a generic view that does exactly what I want or almost what I want, and can I simply plug into it? If yes, use a generic view, right? That's... You know, it's therefore just that. If there isn't, you're sort of left with the choice between a class-based view and a function-based view, but we now know that they're essentially equivalent. The only reason that you might want to use a class-based view is if you have behavior that is shared across multiple views, at which point using object-oriented programming is incredibly helpful, but if you don't, it's entirely up to your preference, right? You could use function views or class-based views. It doesn't really matter. Which brings me to sort of the key takeaways. The view is Django's solution to handling HTTP. All views are callable, or Python callables. Doesn't matter. Please use the require HTTP methods if you are using function methods, or at least consider how you're handling HTTP methods. And finally, please think of the two concepts of generic views and class-based views as very different, very separate. Thank you very much all for coming. I hope this was helpful. Again, all of the related material is at that first link. My book is currently available for pre-order, and it's currently discounted. Amazon is in charge of that, and they won't give me an answer as to whether the discount remains after or if that's simply a pre-order thing, but it's currently discounted. And finally, at the end of September, as I mentioned at the beginning of October, rather, I'm going to be teaching a class in Django locally. As a thank you for all coming to this, that is a promo code that you can use for 20% off. Questions? I'm also, if we're out of time, I'm happy to take questions in the hallway. I have 40 seconds. I'm sorry I cut this so close and that we started late. Are there any questions? And again, feel free to just grab me throughout the conference if you do at any point. I think there's a mic. Based on the flexibility of a class-based view, doesn't it, and the fact that it gives you all those methods to define kind of for free, doesn't it make sense to always use a class-based view over a function view because you'll need to deal with the other methods? It's sort of your, honestly, is really your preference because at that point, you know, it will get you head and options, but let's say that you're using the decorators from Decorator Plus, you get that same behavior in a function view for just calling return. And so there's really very little difference if it's really a very, very simple view. Is there possibly like a performance optimization overhead for, or performance hit for you? Or are you using a class method over a function view, a class view over a function view? There might be a small performance hit, but that's, I mean, that's not really where your performance problems are going to be, right? Typically your performance problems are going to be in IO. Okay. So. Cool. Thanks. No. Hi. So I'm wondering about, you know, let's say for example you have a model or an object of a model such as like a task and you know, you can perform different modifications on it, right? So I guess you would use like an update view or something like that as a class based view. If you wanted to modify it in different ways at different stages of time, do you have a recommendation on how you would do that? So like, you know, let's say at one point the task is unassigned and then you post that it's been assigned to a particular person. I'm thinking of, you know, a sort of simple ticketing system, right? Sure. And then the person updates it and so they post, you know, the status of it and then eventually it gets closed. Could you handle all of that in a single class or would you split it into different URLs? Do you have any thoughts on that? That depends entirely on how you want to handle it. You certainly could have a single edit view where you can change all of this, all of the fields on the model. You certainly could have multiple, right? You might just have one where you click on it and it immediately updates and changes a status flag. So it's sort of up to you. I may be misunderstanding the question though. I'm not super clear on all the details. I'm happy to talk about it afterwards. Thank you all very, very much for coming. I hope that was helpful. Feel free to grab me during the conference if you have any questions. Thank you again. Thank you.
The book is currently available for pre-order on that from me. So the goal for today is to make it to that by the end of this talk, if you currently And this is going to allow us to step back and look at Django views from a very high-level then we'll look at each type of view available in Django at the moment. And finally, we will talk. And we're going to start with HTTP. You've of start when we go, yes, well, it stands for quick about what a view is. When you do the yes, they're going to issue an HTTP request. Your is what is a view and we can look at it from a question, why do we talk about functions and difficulty there is that if you're using a can use any callable. And so naturally, you can use a function view. And then the object views or should deal with function views in Django. We can these be classes, we would be able to go ahead they're Classy Class Base Views and sort of the tacklable, if that's a word. So Django handles the two. Finally, how do I choose what kind of view to use? This is easily the hardest question with the choice between a class-based view and a generic views and class-based views as very