A More Accessible Django Girls
Published July 11, 2015
This video features Lacey Williams Henschel at PyCascades 2021 in Online.
Lacey Williams Henschel
https://pretalx.com/pycascades-2021/talk/NH8C8U/
My goal with this talk is to make Django REST Framework easier and more approachable for developers who are new to DRF. Many people feel that you should start in DRF with the APIView and a manual serializer, but I disagree! DRF ships with some powerful tools that make developers' lives easier, and many people never even learn what those tools are. Using the built-in tools like ModelViewSet, coupled with always having Classy DRF open in a tab, helped me gain a full understanding of how DRF worked (and a better understanding of how Django worked).
This talk is not a DRF tutorial.
ModelViewSet and how it's composed of all the mixins that allow you to perform different operations on your database objects (CreateModelMixin, RetrieveModelMixin, etc.).permission_classes, queryset, and serializer_class.get_serializer_class() to return different serializers for List vs. Detail requests.permission_classes to create modular permissions. Note: This will not cover how to write custom permission classes, only how to use them.APIView and the necessary mixins. Notes on when you might use them (example: you want a viewset that allows all actions except delete)I will be referring to Classy DRF throughout the talk. In my experience, many people find the Classy Class-Based Views, Classy DRF, and that family of helper websites confusing, until they learn how to use them. I want to help the audience learn to use these tools.
Note: This is a new talk for me. I tend to rehearse my talks a lot, so if time is too tight I will know that ahead of time. The section I would cut for time would be "Overview of the generic views," because this idea will be introduced in the ModelViewSet section.
After three amazing in-person conferences, this time we're moving PyCascades online.
PyCascades is a regional PyCon in the Pacific Northwest, celebrating the west coast Python developer and user community. Our organizing team includes members of the Vancouver, Seattle, and Portland Python user groups.
Videos are released as CC BY-NC-SA 4.0.
Produced by Next Day Video Australia: https://nextdayvideo.com.au
#pycascades #pycon #python #conference
Sat Feb 20 11:05:00 2021 at Prerecorded Talks
Lacey Williams Henschel explains how Django REST Framework viewsets are assembled and where to customize them. She focuses on `ModelViewSet`, its CRUD mixins, core attributes and methods, serializer selection and context, and the value of tracing DRF’s source with Classy DRF. She shows how to choose a smaller mixin combination, use `self.action` to select serializers, customize creation responses, and add specialized endpoints with the `@action` decorator. Her main argument is that understanding the framework’s inheritance and processing flow lets developers make small, targeted changes instead of rebuilding API behavior from scratch.
Summarised automatically from the transcript.
Automatically transcribed, so expect mistakes in names and technical terms.
Speaker 1: Hey everyone, I'm glad you're staying here at the Pur Record Talks at the Pi Cascades event. And I want you to introduce you all, uh, Lacey, Lacey Williams Henschel, who will give us the talk, What You Should Know About Django REST Framework. So Lacey, how are you doing?
Speaker 2: Hi, I'm good. How are you?
Speaker 1: I'm really great and excited about this event and this talk in particular, because I I believe it's really important for us all. So uh tell tell me Lacey, what inspired you to make this talk?
Speaker 2: Um yeah, whenever I started working in Django Rest Framework, I had never done anything like that before and um I've really enjoyed the work that I've done with it in the last three years, but I haven't ever done a talk on it. I haven't really blogged very much about it, so I wanted to um share what I've learned over the last few years.
Speaker 1: Oh, awesome. And what really excites me the most is the fact that you are sharing us your experience. And I I believe that's really important. And as it has a lot of value. Um so we we can learn a lot about it. Um uh since uh right now at PyCascades we are people scattered around all the world where are you located right now?
Speaker 2: I'm actually in Oregon, so if Piecascades were being um held in person, I don't know if it would be Portland's year, but it would be very convenient for me if it were. Um I'm outside of Portland, though. I'm in Newburgh, which is about an hour outside of Portland
Speaker 1: Great, right. So before we begin, um I I'd like to know if you have um I believe there are there's a lot of advice you can give us in your talk, but I would like to know if you have um uh an advice for us who are learning about Django because I'm a Django beginner right now.
Speaker 2: Um my best advice is just don't be able don't be afraid to Google things constantly. I have um the docs or a specific website that I talk about in the talk open all the time whenever I'm coding in either Django or Django Rest framework. So um never feel bad about needing to look something up. We all have to do it all of the time.
Speaker 1: Awesome. And and I believe that we should point that Django and Django REST framework are different things. So we have take that in consideration when we are beginning. So uh we're almost ready to begin with the talk and I remember that you can um interact in the chat of this talk. And at the f uh once we finish the the talk, you can go to the um QA room for um to interact with the speakers and other attendees here at Venu list. Remember we are uh answering questions in venue list. So I believe we're almost ready and so we can begin.
Speaker 2: Awesome Hi, I'm Lacey Williams Henschel and this is What You Should Know About Django Rest Framework. I'm a software engineer with a consultancy called Revsys, and for the last three and a half years, most of what I have done is write APIs using Django REST Framework. And this talk is a lot of the things that I wish I had known whenever I first started writing DRF code. But you really should know that we're not going to be talking very much about serializers today. Mostly we're talking about view sets. So this talk really should be called What You Should Know About Django Rest Framework. ViewSets edition. I have so many things to say about the views. py that I couldn't fit anything else into this talk, but I may try to sneak in a serializers talk sometime later
Speaker 2: Another thing I want to introduce you to in this talk is a wonderful tool called Classy DRF. This is a site that breaks down the inheritance chain of all of the main classes in Django Rest framework. So all of the views, view sets, serializers, and mix-ins are all right here on this website. When you click on one of the classes, then you get to see a lot of information about that class So right here for the generic view set, you can see its entire inheritance chain, all of its ancestors, all of the classes that inherit from generic viewset, and then you see a list of its attributes. If you keep scrolling, then you'll also see a list of all of its methods, and you can click on all of those to expand them to see the source code for those methods.
Speaker 2: Now, at first glance you might think, how is this different than just reading the source code in GitHub or something? But hopefully by the end of this talk, you'll be consulting this website regularly. I do want to shout out to VintaSoftware for maintaining this tool. I use it literally every day. Also Django Rest Framework has really good documentation. The docs are pretty well organized and thorough, so if you're new to Django Rest Framework, I highly recommend starting with their tutorial and then reading through their docs. Most of this talk is summarized on this page on ViewSets, so you can save yourself 20 minutes and just go ahead and read that page and skip the rest of this talk. But I hope that you'll stick around because I do think that I have some insights that will make this page make even more sense to you
Speaker 2: So Django Rest Framework is a lot like Django in that it ships with batteries included. And one of the most powerful of those batteries is the model view set. The model view set is really like a battery pack in that it contains a lot of different things that make it really powerful If you have any experience with Django's other class-based views, then the view sets in DRF will probably look a little bit familiar to you, but they do work a little bit differently. So a view set is what it sounds like. It's a set of views that let you do a bunch of different things. The model view set is a view class that contains the methods for a lot of different actions that a user might want to take with your API. The Django Rest framework docs define the view set as a type of class-based view that doesn't provide method handlers like get
Speaker 2: and post. but instead provides action-based methods like list and create. So the model viewset includes endpoints that let you create, retrieve, update, list, and destroy objects in your database. So, this is what the model viewset is composed of. The model viewset inherits from the generic view set that includes a lot of useful attributes and methods that you'll need to know about, and we'll go over in a little bit. And also these five different mix-ins, create model mixin, retrieve model mixin, update model mix-in, destroy model mixin' In and list model mix in. So you can see that this sets up the basic CRUD endpoints, those create, read, update, delete endpoints for one of your models.
Speaker 2: Now, the model viewset, like we said before, doesn't deal directly with get methods and post methods the way that Django's class-based views do. Instead, each model mix-in class has its own action-based methods that perform the right functions. So the create model mix-in has a create method instead of a post method. The list model mix in has a list method instead of a get method, etc. So what this means is that these six lines of code are enough to get us started with a fully functional and working API. We just need to import the model view set, import our model and our serializer, and set up our our own view set that inherits from model view set, and then set two attributes on that class, and we're good to go.
Speaker 2: Now I said that I wasn't going to talk about serializers today, and I'm really not. But if you're new to Django Rest Framework and you don't know what a serializer is, that's okay. A serializer is a class that you use to format your Django model objects into the JSON that you'll be sending back in your response. You can use serializers for other things than just model objects. You can serialize anything, but the application we're talking about is specific to model objects. So these six lines of code wind up giving us these six endpoints. We have a list endpoint to get all of our books. We have a retrieve endpoint to get just one book by its ID. We have an endpoint to post or create new books. We have two endpoints to update a specific book, so we can do a full update or a partial update.
Speaker 2: And then we have an endpoint to delete a specific book. Now you do need to add your view set to the URLs. py file, and we're not going to go over that today. That's in the DRF tutorial. But those six lines of code that we had on the prior page Plus your URLs. py file gives you these six endpoints that work perfectly well There are some attributes that you need to know about the model viewset before you can get started though, so we're going to talk about those in a little bit more detail now. First, you need to tell your model viewset what objects that it's working with, and you do that by setting the query set attribute. So you'll import your model And then you'll set the query set attribute to a specific query set that's based on your model. Most of the time you'll just retrieve all of your objects, but sometimes you might want to put a filter or a manager method or something in there
Speaker 2: The second question that you need to answer for your view set is how should this data be serialized? When you send your model objects back in the response, what should that JSON look like? And you do that by setting the serializer class attribute. And then finally, you want to set who's allowed to use these endpoints that are created by your model view set Our permission class right now we've set to allow any. It's not a required attribute. If you leave it blank, Django Rest framework will provide a default for you. But most of the time you're going to want to be explicit about who is allowed in your endpoints. Okay, now let's talk about some of the methods that are coming with your model view set that come from that generic API view
Speaker 2: class. The first of these is the getQuery set method, and really all it does is return whatever you set in your queryset attribute. And that's not very exciting at first glance, but this is a useful method to know because you'll override this method pretty frequently to do some extra filtering. So for example, you might want to override get query set when you need to filter your query set based on some information that you don't have until the request is made. Maybe you want to filter based on something about the user, but obviously the user doesn't exist until they've made a request. The second method is the getObject method. Now really all this does is for your endpoints that take some kind of ID or other identifier.
Speaker 2: It just performs that lookup and returns you the object. It does this by getting the query set, calling the getObject or 404 method, so it will raise a 404 on your behalf. if this object isn't found. It'll check permissions for your object. And if this user doesn't have permissions for this object, then it will raise a permission denied error on your behalf. And then it gives you back your object. Now this is not a method that I wind up overriding very often. It works perfectly well on its own. But in your own methods, whenever you're doing extra work to customize your view set You can call self. getObject on your detail methods to have Django Rust framework take care of all of that logic for you That way you don't accidentally skip a permission check or you don't accidentally forget a step.
Speaker 2: You don't have to worry about the 404. Just let Django Rest Framework handle that. Then there are three methods that have to do with serializers. Django Rest Framework has broken up giving you your serializer into three separate steps, so we're gonna go over those. The first is the getSerializerClass method, and this is very simple. All it does is return whatever you set in the serializer class attribute. This is another one of those that's useful to know though because you'll wind up overriding it pretty frequently. So if there's a situation where you want to use a different serializer for one endpoint than the other endpoints You could put that logic in your getSerializerClass method. Then there's the getSerializer method What the getSerializer
Speaker 2: method does is get whatever serializer is returned by getSerializer class, but then it calls this getSerializerContext method. So let's jump into that and see what that does. Okay, so getSerializerContext returns this dictionary that includes some stuff. The most important of these things that I wind up using is the request. So we get this dictionary back and oh yeah, before I go on, I want to point out why I've told you about get serializer context. So you want to know about get serializer context because that is some data that's included with your serializer. And sometimes You need to access some data in your serializer so that you can do some other processing. So if you need to add special data to your serializer, then you can do that by overriding get
Speaker 2: serializer context and adding it there. I recently had a situation where it was more efficient for me to do some math up front in my view set and pass the results of that math into the serializer context. and then finish up that math per object in my serializer. So that's an example of when you might want to add something to your serializer context. Also, um I just wanted you to know too about self. getSerializer. This method, and we can go back a couple of slides to look at it. The self. getSerializer method then returns that serializer class with the serializer context, so with that dictionary. What this means is that in your own methods, you can run self.
Speaker 2: getSerializer to retrieve your serializer instead of invoking your serializer directly. And that means that the serializer that you're using has already passed through the logic to decide which serializer is getting used. And it's already passed through the logic that is adding the context. So you have access to the request, which contains the user. You have access to any other custom information that you put in the context. So it's a lot more efficient than having to gather all of those pieces yourself in a serializer that you invoke directly. Okay, now let's talk about some of the methods that come with those mix-ins in model viewset. So everything we've talked about so far has been some basic methods that come with the generic viewset.
Speaker 2: But now we want to talk about like the create method, the list method, those kind of action-based methods. So if we look at classy DRF, Then we can see that there are three methods that come with the create model nixin. We can see create, get success headers, and perform create Get success headers is not one that we really need to worry about. I've never needed to worry about it. Um, so we won't talk about that today. But we do need to know about create and perform create. Okay, so let's look at what create does. This is the create method that comes with createModel Mixin. First, it calls self. getSerializer and it passes in the data from our request. Then it validates the serializer and it will raise an exception on our behalf if something is wrong.
Speaker 2: Then it calls this perform create method, so let's hop over there Okay, so all performCreate does is call serializer. save. It doesn't return anything or do any other processing. So hopping back over to the create method. Then we call to get the success headers and we return the response with the serializer information and our status code. And that's all the create method does. The other methods that come with the other mix-ins, so the list model mix-in, the destroy model mix-in, they'll be similar. They'll they'll obviously be a little bit different depending on what they're doing. But each one of them will have this method, you know, create or list or retrieve, and then this, you know, perform destroy, perform , update, you know, things like that.
Speaker 2: So at this point you may be wondering why we've spent all this time going through a bunch of source code. And the answer is that if you know what the main methods are that do the processing if you know what's going on with what Django Rest framework ships to you then you know where you can customize to do what you need So you can just pull out a tiny piece of the Django REST framework code, tinker with it, and put it back without having to reconstruct an entire API by yourself. Okay, so let's trace through some examples so you can see what I mean. So let's say we have a situation where we have a lot of information. We want a lot of information for our detail endpoints, but only some information for our list endpoints. So basically we want to use different serializers for the list endpoint and the the retrieve endpoint.
Speaker 2: Maybe in our situation on the list endpoint we want the title and the cover and the author's name, but on the detail endpoint, we also want to add the reviews and other editions of the book and links to other books the author has written. You know, we want a whole other host of information for the detail page. So we do this by importing both serializers and we set the serializer class attribute to one of them. In this case, I'm going to say that my default serializer is going to be the detail serializer Then we override getSerializer class. We add our own version of the getSerializer class method. And we can um Inspect these actions. So remember instead of get and post, we're dealing with these action methods, and those actions are available to you in self.
Speaker 2: action. So whenever a request is made, the self. action attribute will tell you what kind of request it is. So we're asking if self. action is in list then return the list serializer. Otherwise return super, which basically just means return whatever you were going to if I hadn't done anything. Okay, now a slightly different situation. Let's say that we do want to use two serializers, but it's not for two different actions. We want to take in a new book um using one serializer, but give it back to the user with a more detailed serializer. Maybe whenever we create new books, there's some processing that we do on the back on the back end and so we want to send back the results of all of that processing.
Speaker 2: So just to refresh your memory on what the create method does, it gets the serializer, validates it, calls perform create, which saves the serializer, and then returns all of the data. So the part that we want to tinker with is this self. perform create and also the the serializer data that we are returning. So we're going to pretty much copy and paste the entire create method from classy DRF into our own book view set. And we're going to leave everything there except we're going to comment out the self. perform create call. We're not going to do that. Instead, we're going to call serializer. save ourselves and we're going to save the result of that in the instance variable. Now something important to know is that the serializers
Speaker 2: save method returns the object that was created. That's important because that's how this works. We want to have that new object available to us. So we've commented outperform create. We've saved our new book in a variable called instance. And now we're going to invoke our return serializer, the book created serializer. And we're going to call that return serializer, and that's the data that we're going to return in that last line. Okay, let's say that we have this view set, this model view set that gives us these six endpoints, but we don't actually need all of these endpoints. We only want some of the endpoints. So if we want to do everything except
Speaker 2: delete, for example, um this is what we would do. We would kind of construct our own Frankenstein view set using whichever mix-ins made sense for our purposes. So in this case we've imported the generic API view. And then we've also imported the create, retrieve, update, and list model mix-ins, but we've left out the destroy model mix-in And so yeah, we can create our view set with just those, and this will provide us with those five endpoints, all of them except the destroy endpoint. But Django Rest Framework knows that this is something that you might want to do, so it's provided a lot of these combinations as convenience classes for you. So for example, there's the update API view, which is the generic API view plus the update model
Speaker 2: mix-in. And they've also gone ahead and given you create, list, retrieve, and destroy all by themselves Plus, they've given you a read-only model view set, which is just list and retrieve. So just the two get endpoints, basically. And then they've given you a couple of convenient combinations. So retrieve and destroy, retrieve, update and destroy, list and create, and then retrieve and update. So if if any of these classes suit your purposes, then you can use those instead of creating your own Okay, this is the last big thing that we're going to talk about, and it's constructing your own special endpoints. Let's say that you want a special endpoint that only shows your featured books for this particular month.
Speaker 2: Now, you could do this on your own. You could create your own view class and make make your own query set and add it to sorry You can do this on your own. You can create your own class that you add to your URLs. py, and that will work perfectly fine. But Django Rest Framework has provided you with a way to add custom endpoints to your existing viewsets. And those are called actions. So I'm gonna take a moment here and I'm gonna move my video There we go. That's better. Now you can see the whole screen.
Speaker 2: Okay, so this is the code that we will need to make our custom action. So let's walk through it. First, we want to import the action decorator and use that decorator on the method that is going to perform all of our logic. Now the Action Decorator takes a couple of arguments. The detail argument, which tells Django Rest framework whether this particular endpoint is dealing with a list of something or with one specific object in your database Then we have to tell Django Rest framework what HTTP methods are valid to call this endpoint. So I know I told you that Django Rest framework doesn't deal with the kind of get and post methods the way that the other Django classes based views do and that's still true but you do still need to let Django Rest framework know what to expect whenever this endpoint is being called
Speaker 2: and you do that with the methods argument The Action Decorator does take a lot of other arguments that are optional, and they are really powerful and really useful, but we're not going to go through them all right now. Now this decorator on top of this method gets you this endpoint slash book slash featured. The reason it's called featured is because that's the name of our method and that is one of the things that you can customize with an extra argument to the action decorator. Okay, so we have our featured method, and the first thing that we're going to do is call self. getQuerySet to get our books. But we're going to filter that. So we have a field on our model called featured, and we're just going to get all of the ones where featured equals true.
Speaker 2: Then we're going to call getSerializer so that we can perform all of that logic to get the serializer context, but also select the right serializer. And speaking of selecting the right serializer We want to use our list serializer for this particular endpoint. So we can edit getSerializer class to add the name of our endpoint, the name of our action. to that list of actions that get the book list serializer. And then finally we're going to return the serializer in our response. And that's all we needed to do to get our own custom endpoint. We didn't need to write a whole separate class or touch our URLs. py file at all. So that's all I have for you today.
Speaker 2: I do want to thank several people for um for their help with this talk. I want to thank Tom, Christy, and the maintainers of Django Rest Framework for making such a great library. Vintage Software and the maintainers of the Classy DRF website, which I find indispensable. My friends Becky Post and Jeff Triplett for their help with this talk. the Vancouver Pi Ladies Group for letting me preview this talk and all of you at Pie Cascades. I'm gonna leave my contact information up here for a moment so you can screenshot it If any of this sounded like something that would be useful to you, then definitely feel free to contact me or contact Revsys. We would love to help you out with your API needs. And I hope you have a great rest of the conference. Bye-bye
Speaker 1: Really amazing and illustrative talk. Actually everyone at at the chat loved the talk. They were asking for the slides. They were wanting to know more. It was very, really amazing.
Speaker 2: I will drop the link um to the slides in the chat here in just a second.
Speaker 1: Awesome. Also
Speaker 2: anyway.
Speaker 1: Also remember that if you have questions, you can go to the Q<unk>A room channel here in Venuless. And once again, thanks a lot, Lacey, for this talk about Django Res framework and everything we should know about it. And remember that the next talk will be enhancing Civic Data with Elasticsearch, Pandas, and Elant with J. Miller. After this little break of 15 minutes, remember we are coming back at 11. 45. So um amazing lazy. Everyone, love it. Congrats for it.
Speaker 2: Thanks. I'll see y'all in the the QA room.
Speaker 1: Okay, see it there.
A ModelViewSet is a class-based view that bundles action methods for creating, retrieving, updating, listing, and deleting model objects. It combines GenericViewSet with several model mixins to provide standard CRUD endpoints.
Discussed at 5:38Define a viewset inheriting from ModelViewSet, import the model and serializer, and set the viewset’s `queryset` and `serializer_class` attributes. After registering the viewset in `urls.py`, it provides list, retrieve, create, update, partial-update, and delete endpoints.
Discussed at 7:14The main attributes are `queryset`, which determines the objects the viewset works with; `serializer_class`, which determines the response and input representation; and `permission_classes`, which controls who can use the endpoints.
Discussed at 8:51Override `get_queryset` when the queryset needs request-dependent filtering, such as filtering objects based on the current user. The method normally returns the viewset’s `queryset` attribute, but it can add filters or invoke a manager method once request information is available.
Discussed at 10:30`get_object` looks up an object from the queryset, raises a 404 if it does not exist, and checks object-level permissions. Calling it from custom detail actions lets DRF handle those checks and errors consistently.
Discussed at 11:18Override `get_serializer_context` and add the extra data to the context dictionary. Serializers receive that context along with the request, so custom calculations or request-specific information can be shared with serializer logic.
Discussed at 13:43Override `get_serializer_class` and inspect `self.action`. Return the lightweight list serializer for the `list` action and fall back to the default detail serializer for other actions.
Discussed at 17:37Customize the `create` method, call `serializer.save()` yourself, keep the returned object, and serialize that instance with a second, more detailed serializer for the response.
Discussed at 19:13Instead of using `ModelViewSet`, combine `GenericAPIView` with only the model mixins you need, leaving out unwanted operations such as destroy. DRF also supplies convenience classes such as `ReadOnlyModelViewSet` and several predefined mixin combinations.
Discussed at 20:46Use DRF’s `@action` decorator on a method, specifying whether the action applies to a detail object and which HTTP methods it accepts. The method can filter the queryset, select a serializer, and return the response without requiring a separate view class or URL entry.
Discussed at 23:06Note: 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 May 23, 2026
Published February 26, 2025
Published April 11, 2023