Hint: You can adjust the default video playback speed in your account settings.
Hint: You can set the default subtitles language in your account settings.
Sorry! Looks like there’s an issue with video playback 🙁 This might be due to a temporary outage or because of a configuration issue with your browser. Please see our video player troubleshooting guide to resolve the issue.

DRF ViewSets

Give Feedback

00:00 In the previous lesson, I talked about the Django REST Framework serialization mechanism and how to use the @api_view decorator to create a view. In this lesson, I’m going to be drilling down more on views and introducing the DRF ViewSets class. As a quick refresher, here are the DRF components so far. You’ve seen the Serializer.

00:23 The Serializer is responsible for taking an object and turning it into a text payload, or also to take text payloads and turning them back into objects.

00:32 Most of the time you’re going to want to do this with a Django model, but it doesn’t have to be. The entry point for your REST call is a view, just like a regular Django view.

00:42 The DRF provides decorators to make this a little easier. The heart of it is you have to return a DRF Response object with your serialized data inside of it for what to respond to with the view. To make your life easier, the DRF also has a concept called ViewSets.

01:00 A ViewSet is a class that encapsulates the common REST HTTP method calls, things like the gets, the posts, the patches, et cetera. Using a ViewSet makes it far faster to implement a series of REST calls on a class of objects. Going with the ViewSet is the concept of a Router.

01:19 A Router allows you to use a ViewSet to declare a series of URLs. This means you have far less work to do. You just map the ViewSet to a Router, and the DRF takes care of the rest of it for you.

01:32 Here’s an example base ViewSet, taken straight out of the DRF docs. As you can see, it declares six methods on the ViewSet class: .list(), .create(), .retrieve(), .update(), .partial_update(), and .destroy(). .list() maps to the GET method for listing the objects.

01:51 This would be used to do something similar to the people list view that I showed you in the previous lesson. .create() maps to the POST, allowing you to create a new object. .retrieve() maps to the GET, but for a specific identifier, so to get book number 12.

02:08 .update() maps to HTTP PUT, taking an object as well as some fields, those fields updating the values inside of the object specified. .partial_update() maps to PATCH, taking an object as well as a subset of fields, only updating those fields that are given. And .destroy() maps to the HTTP DELETE method. Throughout this course, I’m going to continue building on the Fedora project. For the most part, I’m going to create a new app for each lesson.

02:40 I won’t stepwise go through the process of creating each app—I will just quickly summarize it in order to save time. If you need guidance on how to do this, see the previous lesson or dig into one of the other Django courses. To get going for this lesson, I’m going to create another app, this one called artifacts.

02:58 I’m going to have to edit the settings.py file, adding artifacts to the INSTALLED_APPS list. I’m going to have to edit the Fedora/urls file to add the artifacts.urls file in the urlpatterns list. And then for the rest of this lesson, I’m going to show you the contents of models.py, serializers.py, views.py, and urls.py.

03:18 You can code along with me as I go. In order to play with the REST interface, you’re going to need some data, so you can either create an admin.py file to go with the models.py or you can use the one supplied in the supplemental materials.

03:32 Don’t forget to run makemigrations and migrate as necessary, and then use the admin or loaddata command to add some data to play with.

03:43 Inside of your newly created artifacts app, edit the models.py file and add this code. What I’ve done here is created a new Django model called Artifact.

03:54 It has two fields, a CharField for name and a BooleanField to indicate whether or not the artifact is shiny.

04:04 Like before, I need a serializer. Inside of a new file called serializers.py, I’m creating the ArtifactSerializer. As in the previous lesson, all I need to do here is identify the model that’s being serialized, which in this case is the Artifact, and the list of fields that I want serialized. The DRF provides a handy shortcut.

04:27 Instead of fields being a list, you can give it the string "__all__", and all the fields in the Artifact will be serialized.

04:36 The DRF is all about making your life easier and writing less code.

04:43 Instead of writing a view, this time I’m going to write a ViewSet. A ViewSet is a view class, and to keep things short and sweet, all you have to do is provide the Serializer that you want associated with the ViewSet and the queryset associated with that Serializer, and the DRF will create everything else for you. So on line 7, by convention, I name it the ArtifactViewSet. You’ll notice this pattern seems to hold—ArtifactSerializer goes with our Artifact model.

05:13 This inherits from the ModelViewSet class. On line 8, I specify the Serializer class, which is the ArtifactSerializer. And on line 10 and 11, I override the .get_queryset() method, returning the queryset of what I want. In this case, it’s all of the Artifact objects. Essentially, I’m accomplishing the same kind of thing that I did with the people list in the previous lesson. I’m listing off all of the artifacts, but this time, because I’m implementing the ModelViewSet, not only am I getting the GET for the listing, I’m also provided with retrieves, deletes, creates, and both kinds of updates.

05:59 To wire this ViewSet into the system, I use a router. Inside of artifacts/urls.py, on line 7 I create a DefaultRouter, and on line 8 I register this router.

06:11 I’m registering the ArtifactViewSet under the name r"artifacts". This means it’ll be listed under the path artifacts/ wherever my URL is mounted.

06:22 By using this router, I don’t have to specify routes for all the different URLs for creates and posts and patches. I just have to register the router, and then on line 11, include that router.

06:37 In a separate window, I’m running the Django development server. Now I’m going to demonstrate hitting those REST URLs with curl. First off, a simple GET. I’m hitting localhost port 8000 under artifacts/ and piping it through json.tool to get a pretty print.

06:55 What I get back is a dictionary with "artifacts" and a URL that says “Go to artifacts/artifacts/.” This happens because of the way I set up the router.

07:06 The first artifacts/ in that URL is part of the path from my include(). The second artifacts/ in that URL is placed there from the registration of the router. In later lessons, after you’ve registered a bunch of different routers, this listing will be helpful.

07:24 It gives the developer information about all the possible object routers that are available. Right now it seems a little redundant because there’s only one thing in there.

07:33 But I’ll take the hint, I’ll use that dictionary and get that first URL.

07:42 Once again with curl,

07:47 piping it through the json.tool, and there you go. This is the GET for the artifacts/artifacts/ path. It returns two artifacts from the database.

08:00 Notice it’s just a list in this case—there’s no dictionary to go with it. I can also do a GET on a specific value from the database by appending the ID of the object to the previous URL. Still a GET,

08:15 same localhost, same port, this time with ID 1.

08:22 And what is returned is just the information about that specific object. So far, so good. Now let’s do a .create().

08:33 The -X parameter to curl tells it to use a different kind of HTTP method, and -d are fields to pass in. In this case, I’m passing in the name and shiny fields.

08:47 It hits the URL. It’s a bit of a long command line there, so notice that it’s wrapped around to the second line. And what comes back is JSON of the new item created, the "Ark of the Covenant", with the shiny, of course, being True. This time I didn’t pass it through the pretty printer, so it just gets spit out all in one line.

09:08 If I run the listing again,

09:13 you’ll notice that the "Ark of the Covenant" has been added to our list of artifacts. Now let’s do an .update(). Once again, using the -X, this time using the HTTP PUT method, specifying fields for "Golden Idol" and "shiny=True", and the full URL of the object that I’m replacing, object 1.

09:37 This renames the "Chachapoyan Fertility Idol" to the easier-to-say "Golden Idol". As with the POST, what comes back is the object that was changed.

09:50 Let me try the same thing, but with a subset of the fields, this time only specifying shiny.

09:58 I get back an error from the server. Notice that this error is similar to how a Django form field works. If you fail to specify a required field in a Django form, Django gives you error information about what field failed. Django REST Framework is doing the same thing here.

10:18 Because I used a PUT, and a PUT maps to an .update(), you have to provide all fields for an .update().

10:24 And because I failed to provide the name field, I get back a dictionary with an error that says the name is required. If I only want to update the single field, instead of using a PUT, I have to use a PATCH. A similar concept here, this time using HTTP PATCH, provide only the shiny field and same URL.

10:49 And this time it worked. I don’t know what Belloq did to that pretty little gold statue to make it no longer shiny, but the database reflects it now. The only HTTP method left is DELETE so here it goes. Once again capital -X, this time with DELETE, specify a URL that has a specific object. In this case, you get nothing back from the server. If I run the listing, GET again,

11:20 you’ll see that the "Golden Idol" is no longer there. I guess Belloq took it out of inventory.

11:28 By using a ViewSet instead of a view, you automatically get the .list(), .retrieve(), .create(), .update(), .partial_update(), and .delete() methods for your object. In just a couple of lines of code, you fully defined a REST interface for your object.

11:45 This is extremely convenient and shows off the power of the DRF. Normally, I am a views-should-be-functions kind of guy, but when I use the DRF, ViewSets are the way to go.

11:58 In addition to the convenience of having the ViewSet define all of those things, the router means you don’t have to define the mappings for all of those. .list(), .retrieve(), .create(), .update(), .partial_update(), and .delete() are all created by the router in a single line.

12:14 The DRF saves you an awful lot of work and an awful lot of definition. Everything’s about the shortcuts here. So, that was ViewSets. Next up, I’ll show you the web interface, a great way to debug your REST application.

Become a Member to join the conversation.