00:21 If you were going to be creating a single-page web application, you might want one REST call that includes all of the objects that you want back. So it would contain a dictionary and the dictionary would then have keys for each type of object that’s coming back in your page.
00:38 The ViewSets methods that I’ve shown you up until now have been object-specific, so that technique won’t work in this case. Instead, I’m going to start by showing you how to declare a view and nest those multiple serializers inside of it. New lesson, new app.
This time, I’m going to create a new app called
api. As always with a new app, you need to install it in the
INSTALLED_APPS listing, add the path for the app into the
urls file, and just to throw you a curve ball this time, I’m going to add a little wrinkle.
01:12 It’s a good idea to include a version number in your API path. This allows you to do backwardly-incompatible changes with your API by declaring a new version number, while maintaining backward compatibility while someone hits the old URLs.
An easy way of doing this is inside of the
path() declaration inside of your
urls file. I’ll show you what I mean in a moment. As before, if you’re coding along with me, the changes to the views and urls files will need to be done in conjunction. For the moment, I’m going to be using the data that’s already in the database, so you shouldn’t need to do any migrations this time. Here’s the the new view that I’m going to include inside of my
The view starts on line 12 with the
@api_view decorator indicating that this is going to be a
GET view. This view is going to include two different types of information, both the doctors in the
Person objects and the vehicles. For a little variety, this time I’m changing the queryset that’s being serialized to be just the doctors, so I’m filtering on anyone with the
title="Dr.". And one other complication arises here as well. I hinted at this in the previous lesson.
You may recall that the
VehicleSerializer uses the
url field. In order to properly populate the
url field, the serializer needs to be aware of the request. When you use a
ViewSet does this automatically for you. Because I’m not using a
ViewSet here, I need to pass extra information into the
VehicleSerializer so that it can see the
request object. This is done through the
So, the serializer includes the vehicles being serialized. Because it’s multiple vehicles,
many=True, as well as the
context that includes the
request object. The serializer then uses the
request object out of the
context to construct the host name inside of the URL so that you can get a fully qualified URL inside of the serialized payload. On line 23, I’m using the
PersonSerializer to serialize the
Notice that what goes in the dictionary is actually the
.data attribute, so I have a shortcut here. Rather than creating a object called the serializer and then calling
.data on the object, I’m just doing it directly on the constructor in one line. Then on line 24, I serialize the vehicles, like you’ve seen me do before, and return all of this inside of a REST
"doctors" field contains an array with all of the doctors, and the
"vehicles" field contains an array with all of the vehicles. Scrolling back down, as before, the
"vehicles" includes the nested
"part_set" inside of it.
So this ViewSet will only support listing objects. For each mixin that you include, you will have a corresponding method. For the
ListModelMixin, I have the
.list() method. Inside this
.list() method, I’m not doing anything you haven’t seen before.
Here’s the new
api/urls file. Since I’m now using a
ViewSet instead of a view, I use the
router to register it, and I include all the URLs provided by the
router—in this case, this will only be one—under the
"v1/" path listing, giving me version numbers for my API.
The DRF provides an entire hierarchy of
ViewSet classes for your use. There’s the base
ViewSet class, the
GenericViewSet class that I just showed you—which adds the
.queryset attribute, the
ModelViewSet that you’ve been using in the lessons up until now, and there’s also a
ReadOnlyModelViewSet that is a
ModelViewSet but doesn’t allow changes to it. Several lessons ago when I introduced ViewSets, I showed you this base class. It’s probably worth reviewing now. The base
ViewSet declares six methods that correspond to the actions that are being performed in REST.
.list() lists objects.
.create() is for a
POST, creating an object.
.retrieve() is to get a specific object.
.partial_update() are for updating existing objects. And
.destroy() is for deleting an object.
Each of these methods is declared inside of a mixin. It’s done this way so you can mix and match the mixins and create a ViewSet with only those methods that you wish to support. The mixins are
UpdateModelMixin—which provides both
08:42 Essentially, there’s a mixin for each one of those methods I just showed you in the base class. Additionally, if there’s something that you want to do that isn’t covered by one of those actions, you can declare your own.
REST, by default, doesn’t support the change of more than one object at a time. For example, if you wanted to be able to delete multiple objects, you would have to make multiple calls. Instead, you can create an action which is
.mass_delete(). Let me show you how to do that right now.
ViewSet is only going to support deleting objects, so I’m going to use the
DestroyModelMixin. Inside of the class, I’m creating a method called
.mass_delete(), and I tell DRF that I want this to be an action available in the REST API by decorating it with the
I’m passing two arguments to the decorator. The first is
detail=False. This tells the DRF that the URL to be used with this action does not include an ID. Because I’m going to be deleting multiple objects, I just want a regular URL—I don’t want
/3 on the end of it.
Secondly, I’m passing in a list of the HTTP methods that I’m supporting in this action. In this case, it’s only
"delete". Because I’m deleting more than one thing, I somehow have to get multiple IDs up to the server.
There’s different ways of handling this. I could use
GET with query parameters, or, in this case, what I’m showing you is using a
POST with a string inside of it that is comma-separated. When this action is called, I will process the
POST field named
"ids" and split it on any commas (
,) inside of it.
Each value that is found is assumed to be the
id of an
Artifact that needs to be deleted. I fetch that
Artifact and then call the
.delete() method on it. Finally, because there’s no payload that I want to return, I just send back an empty
And there are my two artifacts. And now I will call
.mass_delete(). I specify
-X DELETE so that I use the HTTP
DELETE method with
curl, and the
-d parameter shows the
POST fields that I’m going to be sending in of
"1,2". Notice that the URL is a little weird, that you’ve got the
This has to do with how the router constructs URL names. It’s based on both the class name and the method that is attached to it. There are things you can do to modify this, but you kind of have to jump through hoops. It’s easier just to accept it as it is. Finally, to show you that this worked, I’ll run the
Become a Member to join the conversation.