{"id":6679,"date":"2023-08-21T13:51:18","date_gmt":"2023-08-21T13:51:18","guid":{"rendered":"https:\/\/www.pythontutorial.net\/?page_id=6679"},"modified":"2023-08-22T14:32:43","modified_gmt":"2023-08-22T14:32:43","slug":"django-rest-framework","status":"publish","type":"page","link":"https:\/\/www.pythontutorial.net\/django-tutorial\/django-rest-framework\/","title":{"rendered":"Django REST Framework"},"content":{"rendered":"\n<p><strong>Summary<\/strong>: in this tutorial, you will learn about the Django REST Framework and how to use it to create a simple but complete RESTful API that manages todos.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id='introduction-to-the-django-rest-framework'>Introduction to the Django REST Framework <a href=\"#introduction-to-the-django-rest-framework\" class=\"anchor\" id=\"introduction-to-the-django-rest-framework\" title=\"Anchor for Introduction to the Django REST Framework\">#<\/a><\/h2>\n\n\n\n<p>Django REST Framework or DRF is a powerful toolkit for developing Web APIs in Django applications. The DRF allows you to create RESTful APIs <strong>fast<\/strong> by providing pre-built classes and conventions. <\/p>\n\n\n\n<p>DRF has the following key features:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Serialization:<\/strong> Serialization allows you to automatically convert Django models to JSON and vice versa, making data transfer between client and server seamless.<\/li>\n\n\n\n<li><strong>URL Routing:<\/strong> DRF provides URL routing that is the same as Django&#8217;s router, which allows you to associate URLs with their API views efficiently.<\/li>\n\n\n\n<li><strong>Authentication:<\/strong> DRF offers various authentication methods including basic authentication and token authentication. It also supports JWT via a third-party package.<\/li>\n\n\n\n<li><strong>Permission<\/strong>: DRF allows fine-grained control over user permissions.<\/li>\n\n\n\n<li><strong>Throttling \/ Rate Limiting:<\/strong> The throttling and rate features help you to limit the number of requests a client can make within a certain time period.<\/li>\n\n\n\n<li><strong>Pagination:<\/strong> DRF provides built-in support for paginating large datasets in API responses.<\/li>\n\n\n\n<li><strong>Browsable API:<\/strong> DRF has a user-friendly HTML interface for testing and exploring APIs directly from the browser.<\/li>\n<\/ul>\n\n\n\n<p>We&#8217;ll continue the <a href=\"https:\/\/www.pythontutorial.net\/django-tutorial\/django-rest-api\/\">Todo project that we left off in the previous tutorial<\/a>. To start with, you can <a href=\"https:\/\/www.pythontutorial.net\/wp-content\/uploads\/2023\/08\/todolist.zip\">download the project via this link<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id='installing-the-django-rest-framework-package'>Installing the Django REST Framework package <a href=\"#installing-the-django-rest-framework-package\" class=\"anchor\" id=\"installing-the-django-rest-framework-package\" title=\"Anchor for Installing the Django REST Framework package\">#<\/a><\/h2>\n\n\n\n<p>First, install the Django REST framework in the project&#8217;s virtual environment:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"plaintext\" data-shcb-language-slug=\"plaintext\"><span><code class=\"hljs language-plaintext\">pip install djangorestframework<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">plaintext<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">plaintext<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Second, update the <code>requirements.txt<\/code> file:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"plaintext\" data-shcb-language-slug=\"plaintext\"><span><code class=\"hljs language-plaintext\">pip freeze &gt; requirements.txt<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">plaintext<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">plaintext<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Third, register <code>rest_framework<\/code> app in the <code>settings.py<\/code> of the project:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"Python\" data-shcb-language-slug=\"python\"><span><code class=\"hljs language-python\">INSTALLED_APPS = &#91;\n    ...\n    <span class=\"hljs-string\">'rest_framework'<\/span>, \n    ...\n]<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">Python<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">python<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h2 class=\"wp-block-heading\" id='creating-a-new-django-rest-framework-app'>Creating a new Django REST framework app <a href=\"#creating-a-new-django-rest-framework-app\" class=\"anchor\" id=\"creating-a-new-django-rest-framework-app\" title=\"Anchor for Creating a new Django REST framework app\">#<\/a><\/h2>\n\n\n\n<p>First, create a new directory called <code>api<\/code> in the project directory to host the API code:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"plaintext\" data-shcb-language-slug=\"plaintext\"><span><code class=\"hljs language-plaintext\">mkdir api<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">plaintext<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">plaintext<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Second, create three Python files inside the <code>api<\/code> directory:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>serializers.py<\/code> &#8211; provides a serializer that converts Django&#8217;s models into JSON format and vice versa.<\/li>\n\n\n\n<li><code>views.py<\/code> &#8211; houses the API views, similar to Django&#8217;s app&#8217;s views.<\/li>\n\n\n\n<li><code>urls.py<\/code> &#8211; defines the API endpoint that maps to the API views.<\/li>\n<\/ul>\n\n\n\n<p>Third, add the <code>api<\/code> to the <code>INSTALLED_APPS<\/code> in the <code>settings.py<\/code> file of the project:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"Python\" data-shcb-language-slug=\"python\"><span><code class=\"hljs language-python\">INSTALLED_APPS = &#91;\n    ...\n    <span class=\"hljs-string\">'api'<\/span>,\n    ...\n]<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">Python<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">python<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>We&#8217;ll create an API with the following endpoints:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><thead><tr><th>Endpoints<\/th><th>HTTP Verb<\/th><th>Description<\/th><\/tr><\/thead><tbody><tr><td><code>api\/v1\/todos\/<\/code><\/td><td><code>GET<\/code><\/td><td>Return all todos<\/td><\/tr><tr><td><code>api\/v2\/todos\/<\/code><\/td><td><code>POST<\/code><\/td><td>Create a new todo<\/td><\/tr><tr><td><code>api\/v2\/todos\/1<\/code><\/td><td><code>GET<\/code><\/td><td>Return the todo with the id 1<\/td><\/tr><tr><td><code>api\/v1\/todos\/1<\/code><\/td><td><code>PATCH<\/code><\/td><td>Update the todo with id 1<\/td><\/tr><tr><td><code>api\/v1\/todos\/1<\/code><\/td><td><code>DELETE<\/code><\/td><td>Delete the todo with id 1<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\" id='creating-a-serializer-class'>Creating a serializer class <a href=\"#creating-a-serializer-class\" class=\"anchor\" id=\"creating-a-serializer-class\" title=\"Anchor for Creating a serializer class\">#<\/a><\/h2>\n\n\n\n<p>Serializer classes allow you to serialize Django&#8217;s model instances into JSON and vice versa. <\/p>\n\n\n\n<p>The following defines a serializer class called <code>TodoSerializer<\/code> in the <code>serializers.py<\/code> file that serializes the <code>Todo<\/code> instance to JSON and vice versa:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"Python\" data-shcb-language-slug=\"python\"><span><code class=\"hljs language-python\"><span class=\"hljs-keyword\">from<\/span> rest_framework <span class=\"hljs-keyword\">import<\/span> serializers\n<span class=\"hljs-keyword\">from<\/span> todo.models <span class=\"hljs-keyword\">import<\/span> Todo\n\n<span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">TodoSerializer<\/span><span class=\"hljs-params\">(serializers.ModelSerializer)<\/span>:<\/span>\n    user = serializers.StringRelatedField(read_only=<span class=\"hljs-literal\">True<\/span>)\n\n    <span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">Meta<\/span>:<\/span>\n        model = Todo\n        fields = (<span class=\"hljs-string\">'id'<\/span>, <span class=\"hljs-string\">'title'<\/span>, <span class=\"hljs-string\">'completed'<\/span>, <span class=\"hljs-string\">'user'<\/span>)<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">Python<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">python<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>How it works.<\/p>\n\n\n\n<p>First, import the <code>serializers<\/code> module from <code>rest_framework<\/code> package:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"Python\" data-shcb-language-slug=\"python\"><span><code class=\"hljs language-python\"><span class=\"hljs-keyword\">from<\/span> rest_framework <span class=\"hljs-keyword\">import<\/span> serializers<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">Python<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">python<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Second, import the <code>Todo<\/code> model from the <code>models<\/code> module of the <code>todo<\/code> app:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"Python\" data-shcb-language-slug=\"python\"><span><code class=\"hljs language-python\"><span class=\"hljs-keyword\">from<\/span> todo.models <span class=\"hljs-keyword\">import<\/span> Todo<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">Python<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">python<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Third, define the <code>TodoSerializer<\/code> class that extends the <code>serializers.ModelSerializer<\/code> class:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"Python\" data-shcb-language-slug=\"python\"><span><code class=\"hljs language-python\"><span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">TodoSerializer<\/span><span class=\"hljs-params\">(serializers.ModelSerializer)<\/span>:<\/span>\n    ...<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">Python<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">python<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>The <code>ModelSerializer<\/code> provides a quick way to define a serializer class with fields corresponding to the model&#8217;s fields.<\/p>\n\n\n\n<p>Inside the <code>TodoSerializer<\/code> class, define a <code>Meta<\/code> class that initializes:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>model<\/code> &#8211; specifies the <code>Todo<\/code> model.<\/li>\n\n\n\n<li><code>fields<\/code> &#8211; specifies a list of fields for the serializer. If the serializer uses all the fields of the model, you can use the <code>'__all__'<\/code> instead, like this:<\/li>\n<\/ul>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-10\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">fields = <span class=\"hljs-string\">'__all__'<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Since the <code>Todo<\/code> model is associated with the <code>User<\/code> model, we specify the <code>user<\/code> attribute as the <code>StringRelatedField()<\/code> and set its parameter to <code>read_only<\/code>. <\/p>\n\n\n\n<p>It means that the <code>Todo<\/code> will have the string representation of the <code>User<\/code> which is the <code>username<\/code> in this case.<\/p>\n\n\n\n<p>The <code>read_only<\/code> parameter allows the serializer to only read the <code>User<\/code> model. In other words, the serializer will not be able to update the <code>User<\/code> model.<\/p>\n\n\n\n<p>Besides the <code>StringRelatedField<\/code>, DRF provides other types of related fields as shown in the following table:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><thead><tr><th>Field<\/th><th>Description<\/th><\/tr><\/thead><tbody><tr><td><code>PrimaryKeyRelatedField<\/code>&nbsp;<\/td><td>Represent the related model as the primary key.<\/td><\/tr><tr><td><code>HyperlinkedRelatedField<\/code><\/td><td>Represent the related model as a hyperlink.<\/td><\/tr><tr><td><code>SlugRelatedField<\/code>&nbsp;<\/td><td>Represent the related model as one of its fields.<\/td><\/tr><tr><td><code>HyperlinkedIdentityField<\/code><\/td><td>Represent the related model as a hyperlink to the identity field.<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>Since we have completed defining the Serializer class, let&#8217;s use it to serialize the Todo model using the TodoSerializer class in the Django Shell.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id='serializing-data'>Serializing data <a href=\"#serializing-data\" class=\"anchor\" id=\"serializing-data\" title=\"Anchor for Serializing data\">#<\/a><\/h3>\n\n\n\n<p>First, start the Django Shell from the terminal:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-11\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">python<\/span> <span class=\"hljs-selector-tag\">manage<\/span><span class=\"hljs-selector-class\">.py<\/span> <span class=\"hljs-selector-tag\">shell<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-11\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Second, import the <code>Todo<\/code> model and <code>TodoSerializer<\/code> class:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-12\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">&gt;&gt;&gt; <span class=\"hljs-keyword\">from<\/span> api.serializers <span class=\"hljs-keyword\">import<\/span> TodoSerializer\n&gt;&gt;&gt; <span class=\"hljs-keyword\">from<\/span> todo.models <span class=\"hljs-keyword\">import<\/span> Todo<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-12\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Third, get the <code>Todo<\/code> with id 1:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-13\" data-shcb-language-name=\"Python\" data-shcb-language-slug=\"python\"><span><code class=\"hljs language-python\">&gt;&gt; todo = Todo.objects.get(id=<span class=\"hljs-number\">1<\/span>)\n<span class=\"hljs-meta\">&gt;&gt;&gt; <\/span>todo\n&lt;Todo: Learn Python&gt;<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-13\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">Python<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">python<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Fourth, create a new instance of the <code>TodoSerializer<\/code> with the <code>Todo<\/code> model and access the data attribute:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-14\" data-shcb-language-name=\"Python\" data-shcb-language-slug=\"python\"><span><code class=\"hljs language-python\"><span class=\"hljs-meta\">&gt;&gt;&gt; <\/span>serializer = TodoSerializer(todo)\n<span class=\"hljs-meta\">&gt;&gt;&gt; <\/span>serializer.data\n{<span class=\"hljs-string\">'id'<\/span>: <span class=\"hljs-number\">1<\/span>, <span class=\"hljs-string\">'title'<\/span>: <span class=\"hljs-string\">'Learn Python'<\/span>, <span class=\"hljs-string\">'completed'<\/span>: <span class=\"hljs-literal\">False<\/span>, <span class=\"hljs-string\">'user'<\/span>: <span class=\"hljs-string\">'john'<\/span>}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-14\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">Python<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">python<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>The <code>TodoSerialzier<\/code> object serializes the todo model into JSON format.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id='creating-an-api-view-class'>Creating an API view class <a href=\"#creating-an-api-view-class\" class=\"anchor\" id=\"creating-an-api-view-class\" title=\"Anchor for Creating an API view class\">#<\/a><\/h2>\n\n\n\n<p>The following define API view classes in the <code>views.py<\/code> file:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-15\" data-shcb-language-name=\"Python\" data-shcb-language-slug=\"python\"><span><code class=\"hljs language-python\"><span class=\"hljs-keyword\">from<\/span> rest_framework <span class=\"hljs-keyword\">import<\/span> generics\n<span class=\"hljs-keyword\">from<\/span> .serializers <span class=\"hljs-keyword\">import<\/span> TodoSerializer\n<span class=\"hljs-keyword\">from<\/span> todo.models <span class=\"hljs-keyword\">import<\/span> Todo\n\n\n<span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">TodoList<\/span><span class=\"hljs-params\">(generics.ListCreateAPIView)<\/span>:<\/span>\n    queryset = Todo.objects.all()\n    serializer_class = TodoSerializer\n\n    <span class=\"hljs-function\"><span class=\"hljs-keyword\">def<\/span> <span class=\"hljs-title\">perform_create<\/span><span class=\"hljs-params\">(self, serializer)<\/span>:<\/span>\n        serializer.save(user=self.request.user)\n\n\n<span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">TodoDetail<\/span><span class=\"hljs-params\">(generics.RetrieveUpdateDestroyAPIView)<\/span>:<\/span>\n    queryset = Todo.objects.all()\n    serializer_class = TodoSerializer\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-15\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">Python<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">python<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>How it works.<\/p>\n\n\n\n<p>First, import the <code>generics<\/code> from the <code>rest_framework<\/code>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-16\" data-shcb-language-name=\"Python\" data-shcb-language-slug=\"python\"><span><code class=\"hljs language-python\"><span class=\"hljs-keyword\">from<\/span> rest_framework <span class=\"hljs-keyword\">import<\/span> generics<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-16\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">Python<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">python<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>The <code>generics<\/code> provide various base view classes such as <code>ListCreateAPIView<\/code> and <code>RetrieveUpdateDestroyAPIView<\/code>.<\/p>\n\n\n\n<p>Second, import the <code>TodoSerializer<\/code> from the <code>serializers<\/code>  of the <code>api<\/code> app and <code>Todo<\/code> model from the <code>models<\/code> of the <code>todo<\/code> app:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-17\" data-shcb-language-name=\"Python\" data-shcb-language-slug=\"python\"><span><code class=\"hljs language-python\"><span class=\"hljs-keyword\">from<\/span> .serializers <span class=\"hljs-keyword\">import<\/span> TodoSerializer\n<span class=\"hljs-keyword\">from<\/span> todo.models <span class=\"hljs-keyword\">import<\/span> Todo<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-17\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">Python<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">python<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Third, define the <code>TodoList<\/code> class that extends the <code>ListCreateAPIView<\/code> class. The <code>TodoList<\/code> class is responsible for two tasks:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>List all todos.<\/li>\n\n\n\n<li>Create a new todo.<\/li>\n<\/ul>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-18\" data-shcb-language-name=\"Python\" data-shcb-language-slug=\"python\"><span><code class=\"hljs language-python\"><span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">TodoList<\/span><span class=\"hljs-params\">(generics.ListCreateAPIView)<\/span>:<\/span>\n    queryset = Todo.objects.all()\n    serializer_class = TodoSerializer\n\n    <span class=\"hljs-function\"><span class=\"hljs-keyword\">def<\/span> <span class=\"hljs-title\">perform_create<\/span><span class=\"hljs-params\">(self, serializer)<\/span>:<\/span>\n        serializer.save(user=self.request.user)<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-18\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">Python<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">python<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>In the <code>TodoList<\/code> class, specify the <code>queryset<\/code> used to return all todos and <code>serializer_class<\/code> used for serialization\/deserialization of the <code>Todo<\/code> instances.<\/p>\n\n\n\n<p>The <code>perform_create()<\/code> method of the TodoSerializer class is invoked automatically when you save a new Todo instance. <\/p>\n\n\n\n<p>Since each <code>Todo<\/code> instance needs a <code>User<\/code> instance, we assign the <code>user<\/code> from the HTTP request (<code>request<\/code>)to the <code>user<\/code> attribute of the <code>Todo<\/code> instance before saving it to the database.<\/p>\n\n\n\n<p>Finally, define the <code>TodoDetail<\/code> class that extends the <code>RetrieveUpdateDestroyAPIView<\/code> class: <\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-19\" data-shcb-language-name=\"Python\" data-shcb-language-slug=\"python\"><span><code class=\"hljs language-python\"><span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">TodoDetail<\/span><span class=\"hljs-params\">(generics.RetrieveUpdateDestroyAPIView)<\/span>:<\/span>\n    queryset = Todo.objects.all()\n    serializer_class = TodoSerializer<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-19\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">Python<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">python<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>The <code>TodoDetail<\/code> class is in charge of the following operations:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Retrieve a todo by id.<\/li>\n\n\n\n<li>Update an existing todo.<\/li>\n\n\n\n<li>Destroy (or delete) a todo.<\/li>\n<\/ul>\n\n\n\n<p>In the <code>TodoDetail<\/code> class, we also need to define the <code>queryset<\/code> and <code>serializer_class<\/code>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id='defining-api-endpoints'>Defining API endpoints <a href=\"#defining-api-endpoints\" class=\"anchor\" id=\"defining-api-endpoints\" title=\"Anchor for Defining API endpoints\">#<\/a><\/h2>\n\n\n\n<p>The following define API endpoints in the <code>urls.py<\/code> of the <code>api<\/code> app:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-20\" data-shcb-language-name=\"Python\" data-shcb-language-slug=\"python\"><span><code class=\"hljs language-python\"><span class=\"hljs-keyword\">from<\/span> django.urls <span class=\"hljs-keyword\">import<\/span> path\n\n<span class=\"hljs-keyword\">from<\/span> .views <span class=\"hljs-keyword\">import<\/span> TodoList, TodoDetail\n\nurlpatterns = &#91;\n    path(<span class=\"hljs-string\">'todos\/'<\/span>, TodoList.as_view(), name=<span class=\"hljs-string\">'todo_list'<\/span>),\n    path(<span class=\"hljs-string\">'todos\/&lt;int:pk&gt;\/'<\/span>, TodoDetail.as_view(), name=<span class=\"hljs-string\">'todo_detail'<\/span>),\n]<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-20\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">Python<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">python<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h2 class=\"wp-block-heading\" id='interacting-with-api-using-the-browsable-api'>Interacting with API using the Browsable API <a href=\"#interacting-with-api-using-the-browsable-api\" class=\"anchor\" id=\"interacting-with-api-using-the-browsable-api\" title=\"Anchor for Interacting with API using the Browsable API\">#<\/a><\/h2>\n\n\n\n<p>Django REST Framework support generating user-friendly HTML pages of all resources when you request the HTML format. <\/p>\n\n\n\n<p>These pages allow you to browse the APIs easily and submit data to the API endpoints using POST, PUT, PATCH, and DELETE.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id='getting-all-todos'>Getting all todos <a href=\"#getting-all-todos\" class=\"anchor\" id=\"getting-all-todos\" title=\"Anchor for Getting all todos\">#<\/a><\/h3>\n\n\n\n<p>Open the endpoint http:\/\/localhost:8000\/api\/v1\/todos\/, and you&#8217;ll see the following page.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"541\" src=\"https:\/\/www.pythontutorial.net\/wp-content\/uploads\/2023\/08\/django-rest-framework-get-todos-1024x541.png\" alt=\"\" class=\"wp-image-6689\" srcset=\"https:\/\/www.pythontutorial.net\/wp-content\/uploads\/2023\/08\/django-rest-framework-get-todos-1024x541.png 1024w, https:\/\/www.pythontutorial.net\/wp-content\/uploads\/2023\/08\/django-rest-framework-get-todos-300x158.png 300w, https:\/\/www.pythontutorial.net\/wp-content\/uploads\/2023\/08\/django-rest-framework-get-todos-768x406.png 768w, https:\/\/www.pythontutorial.net\/wp-content\/uploads\/2023\/08\/django-rest-framework-get-todos.png 1378w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>By opening the <code>api\/v1\/todos\/<\/code> in the web browser, you are performing a GET request to the endpoint. The page returns a list of todos list in the nicely HTML formatted page.<\/p>\n\n\n\n<p>To get the raw JSON format, you specify the format of the GET request by clicking the json menu item in the GET button as shown in the following picture :<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"395\" height=\"211\" src=\"https:\/\/www.pythontutorial.net\/wp-content\/uploads\/2023\/08\/django-rest-framework-todos-json.png\" alt=\"\" class=\"wp-image-6706\" srcset=\"https:\/\/www.pythontutorial.net\/wp-content\/uploads\/2023\/08\/django-rest-framework-todos-json.png 395w, https:\/\/www.pythontutorial.net\/wp-content\/uploads\/2023\/08\/django-rest-framework-todos-json-300x160.png 300w\" sizes=\"auto, (max-width: 395px) 100vw, 395px\" \/><\/figure>\n\n\n\n<p>The API will return the raw JSON:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-21\" data-shcb-language-name=\"JSON \/ JSON with Comments\" data-shcb-language-slug=\"json\"><span><code class=\"hljs language-json\">&#91;{<span class=\"hljs-attr\">\"id\"<\/span>:<span class=\"hljs-number\">1<\/span>,<span class=\"hljs-attr\">\"title\"<\/span>:<span class=\"hljs-string\">\"Learn Python\"<\/span>,<span class=\"hljs-attr\">\"completed\"<\/span>:<span class=\"hljs-literal\">false<\/span>,<span class=\"hljs-attr\">\"user\"<\/span>:<span class=\"hljs-string\">\"john\"<\/span>},{<span class=\"hljs-attr\">\"id\"<\/span>:<span class=\"hljs-number\">2<\/span>,<span class=\"hljs-attr\">\"title\"<\/span>:<span class=\"hljs-string\">\"Study Django\"<\/span>,<span class=\"hljs-attr\">\"completed\"<\/span>:<span class=\"hljs-literal\">false<\/span>,<span class=\"hljs-attr\">\"user\"<\/span>:<span class=\"hljs-string\">\"john\"<\/span>},{<span class=\"hljs-attr\">\"id\"<\/span>:<span class=\"hljs-number\">3<\/span>,<span class=\"hljs-attr\">\"title\"<\/span>:<span class=\"hljs-string\">\"Master Django REST API\"<\/span>,<span class=\"hljs-attr\">\"completed\"<\/span>:<span class=\"hljs-literal\">false<\/span>,<span class=\"hljs-attr\">\"user\"<\/span>:<span class=\"hljs-string\">\"john\"<\/span>}]<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-21\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JSON \/ JSON with Comments<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">json<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>If you have a JSON viewer extension installed on the web browser, you can see the human-readable JSON format as follows:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-22\" data-shcb-language-name=\"JSON \/ JSON with Comments\" data-shcb-language-slug=\"json\"><span><code class=\"hljs language-json\">&#91;\n  {\n    <span class=\"hljs-attr\">\"id\"<\/span>: <span class=\"hljs-number\">1<\/span>,\n    <span class=\"hljs-attr\">\"title\"<\/span>: <span class=\"hljs-string\">\"Learn Python\"<\/span>,\n    <span class=\"hljs-attr\">\"completed\"<\/span>: <span class=\"hljs-literal\">false<\/span>,\n    <span class=\"hljs-attr\">\"user\"<\/span>: <span class=\"hljs-string\">\"john\"<\/span>\n  },\n  {\n    <span class=\"hljs-attr\">\"id\"<\/span>: <span class=\"hljs-number\">2<\/span>,\n    <span class=\"hljs-attr\">\"title\"<\/span>: <span class=\"hljs-string\">\"Study Django\"<\/span>,\n    <span class=\"hljs-attr\">\"completed\"<\/span>: <span class=\"hljs-literal\">false<\/span>,\n    <span class=\"hljs-attr\">\"user\"<\/span>: <span class=\"hljs-string\">\"john\"<\/span>\n  },\n  {\n    <span class=\"hljs-attr\">\"id\"<\/span>: <span class=\"hljs-number\">3<\/span>,\n    <span class=\"hljs-attr\">\"title\"<\/span>: <span class=\"hljs-string\">\"Master Django REST API\"<\/span>,\n    <span class=\"hljs-attr\">\"completed\"<\/span>: <span class=\"hljs-literal\">false<\/span>,\n    <span class=\"hljs-attr\">\"user\"<\/span>: <span class=\"hljs-string\">\"john\"<\/span>\n  }\n]<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-22\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JSON \/ JSON with Comments<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">json<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h3 class=\"wp-block-heading\" id='creating-a-new-todo'>Creating a new todo <a href=\"#creating-a-new-todo\" class=\"anchor\" id=\"creating-a-new-todo\" title=\"Anchor for Creating a new todo\">#<\/a><\/h3>\n\n\n\n<p>Open the endpoint <code>\/api\/v1\/todos\/<\/code>. But this time we&#8217;ll issue a <code>POST<\/code> request instead of <code>GET<\/code> request.<\/p>\n\n\n\n<p>First, enter the todo information:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"869\" height=\"505\" src=\"https:\/\/www.pythontutorial.net\/wp-content\/uploads\/2023\/08\/django-rest-framework-create-todo-form.png\" alt=\"\" class=\"wp-image-6682\" srcset=\"https:\/\/www.pythontutorial.net\/wp-content\/uploads\/2023\/08\/django-rest-framework-create-todo-form.png 869w, https:\/\/www.pythontutorial.net\/wp-content\/uploads\/2023\/08\/django-rest-framework-create-todo-form-300x174.png 300w, https:\/\/www.pythontutorial.net\/wp-content\/uploads\/2023\/08\/django-rest-framework-create-todo-form-768x446.png 768w\" sizes=\"auto, (max-width: 869px) 100vw, 869px\" \/><\/figure>\n\n\n\n<p>Second, click the <code>POST<\/code> button, and you&#8217;ll get the following response:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"881\" height=\"322\" src=\"https:\/\/www.pythontutorial.net\/wp-content\/uploads\/2023\/08\/django-rest-framework-create-todo.png\" alt=\"\" class=\"wp-image-6683\" srcset=\"https:\/\/www.pythontutorial.net\/wp-content\/uploads\/2023\/08\/django-rest-framework-create-todo.png 881w, https:\/\/www.pythontutorial.net\/wp-content\/uploads\/2023\/08\/django-rest-framework-create-todo-300x110.png 300w, https:\/\/www.pythontutorial.net\/wp-content\/uploads\/2023\/08\/django-rest-framework-create-todo-768x281.png 768w\" sizes=\"auto, (max-width: 881px) 100vw, 881px\" \/><\/figure>\n\n\n\n<p>The API creates a new todo with id 4. Also, the user is the one that you&#8217;re currently logged in. <\/p>\n\n\n\n<p class=\"note\">Notice that you need to log in to the admin site as a user e.g., john so that the perform_create() method of the TodoList can get the user information from the request.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id='getting-a-specific-todo'>Getting a specific todo <a href=\"#getting-a-specific-todo\" class=\"anchor\" id=\"getting-a-specific-todo\" title=\"Anchor for Getting a specific todo\">#<\/a><\/h3>\n\n\n\n<p>Open the endpoint <code>\/api\/v1\/todos\/4\/<\/code> to get detailed information on the todo with id 4:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"693\" height=\"394\" src=\"https:\/\/www.pythontutorial.net\/wp-content\/uploads\/2023\/08\/django-rest-framework-get-todo-detail-response.png\" alt=\"\" class=\"wp-image-6684\" srcset=\"https:\/\/www.pythontutorial.net\/wp-content\/uploads\/2023\/08\/django-rest-framework-get-todo-detail-response.png 693w, https:\/\/www.pythontutorial.net\/wp-content\/uploads\/2023\/08\/django-rest-framework-get-todo-detail-response-300x171.png 300w\" sizes=\"auto, (max-width: 693px) 100vw, 693px\" \/><\/figure>\n\n\n\n<p>In this case, we are making a GET request to the API endpoint <code>\/api\/v1\/todos\/4\/<\/code><\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id='updating-a-todo'>Updating a todo <a href=\"#updating-a-todo\" class=\"anchor\" id=\"updating-a-todo\" title=\"Anchor for Updating a todo\">#<\/a><\/h3>\n\n\n\n<p>The page for updating a todo is also the one that gets the detail of a todo.<\/p>\n\n\n\n<p>Open the endpoint <code>\/api\/v1\/todos\/4\/<\/code> to get the detail of the todo with id 4 and scroll down to the HTML form:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"701\" height=\"562\" src=\"https:\/\/www.pythontutorial.net\/wp-content\/uploads\/2023\/08\/django-rest-framework-update-todo.png\" alt=\"\" class=\"wp-image-6685\" srcset=\"https:\/\/www.pythontutorial.net\/wp-content\/uploads\/2023\/08\/django-rest-framework-update-todo.png 701w, https:\/\/www.pythontutorial.net\/wp-content\/uploads\/2023\/08\/django-rest-framework-update-todo-300x241.png 300w\" sizes=\"auto, (max-width: 701px) 100vw, 701px\" \/><\/figure>\n\n\n\n<p>Second, modify some values of the <code>Todo<\/code> JSON, and click the PUT button to issue a <code>PUT<\/code> request, and you&#8217;ll get the following response:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"706\" height=\"401\" src=\"https:\/\/www.pythontutorial.net\/wp-content\/uploads\/2023\/08\/django-rest-framework-update-todo-response.png\" alt=\"\" class=\"wp-image-6686\" srcset=\"https:\/\/www.pythontutorial.net\/wp-content\/uploads\/2023\/08\/django-rest-framework-update-todo-response.png 706w, https:\/\/www.pythontutorial.net\/wp-content\/uploads\/2023\/08\/django-rest-framework-update-todo-response-300x170.png 300w\" sizes=\"auto, (max-width: 706px) 100vw, 706px\" \/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\" id='deleting-a-todo'>Deleting a todo <a href=\"#deleting-a-todo\" class=\"anchor\" id=\"deleting-a-todo\" title=\"Anchor for Deleting a todo\">#<\/a><\/h3>\n\n\n\n<p>Open the endpoint to view the todo with id 4: <code>\/api\/v1\/todos\/4\/<\/code> and click the Delete button:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"709\" height=\"278\" src=\"https:\/\/www.pythontutorial.net\/wp-content\/uploads\/2023\/08\/django-rest-framework-delete-todo-response.png\" alt=\"\" class=\"wp-image-6687\" srcset=\"https:\/\/www.pythontutorial.net\/wp-content\/uploads\/2023\/08\/django-rest-framework-delete-todo-response.png 709w, https:\/\/www.pythontutorial.net\/wp-content\/uploads\/2023\/08\/django-rest-framework-delete-todo-response-300x118.png 300w\" sizes=\"auto, (max-width: 709px) 100vw, 709px\" \/><\/figure>\n\n\n\n<p>It&#8217;ll prompt for the delete confirmation: <\/p>\n\n\n\n<figure class=\"wp-block-image size-full border\"><img loading=\"lazy\" decoding=\"async\" width=\"615\" height=\"150\" src=\"https:\/\/www.pythontutorial.net\/wp-content\/uploads\/2023\/08\/django-rest-framework-delete-confirmation.png\" alt=\"\" class=\"wp-image-6707\" srcset=\"https:\/\/www.pythontutorial.net\/wp-content\/uploads\/2023\/08\/django-rest-framework-delete-confirmation.png 615w, https:\/\/www.pythontutorial.net\/wp-content\/uploads\/2023\/08\/django-rest-framework-delete-confirmation-300x73.png 300w\" sizes=\"auto, (max-width: 615px) 100vw, 615px\" \/><\/figure>\n\n\n\n<p>If you click the Delete button, you&#8217;ll get the following response:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"709\" height=\"278\" src=\"https:\/\/www.pythontutorial.net\/wp-content\/uploads\/2023\/08\/django-rest-framework-delete-todo-response.png\" alt=\"\" class=\"wp-image-6687\" srcset=\"https:\/\/www.pythontutorial.net\/wp-content\/uploads\/2023\/08\/django-rest-framework-delete-todo-response.png 709w, https:\/\/www.pythontutorial.net\/wp-content\/uploads\/2023\/08\/django-rest-framework-delete-todo-response-300x118.png 300w\" sizes=\"auto, (max-width: 709px) 100vw, 709px\" \/><\/figure>\n\n\n\n<p>The API issued a <code>DELETE<\/code> request to the endpoint and returned HTTP status 204 to indicate that the todo has been deleted successfully.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id='download-the-project'>Download the project <a href=\"#download-the-project\" class=\"anchor\" id=\"download-the-project\" title=\"Anchor for Download the project\">#<\/a><\/h2>\n\n\n\n<p><a href=\"https:\/\/www.pythontutorial.net\/wp-content\/uploads\/2023\/08\/todolist2.zip\">Download the project source code here.<\/a><\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id='summary'>Summary <a href=\"#summary\" class=\"anchor\" id=\"summary\" title=\"Anchor for Summary\">#<\/a><\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Use Django REST Framework to build RESTful API quickly.<\/li>\n\n\n\n<li>The steps for defining API are creating a serializer class (<code>serializers.py<\/code>), defining views (<code>views.py<\/code>), and wiring up the views with URLs (<code>urls.py<\/code>).<\/li>\n\n\n\n<li>Use the browsable API interface to interact with APIs.<\/li>\n<\/ul>\n<div class=\"helpful-block-content\" data-title=\"\">\n\t<header>\n\t\t<div class=\"wth-question\">Was this tutorial helpful ?<\/div>\n\t\t<div class=\"wth-thumbs\">\n\t\t\t<button\n\t\t\t\tdata-post=\"6679\"\n\t\t\t\tdata-post-url=\"https:\/\/www.pythontutorial.net\/django-tutorial\/django-rest-framework\/\"\n\t\t\t\tdata-post-title=\"Django REST Framework\"\n\t\t\t\tdata-response=\"1\"\n\t\t\t\tclass=\"wth-btn-rounded wth-yes-btn\"\n\t\t\t>\n\t\t\t\t<svg\n\t\t\t\t\txmlns=\"http:\/\/www.w3.org\/2000\/svg\"\n\t\t\t\t\tviewBox=\"0 0 24 24\"\n\t\t\t\t\tfill=\"none\"\n\t\t\t\t\tstroke=\"currentColor\"\n\t\t\t\t\tstroke-width=\"2\"\n\t\t\t\t\tstroke-linecap=\"round\"\n\t\t\t\t\tstroke-linejoin=\"round\"\n\t\t\t\t\tclass=\"feather feather-thumbs-up block w-full h-full\"\n\t\t\t\t>\n\t\t\t\t\t<path\n\t\t\t\t\t\td=\"M14 9V5a3 3 0 0 0-3-3l-4 9v11h11.28a2 2 0 0 0 2-1.7l1.38-9a2 2 0 0 0-2-2.3zM7 22H4a2 2 0 0 1-2-2v-7a2 2 0 0 1 2-2h3\"\n\t\t\t\t\t><\/path>\n\t\t\t\t<\/svg>\n\t\t\t\t<span class=\"sr-only\"> Yes <\/span>\n\t\t\t<\/button>\n\n\t\t\t<button\n\t\t\t\tdata-response=\"0\"\n\t\t\t\tdata-post=\"6679\"\n\t\t\t\tdata-post-url=\"https:\/\/www.pythontutorial.net\/django-tutorial\/django-rest-framework\/\"\n\t\t\t\tdata-post-title=\"Django REST Framework\"\n\t\t\t\tclass=\"wth-btn-rounded wth-no-btn\"\n\t\t\t>\n\t\t\t\t<svg\n\t\t\t\t\txmlns=\"http:\/\/www.w3.org\/2000\/svg\"\n\t\t\t\t\tviewBox=\"0 0 24 24\"\n\t\t\t\t\tfill=\"none\"\n\t\t\t\t\tstroke=\"currentColor\"\n\t\t\t\t\tstroke-width=\"2\"\n\t\t\t\t\tstroke-linecap=\"round\"\n\t\t\t\t\tstroke-linejoin=\"round\"\n\t\t\t\t>\n\t\t\t\t\t<path\n\t\t\t\t\t\td=\"M10 15v4a3 3 0 0 0 3 3l4-9V2H5.72a2 2 0 0 0-2 1.7l-1.38 9a2 2 0 0 0 2 2.3zm7-13h2.67A2.31 2.31 0 0 1 22 4v7a2.31 2.31 0 0 1-2.33 2H17\"\n\t\t\t\t\t><\/path>\n\t\t\t\t<\/svg>\n\t\t\t\t<span class=\"sr-only\"> No <\/span>\n\t\t\t<\/button>\n\t\t<\/div>\n\t<\/header>\n\n\t<div class=\"wth-form hidden\">\n\t\t<div class=\"wth-form-wrapper\">\n\t\t\t<div class=\"wth-title\"><\/div>\n\t\t\t<textarea class=\"wth-message\"><\/textarea>\n\t\t\t<input type=\"button\" name=\"wth-submit\" class=\"wth-btn wth-btn-submit\" id=\"wth-submit\" \/>\n\t\t\t<input type=\"button\" class=\"wth-btn wth-btn-cancel\" value=\"Cancel\" \/>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>In this tutorial, you will learn about the Django REST Framework and how to use it to create a simple but complete RESTful API that manages todos.<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":5531,"menu_order":39,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-6679","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/www.pythontutorial.net\/wp-json\/wp\/v2\/pages\/6679","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.pythontutorial.net\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/www.pythontutorial.net\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/www.pythontutorial.net\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.pythontutorial.net\/wp-json\/wp\/v2\/comments?post=6679"}],"version-history":[{"count":0,"href":"https:\/\/www.pythontutorial.net\/wp-json\/wp\/v2\/pages\/6679\/revisions"}],"up":[{"embeddable":true,"href":"https:\/\/www.pythontutorial.net\/wp-json\/wp\/v2\/pages\/5531"}],"wp:attachment":[{"href":"https:\/\/www.pythontutorial.net\/wp-json\/wp\/v2\/media?parent=6679"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}