Loading video player…

DRF Serialization and Views

Here are resources for curl and Django Rest framework:

00:00 In the previous lesson, I gave you an overview of REST. In this lesson, I’ll give you an introduction to the Django REST Framework, concentrating on the serialization and view mechanisms.

00:12 The Django REST Framework is a toolkit for developing web APIs built on top of the Django platform. It integrates with Django models, views, and URL patterns.

00:22 It provides classes called serializers for turning your Django models into JSON or XML or whatever else you’re going to use for your payload, views for controlling what can and can’t be seen in your API and tools tie into the URLs to specify where your objects live and how to access them.

00:42 Are you like me and prefer function-based views over class-based views, or are you one of those folks who are the other way around? No worries. DRF provides a way to handle either case.

00:53 The serialization toolkits inside of the DRF are most powerful when paired with Django models, but they don’t have to be tied to a Django model. You can also serialize non-ORM based data.

01:04 And to assist with your debugging, one of the payloads is a web-based interface. You can use the web to interact with the API, examine the payloads that come back, and initiate the different HTTP calls to manipulate objects on the server.

01:18 Full documentation and tutorials can be found at django-rest-framework.org.

01:25 Not surprisingly, the Django REST Framework is built on top of Django, so you’ll need both Django and the Django REST Framework installed to be able to follow along with this course.

01:34 As is best practice in the Python world, it’s better if you do this inside of a virtual environment. Here’s the pip command to install both Django and the Django REST Framework.

01:46 Note that djangorestframework is all one word. Most Django pip modules usually have underscores in them. For some reason, the DRF folks decided not to follow this convention.

01:55 If you run this command, you’ll get a long list of output as Django, DRF, and all of their dependencies get installed.

02:04 I’ll be using the command line tool curl to show you some of the results coming out of the DRF. curl comes built in with most operating systems, but in case it doesn’t come with yours, you can get it at curl.haxx.se.

02:17 Don’t forget that all the code that I show you inside of this course is available in the Supporting Material dropdown. It can save you a fair amount of typing if you just grab that zip file and follow along.

02:30 I’m going to start by setting up a sample Django project, which I’ll then use to demonstrate the DRF. First off, I’m going to use the Django command to start a new project called Fedora.

02:41 Go into the Fedora/ directory

02:44 and you’ll see the clean installation of the Fedora/ directory with settings and urls et cetera, as well as the manage.py command.

02:51 Next thing that I want to do is create a superuser. Before I do that, I need to deal with the database so that the auth tables are built, so I’m going to run migrate

03:03 And now that that is done, I’m going to create a superuser.

03:11 Because this is just for me, I’m going to cheat on the password so that I don’t have to type anything complicated in, and so Django warns me. Now that I’ve got the application and the superuser, I’m going to create an app inside of Fedora called people.

03:32 Here’s what the directory looks like. Now I’ve got the Fedora/ directory. I’ve got a database. I’ve still got the manage.py and the newly created people app.

03:44 Now that I have the project created and the people app created, I need to update the Fedora/settings.py file to make a couple of small changes.

03:52 I’m not showing you the entire settings file here, just the sections that I need to change. First off, I’m going to modify the ALLOWED_HOSTS listing to include localhost so that I can hit it from my browser when I’m using the Django development server. I’m adding both versions of localhost.

04:11 And secondly, I need to register the two apps. I need to register Django REST Framework and the newly created People app. First, the Django REST Framework, which oddly enough has the underscore (_) in it even though the PyPI module doesn’t, and the newly created "people" app.

04:28 That’s all the changes for the settings file.

04:32 Now that everything’s set up, let’s start writing some code. First off, I’m going to create a Person object for the database using a Django model.

04:41 I’m going to keep the model fairly simple here with three fields: first_name, last_name, and title. And then because I’m anal-retentive and I don’t like Persons showing up in the Django admin, I’m going to update the Meta value to "People".

04:57 Here’s the first bit of DRF code. Create a file called serializers.py inside of the people app. This file is the pair of the model.

05:06 Typically what happens is with every model you create, you also create a serializer. The serializer specifies how to turn the model into the payload data for REST. By convention, the serializers are named the same thing as the models.

05:21 So here on line five, you see me declare PersonSerializer to serialize my Person object from the models file. Similar to how a Person inherits from Model, the serializer inherits from the ModelSerializer.

05:35 ModelSerializer classes do a whole bunch of work for you. They automatically look at the model that’s associated with them and know how to serialize the different kinds of fields.

05:44 There’s all sorts of control you can do here to get fancy and I’ll show you that in later lessons. But for now, all I want to do is serialize the model as it is.

05:55 I have to do two things inside of the Meta section, specify the model. This is associated with, which in this case is Person and the fields that I am going to serialize—"id", "first", "last", and "title", and that’s all I need to do.

06:10 Serialization is now ready to go. The DRF will take care of the rest of turning the model into a payload.

06:21 Serializers themselves are only responsible for turning models into payloads. They don’t actually create the views or map to the URLs. The DRF uses the same kind of patterns as Django, so now I’m editing the people/views file and I’m going to create a new view.

06:39 This is on line nine, list_people(). What this is going to do is list all of the people in the database, serialize each one of them, and return a payload with a listing of all of the people.

06:51 Line 8 is a decorator from DRF that tells DRF that this is going to be associated with the HTTP GET method. DRF supports all of the HTTP methods supported by REST.

07:04 So I can create views using the @api_view decorator tied to any one of those HTTP methods. Notice that it takes a list. You can actually have it associated with multiple HTTP methods if you desire.

07:17 On line 10, I get a query set of all of my people. On line 11, I instantiate the PersonSerializer defined in the previous file, passing in the query set and the variable many set to True.

07:30 The serializer is capable of serializing more than one object at a time. By passing in the entire people queryset with all the people objects in it, and many=True.

07:42 I will get all the data serialized for every one of the people in the query set. Similar to an HttpResponse object, DRF has its own Response object.

07:53 It takes a content dictionary. In this case, I’m defining the content to have a single key named "people" and the .data associated with the serializer.

08:04 Creating the payload is a two-step process. The first step is instantiating a Serializer with your queryset, and the second step is referencing the .data property and putting it into the Response object.

08:19 The view I’ve just shown you is a Django view like any other, and as such, I need to register it inside of the urls.py file. I’m going to do this by creating a urls.py file inside of people/ and I’m going to specify a path called list_people/ associating that with the view that I just created.

08:39 You’re going to need something to serialize, of course, otherwise, your payload will just be empty. In order to make that easy, I’ve created a PersonAdmin object with the "first", "last", and "title" fields so that I can go into the Django admin and create some data in the database.

08:58 Okay, I’m almost all set now. The last thing I need to do is just register the people/urls with the global Fedora/urls. There are a couple of things I have to do to this file.

09:09 First off, I have to update line three to include the include function because I’m going to include all of the people.urls. Secondly, I’m going to create a path called "people/" and include all of the people.urls file.

09:24 Now you’ll be able to hit the development server with the path people/list_people/ included from the app’s urls file.

09:33 Okay, all the code’s set up, almost ready to go.

09:38 I need to register the database changes with the makemigrations command. It found people and registered it.

09:45 Now I need to migrate that. Great. The database is all set up and in order to be able to demo, I’m going to have to actually have some data on the database.

09:59 I’m going to run the development server and show you the admin right now. Off screen, I’m running the Django development server, and here in my trusty web browser, I’m going to open up the /admin URL.

10:13 That’s localhost:8000/admin. I’m going to log in with admin and the super secret five-letter password I created earlier begins with a and rhymes with admin, and here I am inside of the Django admin.

10:28 I’m going to add a few people by clicking on the Add button

10:58 and here are my four people for the database.

11:03 Or if you don’t feel like doing all of that, I managed to save all of that in a fixture for you so you can run the loaddata command.

11:13 Either way, you’ve now got some data in the database with some people. Running the Django server,

11:22 and then I’m going to switch to the lower window and hit that server with curl. First off, localhost:8000/people/list_people, the view that I just created a few minutes ago, the response that comes back is in JSON.

11:38 It’s a dictionary with the single key "people" and an array of the four people I created in the database. In the upper window, you can see the GET that was executed, the URL /people/list_people was hit, and that translated into the list_people() view that I created in the views.py file in the people app.

12:02 Because that’s a little hard to see, I’m going to do that again for you, but this time in a full window. Here’s the curl command. I’m using -s so that I don’t get the progress bar as I go along.

12:13 I’m hitting the same URL, port 8000 on localhost, /people/list_people/. And then as I did in the previous lesson,

12:21 I’m going to pipe this through Python using the json.tool module to pretty print the result. Let me just scroll up here for you. What comes back is a dictionary with a single attribute of "people" and the four people that I created in the dictionary.

12:40 That kind of feels like a lot, but most of what I did there was just typical Django stuff. Let me just quickly review what I had to do. First off, I created the project and the app inside the project.

12:51 Secondly, I created a Person model no different than I would create any model inside of a Django application. The first DRF specific thing I did was create the PersonSerializer which maps the Person model object to a REST payload.

13:06 I then created a view that uses a DRF Response object to send a serialization of the Person.objects.all() queryset down in the payload of REST.

13:17 And finally, I had to register this view as a URL, like any other view in Django. If you’re new to Django, there was a lot to follow along there. If Django’s old hat for you, there was very little extra code that you had to do to take your typical Django application and make it a REST-capable one.

13:37 So far I’ve shown you the simplest possible view. The ViewSets mechanism in DRF gives you a lot of power to do a lot of REST stuff with very little code.

13:47 Next up, I’ll introduce you to ViewSets.

Avatar image for apurvakunkulol

apurvakunkulol on Jan. 29, 2021

What is the need to add the rest_framework to the INSTALLED_APPS section? Since we’re already installing it before using. I can understand about the people app but why rest_framework?

Avatar image for Christopher Trudeau

Christopher Trudeau RP Team on Jan. 29, 2021

Short answer is the installation instructions for DRF say you should :)

www.django-rest-framework.org/#installation

Longer answer is third party apps are apps just like the ones you write. For Django to see them they have to be in INSTALLED_APPS. The DRF includes views and templates that your project wouldn’t be able to see unless they’ve been registered with Django.

Avatar image for B S K Karthik

B S K Karthik on Feb. 13, 2021

Can you please let me know what is the theme used for VS Code in this tutorial?

Avatar image for Christopher Trudeau

Christopher Trudeau RP Team on Feb. 14, 2021

Hi B S K Karthik,

I don’t personally use VS Code, some of the other course creators do. We’ve recently (after this course was published) started to standardize on a colour theme, we based it closely on “Dainty - Material Theme Ocean”. It isn’t the same as what is here, but not that far off.

If you’re really interested, message back and I can send you the exact colour codes used here and you could adopt them to your own theme.

IIRC, I based them on Vim’s color scheme called “desert”

www.vim.org/scripts/script.php?script_id=105

But I may have mucked with them over the years.

Avatar image for anders242

anders242 on Feb. 18, 2021

Hi there. I got the admin running fine through python3 manage.py runserver and then adding /admin. When I try to do the curl command I get the following: curl: (7) Failed to connect to 127.0.0.1 port 8000: Connection refused

I am using gitpod Thanks Anders

Avatar image for Christopher Trudeau

Christopher Trudeau RP Team on Feb. 18, 2021

Hi @anders242,

I’ve never used gitpod so I’m not sure off the top of my head. My guess is that you’ve got a network exposure or firewall issue. Given that gitpod is built on K8, are you sure that the dev server inside is exposed and bound to the same IP address?

Are you able to run this outside of gitpod in a shell and have the same problem?

When running in gitpod are you able to see the output? Can you see the django server running? It should look something like this:

Django version 3.1.2, using settings 'Fedora.settings' Starting development server at http://127.0.0.1:8000/ Quit the server with CONTROL-C.

Keep in mind that 127.0.0.1 is a local IP address and isn’t exposed to the outside world. If I run it on machine A, machine B won’t see it. Kubernetes tends to set up a little world similar to its own machine so likely isn’t exposing localhost to the outside world. It has been over a year since I played with K8, but IIRC, you would have to tell it to map an outside IP address to the thing happening in the container. I don’t know how much gitpod does for you when setting this kind of thing up.

Maybe someone else on the forum who has experience with gitpod can point you in the right direction.

Avatar image for anders242

anders242 on March 2, 2021

Hi Christopher. Thanks for your response. I am afraid 127.0.0.1 refused to conntect and I have tried everything. I also tried using VS Code but had the same problem.. very strange. If I $ python3 -m http.server I get Serving HTTP on 0.0.0.0 port 8000 (0.0.0.0:8000/) … I have another Django app that I completed where I can access /admin/ Thanks Anders

Avatar image for Christopher Trudeau

Christopher Trudeau RP Team on March 2, 2021

Hi @ander242,

That is truly strange. Are you able to hit other URLs on localhost besides /admin/? Are you seeing anything on the server side at all when you hit the URL, or is curl just refusing? Have you tried a browser instead of curl?

Double check the URL itself. Any chance you’re accidentally using https instead of http?

I’m reaching in the dark at this point. Maybe copy-and-paste both the django server terminal window text and the curl session so I can take a look.

Avatar image for anders242

anders242 on March 3, 2021

OOPPSS.... Schoolboy error I am afraid. I was in the wrong directory. Now that I run Pyhton manage.py runserver it works. I appreciate that you job here I not to provide tuition and I thank you for your respones. I had just been looking for every single answer out there except the obvious one…:-) Have a great day.

Anders

Avatar image for Christopher Trudeau

Christopher Trudeau RP Team on March 3, 2021

Happens to all of us. Nothing like looking at a problem the next day to get that “uh-duh” moment. Glad you figured it out. …ct

Avatar image for Narendrakumar Ratibhai Patel

Narendrakumar Ratibhai Patel on July 28, 2024

I found the following error during loaddata (env) PS D:\pythonProject\BuildDrfCode> python manage.py loaddata people Traceback (most recent call last): File “D:\pythonProject\BuildDrfCode\env\lib\site-packages\django\core\serializers\json.py”, line 69, in Deserializer objects = json.loads(stream_or_string) File “C:\Python310\lib\json__init__.py”, line 346, in loads return _default_decoder.decode(s) File “C:\Python310\lib\json\decoder.py”, line 337, in decode obj, end = self.raw_decode(s, idx=_w(s, 0).end()) File “C:\Python310\lib\json\decoder.py”, line 355, in raw_decode raise JSONDecodeError(“Expecting value”, s, err.value) from None json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

The above exception was the direct cause of the following exception:

Traceback (most recent call last): self.loaddata(fixture_labels) File “D:\pythonProject\BuildDrfCode\env\lib\site-packages\django\core\management\commands\loaddata.py”, line 163, in loaddata self.load_label(fixture_label) File “D:\pythonProject\BuildDrfCode\env\lib\site-packages\django\core\management\commands\loaddata.py”, line 251, in load_label for obj in objects: File “D:\pythonProject\BuildDrfCode\env\lib\site-packages\django\core\serializers\json.py”, line 74, in Deserializer raise DeserializationError() from exc

Avatar image for Christopher Trudeau

Christopher Trudeau RP Team on July 28, 2024

Hi Narendrakumar,

Please re-submit your comment using a code block, the traceback is rather hard to read when translated into paragraph text.

Avatar image for Thierry Gagné

Thierry Gagné on Oct. 5, 2024

In case it helps someone else in the future, when you write the final curl command, make sure not to forget the trailing slash (/) at the end of the URL or it will give a 301 Permanently Moved error message!

Avatar image for Martin Breuss

Martin Breuss RP Team on Oct. 6, 2024

Thanks for adding that note @Thierry Gagné!

Become a Member to join the conversation.