 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 touching 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 so 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, 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. You'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 init 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, and 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? OK. 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. 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 issue an HTTP request. The 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 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. And so please don't email me about the fact that it's wrong. I know it's wrong. Somewhat wrong, right? So we're going to focus on this. And 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. And the entire goal is going to be to deal with views in the context of HTTP. So this is the format of an HTTP method. This is what your server actually expects to receive when it comes in. And we have these two systems, and they are going to be looking at that request and trying to handle it. The first thing is it's going to, 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, and 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, 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? Why do we limit it to this? Let's take a trip down memory lane. Back in 2005, when Django was nothing but a tar ball, 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're 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. When you try and have extensible, or you have this behavior and you say, this is almost exactly what I want. 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. 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. And 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. This is Alex Gainer saying, wow, this would be so useful. I'm sorry if that's not large enough. It's so useful to have. We'd be able to go ahead and just extend it. And so in 2008, Joseph Coker-Hans, I'm sorry if I'm mispronouncing that, went ahead and opened a 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. 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'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 pre-programmed for us. And now we've introduced this class-based view. It's just a view that instantiates an object view. 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 will be no confusion there. Unfortunately, there was a lot of confusion. And there's sort of the 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 of the beginners in the room, the state of the ponies 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. The function views simply because it's a callable. 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 gonna 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's sort of 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, right? 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 gonna program this. Come on, that's not great. Thankfully, Django introduces the HTTP decorator, I'm not gonna get that out, to help that. And so here we simply say look, this view, it only accepts get and head and everything else it will return an HTTP 405 method on return an HTTP response for a five 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 it's 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 HTTP methods, right? You can see that it's, I sort of brought a laser and that's not working. You can see that the top most condition there, the else simply says else, doesn't check for any other HTTP method and that's not so great. So even if you're partially handling the HTTP 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 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're 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're 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's sort of the same thing. You 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're getting options and head because of the way we've built this. This is very different from what we had originally and one of the things that I found with beginners is if you look at this as a beginner, it's kind of a lot to take in. You go, well, there's an if condition but then there's a second if condition and there's 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're totally new you may not know why I'm defending these quite so much. There's a certain, when they were introduced because of the confusion around them a lot of people said, well, they're 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'm 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'm just gonna dive right in because there's so much here and you can see that this is all of model detail now. I've completely removed the get method, it's nowhere. I'm just sort of invocating this and this feels awful because you're looking at this and you're 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've removed get and I've 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's exactly the way it worked before. Right, Andrew? No, it isn't. No, and that's 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's the actual graph of how all of the generic views are related. It's 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'm doing. I don't understand. The point really wasn't that it's 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'll come back to this one but the idea here is that if you're a beginner, the idea was that by having these be classes, we would be able to go ahead and extend them and by over complicating them, it's 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, right? 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 class-based views because last time I presented this, and the last few times I've given this, or similar talks, most people go, wait, could you show the tool? How does this actually work? So you're gonna 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 gonna 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 wanna start, right? If you decide, oh, I'm going to use a generic view, I'm gonna go ahead and I'm gonna try and figure out which attributes I need to define. Once you're comfortable with defining the attributes and going, okay, yep, 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 wanna start with the methods that the class space 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 the classic class space 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 space 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 post. 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, or yes, the questions that I was hoping you would find easy at this point, 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 wanna 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 gonna be really unhappy with you. When is Django deprecating function views? It's not, right? The idea behind a view is, accepts specific input, provides 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 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 there for 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 method 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, 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, 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, it honestly is really your preference, because at that point, 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 using a class method over a function view, class view over a function view? There might be a small performance hit, but that's not really where your performance problems are going to be, right? Typically your performance problems are going to be in IO. Okay, cool, thanks. No? Hi, so I'm wondering about, let's say for example, you have a model or an object of a model such as a task and you can perform different modifications on it, right? So I guess you would use 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 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 a sort of simple ticketing system, right? Sure. And then the person updates it and so they post 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.