Goodbye Print, Hello Debugger! by Nina Zakharenko
Published October 25, 2019
This video features Nina Zakharenko at DjangoCon US 2014 in Portland, Oregon, USA.
By, Nina Zakharenko
Django REST Framework can make creating a RESTFUL api quick and easy.
Join me as I go over: - What makes an API Restful - How Serializers can make representing your existing models in JSON a breeze - What the built in Views provide for you, and how to provide authentication for your API - How to route to your new Endpoints - Last but not least, how to Unit Test them
Help us caption & translate this video!
Django REST Framework (DRF) provides conventions and reusable components for building HTTP APIs. Nina Zakharenko explains REST concepts, HTTP methods and status codes, then shows how serializers represent and validate model data, permissions restrict access, and viewsets or generic views implement endpoint behavior. She also covers requests, responses, routing, the browsable API, and API testing, arguing that DRF is especially productive for new projects with straightforward models, while complex or legacy systems may require more customization.
Summarised automatically from the transcript.
Automatically transcribed, so expect mistakes in names and technical terms.
Speaker 1: Everyone, uh welcome to Django Khan and good morning So uh this talk is a novice level talk, and my purpose is for novices to get familiar with the terminology of APIs. And for me to give them the confidence to explore Django Rust framework on their own. So What is rest? What is restful? It kind of gets talked about a lot. Really, it's just an architecture. And for the purpose of web APIs, it has a few properties that define a RESTful API. It has to be stateless.
Speaker 1: So, you know, the client doesn't have to maintain any sort of knowledge about the server. Each request is kind of made as if it were fresh. It supports common HTTP methods. such as uh actually we'll see some on the next slide. And uh it returns internet media types like JSON or XML. So HTTP verbs, these are the uh five of them. We have uh post, get, put, patch, and delete. It's like CRUD, sort of, not quite. So we use them to perform operations on different endpoints.
Speaker 1: And our endpoints are going to look kind of like this. So that first endpoint, if we call a get on it, it will return a collection of all users The second endpoint, we want to pass it an ID, and it will return, if we call a get on it, it will return the single user at that ID. So some of the other HTTP verbs, how would they look like if we called them on these endpoints? If we called a post on our first endpoint, it would create a new user. If we called a delete on an endpoint with just an ID, it would delete that single user
Speaker 1: If we call delete on our users collection, it will delete all the users. So not very good. And here are some common HTTP response codes, that uh response codes that you'll probably see when you're using your API. So 200 is okay, 201 if you call a post on an endpoint and a 201 is returned, that means that resource was created. 401 is not authorized, so the endpoint requires some sort of authentication like a token, and you do not provide it. 404, common one. The server did not find the resource that you requested.
Speaker 1: And 500 is a server error So I am potency. It's a hard-to-pronounce word. What it means is that the operation produces the same result no matter how many times it is repeated. So put and delete. Item potent? Well, get is a safe method. It might not return the same result every time, but by calling it you're not modifying any resource. Um you're knowing that the server isn't kind of doing anything funky to uh mess with that object that you're trying to get. So here is where DRF comes in. DRF is Django
Speaker 1: Rest framework and it makes API creation really, really easy. So serializers can kind of be thought of as Django forms. They're a guide to representing your data over the wire. You're telling DRF how you want that data to look. So here we have a model of a tweet. It's very simple. We have a foreign key to user. We have some text. The maximum length is 140 characters, and we have a timestamp. So to represent that data, we're going to want to make a serializer for this model
Speaker 1: So we're going to tell our serializer that the user comes from the source field user. And in the meta is where we define which model we're trying to serialize and what fields. on that model uh we're trying to represent. Non-model serializers are also available if you kind of have a bunch of random data and you want to create an endpoint out of it you can create a serializer but uh that nice fields uh Field set won't be available to you, you'll actually have to define every serializer one by one. So when we pass our data through our serializer, this is what our result will look like.
Speaker 1: If we support if I if we configure DRF to send back JSON responses, which are the default, can also pass back XML And that's just a simple setting. You don't really have to change any of your code. So DRF supports really great validation. And here's what a field validator looks like. So an interesting thing to note is that it kind of but by creating a method called validate underscore text It automatically knows that this validator is for that text attribute.
Speaker 1: There's no configuration here, it's just kind of a naming convention. So here we're getting our source attribute out of the list of values, and we're checking to see if the length of it is less than five. You know, if it is, we're going to send back a validation error that says the text is too short, we're going to get back an error response in our API. Other kinds of validators that are available is an is valid. If you add that method to your serializer, you can actually validate a combination of attributes. For example, if you have a start date and an end date, you would uh and you want to make sure that your end date, you know, isn't before your start date, you would put that validation logic in your
Speaker 1: is valid. method. And if you want to make sure that your serializer is valid, you can call that method on it. Pretty similar to a Django form. So permissions. Let's say we only want to let authenticated users see our list of tweets. So is authenticated is actually a built-in permission in Django Rest framework and uh does what it says. It only allows authenticated users to hit that endpoint. Another bolt-in line is admin user, and it checks to see if the user is actually a staff member or not. Creating your own Validate or I'm sorry
Speaker 1: permissions are actually very easy. Let's say we only want the author of the tweet to be able to edit it. So we create our own permission. We base it off base permission, and we create a method called has object permission. So We before our endpoint is hit, that object is passed into this permission method. And we check if our method is in the safe methods, such as get Go ahead, let them see it. If they're trying to call something destructive, like a delete, make sure that the object user is the same as the request user. So views are um
Speaker 1: really interesting topic in DRF. Uh The easiest one to kind of get a grip on is called a view set. Here's an example of a model view set. So we only have to define a few simple variables to be able to use this endpoint. We have a query set, so that's how do we get a collection of the items that we're trying to view. We define our serializer, and we define a list of permission classes So you can provide a set as long as you like for each of your endpoints. We can also define a handy pre-save method. So that gets called before the object is saved to the database.
Speaker 1: And we want the user of our tweet to be saved as the request user. So the model view set is Kind of the whole shebang in one. Behind the scenes, it supports all of the operations on an endpoint. So you can get one tweet by an ID, you can get the collection of tweets. You can delete, you can modify, and that's kind of all given to you by using this class. It's really handy. So, model view sets are awesome when you're working with models, but sometimes you have to break things down a little bit more. So
Speaker 1: Django S framework provides us generic views. API view is the base class, kind of takes care of all the routing. So if you're calling get, it'll call the get method. And mixins provide common operations. So, and there are some generic views that are provided for us that kind of have a common combination of mixins. For example, if you're only supporting an endpoint that has a list of objects, then you would call the, I'm sorry, you would use the list create API view. And it would uh support get and post for you. And you would kind of have to fill in those details
Speaker 1: Requests in Django REST framework actually look pretty similar to many of the methods that we're used to seeing. So if you guys have used Django Forms, you're used to seeing a request. post. And that's the data that comes in when a user submits your form. Request. data is kind of similar. It provides all the fields that were submitted to the API along with their values. handles the data types we specified. I pretty much exclusively use JSON, but some of you might like XML. And responses are
Speaker 1: also kind of similar, but not really. So Django uh REST framework responses are actually completely unrendered You're getting a bunch of data back and it's up to you to figure out how you want to consume it. So, you know, maybe you're using jQuery on your front end to call this uh endpoint. Maybe you're using Angular or another JavaScript framework. But what's going on behind the scenes when you call or uh when you want a response back, if you're using a serializer , Is your query set, those tweets are being passed into the serializer? The serializer does its work and spits out That JSON
Speaker 1: representation, and then you call response with that serializer data. By calling response with no status code, you're actually just sending back a 200 If uh if you wanted to process a request with your serializer, you would pass that request data into your serializer. and then call serializer. isvalid before actually performing the save. Otherwise terrible things happen. So let's talk a little bit about routing. View set routing is absolutely the simplest. So we have a uh what's called a default router, and we register our viewsets with it.
Speaker 1: The nice thing about using a default router is we can pass all sorts of configurations to it. For example, um If you don't care about appending trailing slashes, that's a property that you can pass into default router on instantiation. So when you register your view sets, all you need to do is include the router URLs in your URL patterns. And what that gives you is the whole shebang. You have uh tweets multiple endpoint, you have a single tweet endpoint, and then you support all the operations on those endpoints as well the get The post delete uh kind of with just this.
Speaker 1: So without V sets You're going to be setting up your routing in a default way. So you would create a name for your view and then register each URL pattern. The browsable API is uh really one of the strongest features of um the Django Rust framework. So it gives you a API endpoint that you can kind of hit and instead of getting just of a NOAA JSON response, you'll get um you'll get this kind of interactive page and you can see all the methods that are available on your endpoint
Speaker 1: via that get. You can hit it, you can provide data to it. I think we actually have time for a little bit of a demo. So let's see, make sure my server is running. Oops. I was messing with my code, so no. Sorry about that guys. It's kind of the uh Kind of what happens when you do live demos
Speaker 1: when you're talking, right? Something is always broken. So here's an example of uh thorough data that you can pass in. You'll make sure you have to make sure that your the data that you're passing in is valid JSON and then it matches the fields in your serializer Or Django Rest framework provides this handy-dandy HTML form. So it provides the correct input box for the data you're trying to pass in. Unit testing. Everyone loves the testing goat. It's important.
Speaker 1: So in our past few slides, we defined this field validator that tests and makes sure that our The tweet that someone is trying to submit is more than five characters or it's invalid. So here we're creating a a test for that validator. And let's walk through it one by one and uh see what's going on. So we define our API client, which again has many useful methods for available for us for unit testing. And here we're um We're logging in, we're authenticating uh a request. So if we didn't pass that in
Speaker 1: And we have an authentication permission, then we would get uh 401 back, not authorized. We're getting the URL for our endpoint. We're making up some test data. So this will print out four X's and we're posting to that URL to create a new tweet. And we assume an error message. So we want to assert that the status code is 400. That means bad request. your data isn't valid. We want to ensure that the error message is the same one that we provided in that validation exception.
Speaker 1: So I've been using it pretty extensively for the past few months and definitely have uh You know, some feedback. So the best place to use it is new projects. You don't really have to code for the framework or around the framework. You can use some of the really powerful tools that are available, such as those view sets. You have clean models Not a ton of interdependent validation going on. In that case, it's it's really just excellent. It saves you so much time. So, when not to use it, legacy Django is out there.
Speaker 1: If you have a ton of complex models, interdependent validations. If you're trying to save non-model fields in your endpoints, things really kind of get tricky. You don't get to use that nice view set. You kind of have to break out and use those generic viewsets and customize your code to deal with some of these complexities. So doesn't mean you shouldn't go for it, but really there might be hurdles. On the bright side though, um Django S Framework Three is on the horizon
Speaker 1: and Apparently they're going to be fixing some of these issues that I've had and you know redoing the serializers completely. So don't discount it, keep an eye out for it, but just prepare for some issues. So next steps for you guys, pip install Django Rust framework. The documentation is really good. The tutorial is very thorough. Hopefully I've familiarized you with some of the terminology that you'll be seeing And that is it for me. Thanks, guys.
Speaker 2: Thanks so much Nina. I think we do actually have time for perhaps one or maybe two unbelievably brief questions. So if somebody has a a snappy one ,
Speaker 3: Thanks, great talk Nina. Um I just wanted to quickly ask yeah, um is there any sort of particular pattern you think that doesn't work with models with APIs in general? Like sort of sort of uh past complex relationships or sort of foreign keys, like what would your advice to new programmers on how to handle that kind of sort of more complex model structure?
Speaker 1: Um I I've been able to do it uh you know before a few hiccups. It's it definitely still helps to have those built-in things like those generic API views so you don't have to write a bunch of code to be like when this request is get, do this. And the API browser has been such a powerful and helpful tool that it's It's still worthwhile kind of exploring it even for more complex data models.
Speaker 3: Thank you.
Speaker 1: Okay.
Speaker 4: fit or if you had old code it was not fit. I I was wondering if you thought that in some ways um because it's something that I've looked at and I I actually have two of those issues. a little bit with an older code base. But I was wondering if you thought it was able to it it was practical to break out certain components like the serializers, if you thought that was practical or if it's actually kind of pretty tangled up together or and if you had any if that question sort of made sense. If it's possible to sort of use some components even If you can't use the whole thing because of this.
Speaker 1: I I actually tackled that problem with a very complex model both ways, with a serializer and without a serial serializer. Using the serializer required at hack is kind of out of the scope of this talk, but I'm happy to talk to you about it afterwards. Um, and it really did provide some nice things. For example, um field level validation, like if I said my serializer only accepts 140 characters instead of the model, it would kind of throw back that correct error. Whereas if I didn't use the serializer, I'd have to do all that kind of plumbing myself.
Speaker 2: All right, Nina, thank you again.
It is an API architecture that is stateless, uses common HTTP methods, and returns media types such as JSON or XML.
Discussed at 0:20They perform operations on resources: GET reads them, POST creates them, PUT and PATCH update them, and DELETE removes them. For example, GET on a collection returns all users, while GET on an ID returns one user.
Discussed at 1:05200 means OK, 201 means a resource was created, 401 means authentication is required or invalid, 404 means the resource was not found, and 500 indicates a server error.
Discussed at 2:38Django REST framework (DRF) makes creating APIs much easier by providing serializers, validation, permissions, views, routing, and other reusable tools.
Discussed at 3:49Serializers define how model or other data should be represented in an API, much like Django forms define and process form data. A model serializer specifies the model and fields to serialize, while non-model serializers require fields to be defined individually.
Discussed at 4:09A method named `validate_<field>` performs validation for one field, while `validate` can check relationships between multiple fields. Call `is_valid()` to run the serializer's validation before saving or using the data.
Discussed at 5:45Built-in permissions such as `IsAuthenticated` and `IsAdminUser` restrict access based on authentication or staff status. Custom object permissions can allow safe methods for everyone but require the object's author to perform destructive actions.
Discussed at 7:21A ModelViewSet combines the common CRUD operations for a model in one class. By defining a queryset, serializer, and permission classes, you get collection and detail endpoints that can list, retrieve, create, update, and delete objects.
Discussed at 8:52Use generic views when you need to break an endpoint into more specific behavior. DRF's APIView handles routing to methods such as GET, and combinations such as ListCreateAPIView provide common operations like listing and creating objects.
Discussed at 10:23`request.data` contains the fields and values submitted to the API, similar to `request.POST` in Django forms. A DRF response contains unrendered data, which can then be consumed by a client such as jQuery or Angular; serialized data is commonly returned with `Response(serializer.data)`.
Discussed at 11:08Register viewsets with a DRF router and include the router's URLs in the project's URL patterns. The router creates collection and detail routes and wires up their supported operations automatically.
Discussed at 12:40It is an interactive HTML interface for an API endpoint that shows available methods and lets you submit data, rather than returning only a raw JSON response.
Discussed at 14:16Use DRF's API client in unit tests to authenticate, construct test data, call an endpoint, and assert the status code and returned validation errors. For example, invalid tweet text should produce a 400 Bad Request and the expected error message.
Discussed at 16:35It works especially well for new projects with clean models and little interdependent validation, where viewsets can save substantial time. Legacy code, highly complex models, cross-field validation, and non-model fields can require generic views and more custom plumbing, although DRF can still be useful.
Discussed at 18:10Yes, but it may involve some hurdles and custom work; generic API views remain useful for complex relationships. Serializers can also be introduced selectively, providing conveniences such as field-level validation without requiring the entire application to be rewritten.
Discussed at 21:05Note: We understand that names change, people change, and bodies change. We respect each individual's journey and privacy. If you have any concerns about a video or need us to remove content, please don't hesitate to contact us. We will handle your request with care and promptly address any issues.
Published July 15, 2026
Published July 15, 2026
Published July 15, 2026
Published July 15, 2026
Published July 15, 2026
Published July 14, 2026