{"id":329336,"date":"2023-09-28T12:58:36","date_gmt":"2023-09-28T12:58:36","guid":{"rendered":"http:\/\/itteacheritfreelance.hk\/wordpress\/?guid=5215d67bf205ea141113573976493235"},"modified":"2023-09-28T12:58:36","modified_gmt":"2023-09-28T12:58:36","slug":"building-apis-with-django-rest-framework","status":"publish","type":"post","link":"https:\/\/itteacheritfreelance.hk\/wordpress\/index.php\/2023\/09\/28\/building-apis-with-django-rest-framework\/","title":{"rendered":"Building APIs With Django REST Framework"},"content":{"rendered":"<p class=\"syndicated-attribution\"><meta name= \\\"keywords \\\" content= \\\"\u96fb\u5b50\u8a08\u7b97\u6a5f, \u6559\u80b2, IT \u96fb\u8166\u73ed,\u96fb\u8166\u88dc\u7fd2\uff0c \u96fb\u8166\u73ed\uff0c \u5bb6\u6559\uff0c \u79c1\u4eba\u8001\u5e2b\uff0c \u8cc7\u8a0a\u6280\u8853\uff0c \u7a0b\u5e8f\u8a2d\u8a08\uff0c \u96fb\u5b50\u8a08\u7b97\u6a5f\uff0c \u904a\u6232\uff0c \u860b\u679c\uff0c \u96fb\u5f71\uff0c \u8a08\u7b97\u6a5f\uff0c\u7de8\u78bc\uff0c Java\uff0c C\/C++\uff0c JavaScript\uff0c PHP\uff0c HTML\uff0c CSS\uff0c MySQL\uff0c mobile\uff0c Android\uff0c \u52d5\u6f2b\uff0c Python\uff0c teacher\uff0c \u88dc\u7fd2\uff0c \u96fb\u8166\u88dc\u7fd2 \u8cc7\u8a0a, \u7535\u5b50\u8ba1\u7b97\u673a, IT ,Game, apple, movie, Computer,student,Java,\u6559\u80b2, ,\u5b66\u751f, \u5b66\u4e60, learn, \u6559\u5b66,  Android, apple,anime, animation, \u4fe1\u606f\u6280\u672f, \u7a0b\u5e8f\u8bbe\u8ba1, \u79fb\u52a8\u7535\u8bdd, \u8cc7\u8a0a\u79d1\u6280,Game, Jeu, Juego,Call Of Duty ,\u4f7f\u547d\u53ec\u559a , \u6e38\u620f, \u7535\u5b50\u6e38\u620f,, \u591a\u4eba\u7535\u5b50\u6e38\u620f, \u7f51\u7edc\u6e38\u620f\uff0conline\uff0conline game, \u624b\u673a\u6e38\u620f, mobile \\\"><\/p>\n<p>In this Django REST framework tutorial, you will create a rental platform API. The tutorial demonstrates how to use Python and Django REST framework in PyCharm to develop APIs.<\/p>\n<p>By the time you complete the tutorial, you will be able to answer the following questions:<\/p>\n<ul>\n<li>What are Django REST framework serializers and how do I create them out of Django models?<\/li>\n<li>How do I write concise and idiomatic views with the help of Django REST framework?<\/li>\n<li>How do I test APIs by using PyCharm\u2019s <strong>Endpoints<\/strong> tool window and the built-in <strong>HTTP Client<\/strong>?<\/li>\n<li>What is the browsable API?<\/li>\n<li>How do I set up authentication and permissions for an API?<\/li>\n<\/ul>\n<h2 class=\"wp-block-heading\">Prerequisites<\/h2>\n<p>To successfully complete the Django REST framework tutorial, you\u2019ll need the following:<\/p>\n<ul>\n<li><a href=\"https:\/\/www.jetbrains.com\/pycharm\/download\/\"  rel=\"noopener\">PyCharm Professional<\/a> (a free 30-day trial is available). This tutorial has been created in <strong>PyCharm Professional 2023.2.1<\/strong><\/li>\n<li>General understanding of the concept of RESTful APIs<\/li>\n<li>Previous experience with Python and Django (you can start with our <a href=\"https:\/\/blog.jetbrains.com\/pycharm\/2023\/04\/create-a-django-app-in-pycharm\/\">Django tutorial<\/a>)<\/li>\n<\/ul>\n<p>You can find the full code of the project in this <a href=\"https:\/\/github.com\/denis-mashutin\/apiTutorial\"  rel=\"noopener\">repository<\/a>.<\/p>\n<h2 class=\"wp-block-heading\">Setting up a project<\/h2>\n<p>Click <strong>New Project<\/strong> on PyCharm\u2019s Welcome screen or select <strong>File | New Project<\/strong> from the main menu. When the <strong>New Project<\/strong> window opens, choose <strong>Django<\/strong> as the project type in the left-hand pane and do the following:<\/p>\n<ol>\n<li>Specify the project directory, which will also be used as the project name (<kbd>apiTutorial<\/kbd> in our example).<\/li>\n<li>Choose the type of virtual environment for your project (we will use <strong>virtualenv<\/strong>).<\/li>\n<li>Expand the <strong>More Settings<\/strong> section and provide the application name (<kbd>rental<\/kbd>).<\/li>\n<\/ol>\n<p>You also need to disable the <strong>Enable Django admin<\/strong> checkbox. We will create the admin user manually later.<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img decoding=\"async\" fetchpriority=\"high\" width=\"1600\" height=\"1300\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2023\/09\/01_create_django_project-1.png\" alt=\"Creating a Django project in PyCharm\" class=\"wp-image-391706\"\/><\/figure>\n<\/div>\n<p>When you click <strong>Create<\/strong>, PyCharm will set up the project and install Django in the project environment.<\/p>\n<p>The Django REST framework package needs to be installed manually. Open the <strong>Python Packages<\/strong> tool window by clicking its icon on the left. Search for the <kbd>djangorestframework<\/kbd> package and install the latest version. In this tutorial, we\u2019ve used version 3.14.0.<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"2178\" height=\"1314\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2023\/09\/02_install_drf_package-1.png\" alt=\"Installing the djangorestframework package\" class=\"wp-image-391717\"\/><\/figure>\n<\/div>\n<p>Now we need to update <code>INSTALLED_APPS<\/code> in <strong>settings.py<\/strong>. Here\u2019s PyCharm\u2019s shortcut for that:<\/p>\n<ol>\n<li>Open <strong>Search Everywhere<\/strong> by pressing \u21e7 <strong>(Shift)<\/strong> twice.<\/li>\n<li>Press <strong>Tab<\/strong> several times until you\u2019re on the <strong>Symbols<\/strong> tab.<\/li>\n<li>Type the first letters of the desired symbol (variable, class, etc.) to find it, for example, \u201c<kbd>insapp<\/kbd>\u201d<em>.<\/em><\/li>\n<\/ol>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2023\/09\/03_open_settings.png\" alt=\"Opening settings.py | INSTALLED_APPS\" class=\"wp-image-391728\" style=\"object-fit:contain;width:400px;height:299px\" width=\"400\" height=\"299\"\/><\/figure>\n<\/div>\n<ol start=\"4\">\n<li>Press <strong>Enter<\/strong> to jump to the desired symbol and add <em>\u2018<\/em><code>rest_framework<\/code><em>\u2019<\/em> to <code>INSTALLED_APPS<\/code>.<\/li>\n<\/ol>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img decoding=\"async\" loading=\"lazy\" width=\"2164\" height=\"1316\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2023\/09\/04_edit_settings.png\" alt=\"Adding \u2018rest_framework\u2019 to INSTALLED_APPS\" class=\"wp-image-391739\"\/><\/figure>\n<\/div>\n<h2 class=\"wp-block-heading\">Creating serializers<\/h2>\n<h3 class=\"wp-block-heading\">What are Django REST framework serializers?<\/h3>\n<p>In general, serializers are used to \u201ctranslate\u201d Django model instances or querysets into other formats, usually JSON or XML, so that they can be sent in the body of an HTTP response. Serializers also provide deserialization when text data from an HTTP request is parsed, validated, and converted into a model instance.<\/p>\n<p>The processes of serialization and deserialization are crucial for any API, and Django REST framework can take it over completely. Thanks to its <code>ModelSerializer<\/code> class, we can generate a serializer for any model in just two lines of code.<\/p>\n<p>But we still need to create a model. Let\u2019s do that.<\/p>\n<h3 class=\"wp-block-heading\">Writing a model-based serializer<\/h3>\n<p>Use <strong>Search Everywhere<\/strong> (double Shift) or the <strong>Project<\/strong> tool window (<strong>\u23181 \/ Alt+1<\/strong>) to open <strong>rental\/models.py<\/strong>, and copy the following code into the editor:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">from django.db import models\n\nSIZE_CHOICES = [\n    ('ST', 'Studio'),\n    ('1BR', '1 bedroom'),\n    ('2BR', '2 bedrooms'),\n    ('3BR', '3 bedrooms'),\n    ('MBR', '3+ bedrooms'),\n]\nTYPE_CHOICES = [\n    ('H', 'house'),\n    ('APT', 'apartment'),\n]\n\n\nclass Offer(models.Model):\n    created = models.DateTimeField(auto_now_add=True)\n    address = models.CharField(max_length=100, blank=True, default='')\n    size = models.CharField(choices=SIZE_CHOICES, default='1BR', max_length=100)\n    type = models.CharField(choices=TYPE_CHOICES, default='APT', max_length=100)\n    price = models.PositiveIntegerField(default=0)\n    sharing = models.BooleanField(default=False)\n    text = models.TextField(default='')\n\n    class Meta:\n        ordering = ['created']<\/pre>\n<p>Note that all fields of the <code>Offer<\/code> model have defaults, which means that we can create an instance without providing any field values. Additionally, we\u2019ve provided <a href=\"https:\/\/docs.djangoproject.com\/en\/4.2\/ref\/models\/fields\/#choices\"  rel=\"noopener\">choices<\/a> for the <code>size<\/code> and <code>type<\/code> fields.<\/p>\n<p>Now let\u2019s run migrations. Open PyCharm\u2019s <strong>manage.py <\/strong>console by pressing <strong>\u2325R\/ Ctrl+Alt+R<\/strong> and type \u201c<kbd>makemigrations<\/kbd>\u201d followed by \u201c<kbd>migrate<\/kbd>\u201d<em>.<\/em> Code completion is available, so you don\u2019t need to type out the whole commands.<\/p>\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" loading=\"lazy\" width=\"1766\" height=\"492\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2023\/09\/05_run_migrations.png\" alt=\"Running migrations in the manage.py console\" class=\"wp-image-391750\"\/><\/figure>\n<p>We need to create <strong>serializers.py<\/strong> in the <strong>rental<\/strong> directory. Select the directory in the <strong>Project<\/strong> tool window (<strong>\u23181 \/ Alt+1<\/strong>), press <strong>\u2318N \/ Alt+Insert<\/strong>, select <strong>Python File<\/strong>, and specify \u201c<kbd>serializers<\/kbd><em>\u201d<\/em> as the file name.<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img decoding=\"async\" loading=\"lazy\" width=\"1854\" height=\"1310\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2023\/09\/06_create_serializers.png\" alt=\"Creating serializers.py\" class=\"wp-image-391761\"\/><\/figure>\n<\/div>\n<p>The newly created file opens in the editor. Fill it with the following code:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">from rest_framework import serializers\nfrom rental.models import Offer\n\n\nclass OfferSerializer(serializers.ModelSerializer):\n    class Meta:\n        model = Offer\n        fields = ['id', 'address', 'size', 'type', 'price', 'sharing', 'text']<\/pre>\n<p>As you can see, <code>OfferSerializer<\/code> inherits from the <code>ModelSerializer<\/code> provided by Django REST framework and is defined with only two lines of code. On line 7 we\u2019ve specified the base model (which is imported from <strong>rental\/models<em> <\/em><\/strong>on line 2), while line 8 contains the list of model fields to be serialized.<\/p>\n<p>For more information about Django REST framework serializers, see <a href=\"https:\/\/www.django-rest-framework.org\/api-guide\/serializers\/\"  rel=\"noopener\">https:\/\/www.django-rest-framework.org\/api-guide\/serializers\/<\/a>.<\/p>\n<h3 class=\"wp-block-heading\">Using the serializer to save data<\/h3>\n<p>Let\u2019s use the newly created serializer to add data into the database. Open the Python console by clicking the corresponding icon on the left and run the following code in it:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">from rental.models import Offer\noffer = Offer(text='A cozy space in \"loft\" style.\\nPerfect for young couples')\noffer.save()\noffer = Offer(text='A warm house for a big family')\noffer.save()<\/pre>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img decoding=\"async\" loading=\"lazy\" width=\"1954\" height=\"1410\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2023\/09\/07_add_offer_manually.png\" alt=\"Creating an offer instance in the Python console\" class=\"wp-image-391772\"\/><\/figure>\n<\/div>\n<p>We\u2019ve created two instances of the <code>Offer<\/code> model and saved them into the database by using the built-in <code>save()<\/code> method.<\/p>\n<p>Now let\u2019s open the database. Your project contains <strong>db.sqlite3<\/strong>, which can be opened either from the <strong>Project<\/strong> tool window or by using <strong>Search Everywhere<\/strong>. When you open the database for the first time, PyCharm will register it as the project data source. The <strong>Data Sources and Drivers<\/strong> window will open.<\/p>\n<p>Click <strong>Test Connection. <\/strong>If you see a warning saying that you need to install, update, or switch the database driver, perform the required action. Then click <strong>OK<\/strong> to finish adding the data source to the project.<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full is-resized\"><img decoding=\"async\" loading=\"lazy\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2023\/09\/11_configure_database.png\" alt=\"Adding the database as a project data source\" class=\"wp-image-391783\" style=\"object-fit:contain;width:600px;height:499px\" width=\"600\" height=\"499\"\/><\/figure>\n<\/div>\n<p>When the <strong>Database<\/strong> tool window opens, expand the structure of the <strong>db<\/strong> data source until you see the <strong>rental_offer<\/strong> table.<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full is-resized\"><img decoding=\"async\" loading=\"lazy\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2023\/09\/111_explore_database.png\" alt=\"Exploring the database structure\" class=\"wp-image-391807\" style=\"object-fit:contain;width:400px;height:501px\" width=\"400\" height=\"501\"\/><\/figure>\n<\/div>\n<p>Click it to browse its contents in the editor.<\/p>\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" loading=\"lazy\" width=\"1910\" height=\"442\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2023\/09\/12_view_table.png\" alt=\"Exploring the database table in the editor\" class=\"wp-image-391818\"\/><\/figure>\n<p>As you can see, there are two records in the database table now. We didn\u2019t provide values in any of the fields except <code>text<\/code>, which is why the default values from the model definition have been used.<\/p>\n<h2 class=\"wp-block-heading\">Providing REST API logic<\/h2>\n<h3 class=\"wp-block-heading\">Writing function-based views<\/h3>\n<p>We\u2019ve successfully added two rental offers manually, but we want the API to be able to do that automatically based on the incoming requests. Let\u2019s start creating the API\u2019s logic in <strong>rental\/views.py<\/strong>. Open the file and fill it with the following code:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">from rest_framework import status\nfrom rest_framework.decorators import api_view\nfrom rest_framework.response import Response\nfrom rental.models import Offer\nfrom rental.serializers import OfferSerializer\n\n\n@api_view(['GET', 'POST'])\ndef offer_list(request):\n    if request.method == 'GET':\n        offers = Offer.objects.all()\n        serializer = OfferSerializer(offers, many=True)\n        return Response(serializer.data)\n\n    elif request.method == 'POST':\n        serializer = OfferSerializer(data=request.data)\n        if serializer.is_valid():\n            serializer.save()\n            return Response(serializer.data, status=status.HTTP_201_CREATED)\n        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)<\/pre>\n<p>We\u2019ve added a function-based view called <code>offer_list<\/code>. It will be used to provide information about available rental offers, as well as to add new offers to the database. Here\u2019s what\u2019s inside:<\/p>\n<ul>\n<li><code>@api_view<\/code> (line 8)<em> <\/em>is the Django REST framework decorator for function-based views. <code>GET<\/code> and <code>POST<\/code> are the methods accepted by this view.<\/li>\n<li>If the request method is <code>GET<\/code>, a queryset with all offers in the database is created (line 11) and serialized (line 12). In this case, the body of the response contains data about all available offers in JSON form. The response is sent with the default status code (<code>200 OK<\/code>).<\/li>\n<li>If the request method is <code>POST<\/code>, <code>OfferSerializer<\/code> is used to deserialize data from the request (line 16). If the data is validated successfully (line 17), it\u2019s saved to the database (line 18). The response contains the saved data and has the status code <code>201 Created <\/code>(line 19).<\/li>\n<li>If validation fails, the API will return the error info with the status <code>400 Bad Request.<\/code><\/li>\n<\/ul>\n<p>It would also be useful if we could obtain information about any specific offer, edit that information, and remove offers from the database. Let\u2019s add another view and call it <code>offer_detail<\/code>:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">@api_view(['GET', 'PUT', 'DELETE'])\ndef offer_detail(request, pk):\n    try:\n        offer = Offer.objects.get(pk=pk)\n    except Offer.DoesNotExist:\n        return Response(status=status.HTTP_404_NOT_FOUND)\n\n    if request.method == 'GET':\n        serializer = OfferSerializer(offer)\n        return Response(serializer.data)\n\n    elif request.method == 'PUT':\n        serializer = OfferSerializer(offer, data=request.data)\n        if serializer.is_valid():\n            serializer.save()\n            return Response(serializer.data)\n        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)\n\n    elif request.method == 'DELETE':\n        offer.delete()\n        return Response(status=status.HTTP_204_NO_CONTENT)<\/pre>\n<p>This view accepts three methods (<code>GET<\/code>, <code>PUT<\/code>, and <code>DELETE<\/code>) and works as follows:<\/p>\n<ul>\n<li>First of all, it checks whether the offer whose ID has been specified in the <code>pk<\/code> parameter exists in the database (line 4). If it doesn\u2019t, <code>404 Not Found<\/code> is returned.<\/li>\n<li>For <code>GET<\/code> requests, the API serializes the offer data (line 9) and returns it in the response body.<\/li>\n<li>For <code>PUT<\/code> requests, the API serializes the offer data from the database and merges it with the data from the request body (line 13). If the validation is successful (line 14), the updated offer is saved to the database (line 15) and returned in the response body (line 16). Otherwise, the error info is returned with the <code>400 Bad Request status<\/code>.<\/li>\n<li>Finally, for <code>DELETE<\/code> requests, the API deletes the offer and returns <code>204 No Content.<\/code><\/li>\n<\/ul>\n<p>Now that we\u2019ve defined the API\u2019s logic, we have only one step left before we can use our API. We need to define Django URLs, also known as API endpoints.<\/p>\n<h3 class=\"wp-block-heading\">Defining and testing API endpoints<\/h3>\n<p>Let\u2019s start by creating <strong>urls.py<\/strong> in the app directory and filling it with the following code:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">from django.urls import path\nfrom rental import views\n\nurlpatterns = [\n    path('offers\/', views.offer_list),\n    path('offers\/&lt;int:pk>\/', views.offer_detail),\n]<\/pre>\n<p>We\u2019ve defined two endpoints for our two views. Don\u2019t forget to include <strong>rental\/urls.py<\/strong> in the project\u2019s <strong>urls.py<\/strong> file:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">from django.urls import path,include\n\nurlpatterns = [\n    path('', include('rental.urls')),\n]<\/pre>\n<p>Let\u2019s open the <strong>Endpoints<\/strong> tool window. In case you haven\u2019t used it before, you can find it under the meatball menu on the left.<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full is-resized\"><img decoding=\"async\" loading=\"lazy\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2023\/09\/13_open_endpoints.png\" alt=\"Opening the Endpoints tool window\" class=\"wp-image-391829\" style=\"object-fit:contain;width:400px;height:420px\" width=\"400\" height=\"420\"\/><\/figure>\n<\/div>\n<p>The tool window displays all available endpoints and methods.<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full is-resized\"><img decoding=\"async\" loading=\"lazy\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2023\/09\/14_explore_endpoints.png\" alt=\"Endpoints tool window\" class=\"wp-image-391840\" style=\"object-fit:contain;width:400px;height:528px\" width=\"400\" height=\"528\"\/><\/figure>\n<\/div>\n<p>Before testing the API, make sure that the Django server is running. On project creation, PyCharm automatically set up the run configuration. Just launch it from the <strong>Run<\/strong> widget in the window header. Note the server address (usually, <em>localhost<\/em>) and port number in the <strong>Run<\/strong> tool window that opens.<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img decoding=\"async\" loading=\"lazy\" width=\"1616\" height=\"1076\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2023\/09\/15_launch_django_server.png\" alt=\"Launching the Django server\" class=\"wp-image-391851\"\/><\/figure>\n<\/div>\n<p>Let\u2019s go back to the <strong>Endpoints<\/strong> tool window. Select <strong>offers\/GET<\/strong> in the list and switch to the <strong>HTTP Client<\/strong> tab at the bottom. Edit the port number if needed and then click <strong>Submit Request<\/strong>.<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full is-resized\"><img decoding=\"async\" loading=\"lazy\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2023\/09\/16_submit_get_request.png\" alt=\"Submitting the GET request\" class=\"wp-image-391862\" style=\"object-fit:contain;width:400px;height:546px\" width=\"400\" height=\"546\"\/><\/figure>\n<\/div>\n<p>PyCharm runs the request and saves the response body to a file. You can either scroll up to explore the response or click the link to open the file in the editor.<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full is-resized\"><img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2023\/09\/17_explore_response.png\" alt=\"Response file in the editor\" class=\"wp-image-391873\" style=\"width:600px\" width=\"600\"\/><\/figure>\n<\/div>\n<p>Let\u2019s submit a <code>DELETE<\/code> request to remove the second offer (<code>DELETE <a href=\"http:\/\/localhost:8000\/offers\/2\/\"  rel=\"noopener\">http:\/\/localhost:8000\/offers\/2\/<\/a><\/code>) and then submit another request for the list of available offers. Now only one offer is available.<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full is-resized\"><img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2023\/09\/18_delete_and_get_again.png\" alt=\"List of available offers after running the DELETE API request\" class=\"wp-image-391884\" style=\"width:600px\" width=\"600\"\/><\/figure>\n<\/div>\n<p>Another amazing feature of Django REST framework is its <a href=\"https:\/\/www.django-rest-framework.org\/topics\/browsable-api\/\"  rel=\"noopener\">browsable API<\/a>. Opening <a href=\"http:\/\/127.0.0.1:8000\/offers\/1\/\" >http:\/\/127.0.0.1:8000\/offers\/<\/a> in your browser brings you to a page where you can view the list of available offers and add new ones.<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full is-resized\"><img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2023\/09\/19_browsable_api.png\" alt=\"Using the Django REST framework\u2019s browsable API\" class=\"wp-image-391895\" style=\"width:600px\" width=\"600\"\/><\/figure>\n<\/div>\n<h3 class=\"wp-block-heading\">Implementing generic class-based views<\/h3>\n<p>When speaking about the amazing features of Django REST framework, it\u2019s impossible not to mention <a href=\"https:\/\/www.django-rest-framework.org\/tutorial\/3-class-based-views\/#using-generic-class-based-views\"  rel=\"noopener\">generic class-based views<\/a>. Let\u2019s use them to rewrite the code in <strong>rental\/views.py<\/strong>:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"1\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">from rest_framework import generics\nfrom rental.models import Offer\nfrom rental.serializers import OfferSerializer\n\n\nclass OfferList(generics.ListCreateAPIView):\n    queryset = Offer.objects.all()\n    serializer_class = OfferSerializer\n\n\nclass OfferDetails(generics.RetrieveUpdateDestroyAPIView):\n    queryset = Offer.objects.all()\n    serializer_class = OfferSerializer<\/pre>\n<p>Now each view is just three lines of code! You only need to worry about choosing the right generic class to inherit from. As we\u2019re not using feature-based views anymore, we need to update <strong>rental\/urls.py<\/strong>:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">urlpatterns = [\n    path('offers\/', views.OfferList.as_view()),\n    path('offers\/&lt;int:pk>\/', views.OfferDetails.as_view()),\n]<\/pre>\n<p>Will the API work now? Let\u2019s check. This time, we\u2019ll attempt to submit invalid data to see how validation works.<\/p>\n<p>Go to the <strong>Endpoints<\/strong> tool window. Now there are additional <code>OPTIONS<\/code> and <code>PATCH<\/code> methods, which come from generic views. Select <strong>offers\/[POST<\/strong>] from the list of endpoints and click <strong>Open in Editor<\/strong>. PyCharm creates an <strong>.http<\/strong> file and copies the endpoint into it. Provide the request body in JSON format and submit the request.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">POST http:\/\/localhost:8000\/offers\/\nContent-Type: application\/json\n\n{\n  \"address\": \"\",\n  \"size\": \"8BR\",\n  \"type\": \"H\",\n  \"price\": 1000000,\n  \"sharing\": true,\n  \"text\": \"A spacious villa for a large family.\"\n}<\/pre>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img decoding=\"async\" loading=\"lazy\" width=\"1712\" height=\"1228\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2023\/09\/20_submit_post_request.png\" alt=\"Submitting a request from the editor\" class=\"wp-image-391906\"\/><\/figure>\n<\/div>\n<p>In the <strong>Services<\/strong> tool window that opens, you\u2019ll notice that the response has the <code>400 Bad Request<\/code> status. Click the link to open the JSON file with the response.<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full is-resized\"><img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2023\/09\/21_bad_request_status.png\" alt=\"Errors in the response body\" class=\"wp-image-391917\" style=\"width:400px\" width=\"400\"\/><\/figure>\n<\/div>\n<p>As you can see, the offer hasn\u2019t been added, because we specified the wrong value in <code>size<\/code>. According to the <code>Offer<\/code> model, we should use <code>MBR<\/code> when there are more than 3 bedrooms. Let\u2019s edit the request and submit it again.<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full is-resized\"><img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2023\/09\/22_successful_post.png\" alt=\"Successful POST request\" class=\"wp-image-391928\" style=\"width:600px\" width=\"600\"\/><\/figure>\n<\/div>\n<h2 class=\"wp-block-heading\">Enabling authentication and permissions<\/h2>\n<p>At the moment, anyone who knows the endpoint address can add, edit, and remove offers. This is not a normal situation in the real world. Normally, you\u2019d like to have control over who can do what with your API. That can be achieved by implementing authentication and permissions.<\/p>\n<h3 class=\"wp-block-heading\">Introducing users<\/h3>\n<p>First of all, we need to introduce the concept of users. Let\u2019s start by adding the <code>author<\/code> field to the <code>Offer<\/code> model:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">    author = models.ForeignKey('auth.User', related_name='offers', on_delete=models.CASCADE)<\/pre>\n<p>This field has the <code>ForeignKey<\/code> type, which means that it\u2019s used to represent the relationships between offers and the users who create them.<\/p>\n<p>As we\u2019ve updated the model, we need to reset the database and recreate the<em> <\/em><strong>rental_offer<\/strong> table in it, now with the <code>author<\/code> field. To achieve this, perform the following steps:<\/p>\n<ol>\n<li>Open the <strong>manage.py<\/strong> console ( <strong>\u2325R<\/strong> <strong>\/ Ctrl+Alt+R<\/strong> ) and run the following commands one at a time:<\/li>\n<\/ol>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">> flush\n> migrate rental zero<\/pre>\n<ol start=\"2\">\n<li>In the <strong>rental\/migrations<\/strong> directory, remove all migrations, keeping only <em>__init__.py<\/em>.<\/li>\n<li>Then continue in the <strong>manage.py<\/strong> console:<\/li>\n<\/ol>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">> makemigrations\n> migrate<\/pre>\n<p>To make sure that you are ready to proceed, go to the <strong>Database<\/strong> tool window and open the <strong>rental_offer<\/strong> table. It should have the <strong>author_id<\/strong> column.<\/p>\n<p>Then open <strong>rental\/serializers.py<\/strong> and add <code>UserSerializer<\/code>. We will use Django\u2019s built-in <a href=\"https:\/\/docs.djangoproject.com\/en\/4.2\/topics\/auth\/default\/\"  rel=\"noopener\">authentication system<\/a>, so we will just import the existing <code>User<\/code> model:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">from django.contrib.auth.models import User\n...\n\nclass UserSerializer(serializers.ModelSerializer):\n    offers = serializers.PrimaryKeyRelatedField(many=True, queryset=Offer.objects.all())\n\n    class Meta:\n        model = User\n        fields = ['id', 'username', 'offers']<\/pre>\n<p>Update <code>OfferSerializer<\/code> to comply with the newly added <code>author<\/code><em> <\/em>field:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"2,6\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">class OfferSerializer(serializers.ModelSerializer):\n    author = serializers.ReadOnlyField(source='author.username')\n\n    class Meta:\n        model = Offer\n        fields = ['id', 'address', 'size', 'type', 'price', 'sharing', 'text', 'author']<\/pre>\n<p>We also need to define two new views in <strong>rental\/views.py<\/strong>: one for managing the list of all users and another one for user details. The <code>User<\/code> model should be imported here, too, and don\u2019t forget to import the newly created <code>UserSerializer<\/code> from <strong>serializers.py <\/strong>as well.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"1\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">from rental.serializers import OfferSerializer, UserSerializer\n...\nfrom django.contrib.auth.models import User\n...\n\nclass UserList(generics.ListAPIView):\n    queryset = User.objects.all()\n    serializer_class = UserSerializer\n\n\nclass UserDetails(generics.RetrieveAPIView):\n    queryset = User.objects.all()\n    serializer_class = UserSerializer\n<\/pre>\n<p>Update the <code>OfferList<\/code> class to override the default<em> <\/em><code>perform_create()<\/code> method so that the additional <code>author<\/code> field is passed when creating an offer:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"5,6\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">class OfferList(generics.ListCreateAPIView):\n    queryset = Offer.objects.all()\n    serializer_class = OfferSerializer\n\n    def perform_create(self, serializer):\n        serializer.save(author=self.request.user)<\/pre>\n<p>Add the following endpoints for users to <strong>rental\/urls.py<\/strong>:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"4,5\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">urlpatterns = [\n    path('offers\/', views.OfferList.as_view()),\n    path('offers\/&lt;int:pk>\/', views.OfferDetails.as_view()),\n    path('users\/', views.UserList.as_view()),\n    path('users\/&lt;int:pk>\/', views.UserDetails.as_view()),\n]\n<\/pre>\n<h3 class=\"wp-block-heading\">Making authentication required<\/h3>\n<p>Now we need to ensure that only authenticated users are able to add offers through the API. Update both the <code>OfferList<\/code> and <code>OfferDetails<\/code> views with the following properties to set permissions. Authenticated users will be able to add and edit offers, and others will be able to view them:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"2,8,17\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">...\nfrom rest_framework import permissions\n\n\nclass OfferList(generics.ListCreateAPIView):\n    queryset = Offer.objects.all()\n    serializer_class = OfferSerializer\n    permission_classes = [permissions.IsAuthenticatedOrReadOnly]\n\n    def perform_create(self, serializer):\n        serializer.save(author=self.request.user)\n\n\nclass OfferDetails(generics.RetrieveUpdateDestroyAPIView):\n    queryset = Offer.objects.all()\n    serializer_class = OfferSerializer\n    permission_classes = [permissions.IsAuthenticatedOrReadOnly]<\/pre>\n<p>To make sure that things work as expected, let\u2019s run a <code>POST<\/code> request without authentication:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">POST http:\/\/localhost:8000\/offers\/\nContent-Type: application\/json\n\n{\n  \"address\": \"\",\n  \"size\": \"1BR\",\n  \"type\": \"APT\",\n  \"price\": 350000,\n  \"sharing\": false,\n  \"text\": \"A small modern flat. Central location.\"\n}<\/pre>\n<p>You should get a <code>403 Forbidden<\/code> response.<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img decoding=\"async\" loading=\"lazy\" width=\"1708\" height=\"1090\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2023\/09\/23_forbidden_status.png\" alt=\"POST request without authentication credentials\" class=\"wp-image-391939\"\/><\/figure>\n<\/div>\n<p>Let\u2019s create users. Go to the <strong>manage.py<\/strong> console and run the <code>createsuperuser<\/code> command. Remember the username and password you provide.<\/p>\n<p>Before proceeding to the next step, you\u2019ll need the Base64-encoded string consisting of the username and password joined by a single colon. For example, we\u2019ve created \u2018admin\u2019 with the password \u2018pass123\u2019 (merely as an example; in real life, you should always use a much stronger password). Open the <strong>Python<\/strong> console and run the following, replacing \u2018admin:pass123\u2019 with your user credentials:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">>>> import base64\n>>> base64.b64encode(b'admin:pass123')<\/pre>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full is-resized\"><img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2023\/09\/231_encode_credentials.png\" alt=\"Encoding the username and password for basic authorization\" class=\"wp-image-391950\" style=\"width:400px\" width=\"400\"\/><\/figure>\n<\/div>\n<p>Now let\u2019s run the same request but with the <code>Authorization<\/code> header.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">POST http:\/\/localhost:8000\/offers\/\nAuthorization: Basic YWRtaW46cGFzczEyMw==\nContent-Type: application\/json\n\n{\n  \"address\": \"\",\n  \"size\": \"1BR\",\n  \"type\": \"APT\",\n  \"price\": 350000,\n  \"sharing\": false,\n  \"text\": \"A small modern flat. Central location.\"\n}<\/pre>\n<p>You should get a <code>201 Created<\/code> response.<\/p>\n<h3 class=\"wp-block-heading\">Elaborating on permissions<\/h3>\n<p>At the moment, any authenticated user can edit any offer. Let\u2019s set up permissions so that offers can only be edited by their authors.<\/p>\n<p>Create <strong>rental\/permissions.py<\/strong> and fill it with the following code:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">from rest_framework import permissions\n\n\nclass IsAuthorOrReadOnly(permissions.BasePermission):\n    def has_object_permission(self, request, view, obj):\n        return request.method in permissions.SAFE_METHODS or obj.author == request.user<\/pre>\n<p>The <code>IsAuthorOrReadOnly<\/code> class is subclassed from the Django REST framework <code>BasePermission<\/code> class. Permission is unconditionally granted if the request method is one of the <code>SAFE_METHODS<\/code>, which are <code>GET<\/code>, <code>HEAD<\/code>, and <code>OPTIONS<\/code>. Otherwise, the requesting user must be the offer\u2019s author in order to get permission.<\/p>\n<p>Go to <strong>views.py<\/strong>, import the newly created permission, and update <code>permission_classes<\/code> in <code>OfferDetails<\/code>:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"1,9\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">from rental.permissions import IsAuthorOrReadOnly\n...\n\nclass OfferDetails(generics.RetrieveUpdateDestroyAPIView):\n    queryset = Offer.objects.all()\n    serializer_class = OfferSerializer\n    permission_classes = [\n        permissions.IsAuthenticatedOrReadOnly,\n        IsAuthorOrReadOnly\n    ]\n<\/pre>\n<p>Now create another user by running <code>createsuperuser<\/code> in the <strong>manage.py<\/strong> console (we\u2019ll use \u2018jetbrains:jet123\u2019). Then submit the following request to update the offer with ID <em>1 <\/em>(created by the <code>admin<\/code> user):<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">PUT http:\/\/localhost:8000\/offers\/1\/\nAuthorization: Basic amV0YnJhaW5zOmpldDEyMw==\nContent-Type: application\/json\n\n{\"text\":\"A small modern flat. Very central location.\"}<\/pre>\n<p>You should get <code>403 Forbidden <\/code>with &#8220;You do not have permission to perform this action&#8221; in the response details.<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img decoding=\"async\" loading=\"lazy\" width=\"1638\" height=\"944\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2023\/09\/24_forbidden_no_permission.png\" alt=\"403 Forbidden response when a non-author attempts to edit\" class=\"wp-image-391961\"\/><\/figure>\n<\/div>\n<p>Then try the same but with admin\u2019s credentials:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">PUT http:\/\/localhost:8000\/offers\/1\/\nAuthorization: Basic YWRtaW46cGFzczEyMw==\nContent-Type: application\/json\n\n{\"text\":\"A small modern flat. Very central location.\"}<\/pre>\n<p>You should get <code>200 OK<\/code>.<\/p>\n<p>Do we now also have authentication in the browsable API? Let\u2019s see. Open <a href=\"http:\/\/127.0.0.1:8000\/offers\/1\/\" >http:\/\/127.0.0.1:8000\/offers\/1\/<\/a> in the browser. There\u2019s no longer a form associated with the <code>POST<\/code> method, and the <code>DELETE<\/code> button is gone as well. We need to enable the login page to be able to use browsable API for such operations.<\/p>\n<p>Go to the project\u2019s project <strong>urls.py<\/strong> and update it as follows:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"5\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">from django.urls import path, include\n\nurlpatterns = [\n    path('', include('rental.urls')),\n    path('api-auth\/', include('rest_framework.urls')),\n]\n<\/pre>\n<p>Now update the page in the browser. You should see <strong>Log in<\/strong> in the upper right corner. Click it and enter credentials of one of the previously created users to be able to perform actions on offers.<\/p>\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n<p>By completing this tutorial, you have learned to implement the following features of Django REST framework:<\/p>\n<ul>\n<li><code>ModelSerializer<\/code> for creating serializers based on models.<\/li>\n<li>Generic class-based views for writing API logic in a concise and idiomatic way.<\/li>\n<li>Browsable API for easy visualization of available endpoints and data.<\/li>\n<li>Django authentication system for configuring user permissions.<\/li>\n<\/ul>\n<p>Developing Django APIs in PyCharm Professional is smooth and easy thanks to the following:<\/p>\n<ul>\n<li><strong>Manage.py<\/strong> and <strong>Python<\/strong> consoles with code completion.<\/li>\n<li><strong>Endpoints<\/strong> toolwindow with the list of defined endpoints and available methods.<\/li>\n<li>Built-in <strong>HTTP Client<\/strong> that lets you submit requests and view the history of responses.<\/li>\n<\/ul>\n<p>The support of the Django REST framework in PyCharm will be further extended. You can follow the <a href=\"https:\/\/youtrack.jetbrains.com\/issues\/PY?q=tag:%20%7BDjango%20REST%20Framework%7D\"  rel=\"noopener\">issues<\/a> in our task tracker to stay updated.<\/p>\n<h2 class=\"wp-block-heading\">Useful links<\/h2>\n<h3 class=\"wp-block-heading\">PyCharm documentation<\/h3>\n<ul>\n<li><a href=\"https:\/\/www.jetbrains.com\/help\/pycharm\/django-support7.html\"  rel=\"noopener\">Django support in PyCharm<\/a><\/li>\n<li><a href=\"https:\/\/www.jetbrains.com\/help\/pycharm\/creating-django-project.html\"  rel=\"noopener\">Creating a Django project in PyCharm<\/a><\/li>\n<li><a href=\"https:\/\/www.jetbrains.com\/help\/pycharm\/endpoints-tool-window.html\"  rel=\"noopener\">Endpoints tool window in PyCharm<\/a><\/li>\n<li><a href=\"https:\/\/www.jetbrains.com\/help\/pycharm\/running-manage-py.html\"  rel=\"noopener\">Manage.py console in PyCharm<\/a><\/li>\n<\/ul>\n<h3 class=\"wp-block-heading\">Other sources<\/h3>\n<ul>\n<li><a href=\"https:\/\/www.jetbrains.com\/pycharm\/download\/\"  rel=\"noopener\">Download PyCharm Professional<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/denis-mashutin\/apiTutorial\"  rel=\"noopener\">Repository with the project code<\/a><\/li>\n<li><a href=\"https:\/\/blog.jetbrains.com\/pycharm\/2023\/04\/create-a-django-app-in-pycharm\/\">Create a Django App in PyCharm tutorial<\/a><\/li>\n<li><a href=\"https:\/\/www.django-rest-framework.org\/\"  rel=\"noopener\">Django REST framework documentation<\/a><\/li>\n<\/ul>\n\n<p class=\"syndicated-attribution\"><figure class= \\\"wp-block-image alignnone \\\"><img src= \\\"http:\/\/itteacheritfreelance.hk\/test\/wordpress\/wp-content\/uploads\/2016\/05\/logo2-2.png\\\" alt=\\\"IT\u96fb\u8166\u88dc\u7fd2 java\u88dc\u7fd2 \u70ba\u5927\u5bb6\u914d\u5c0d\u96fb\u8166\u88dc\u7fd2,IT freelance, \u79c1\u4eba\u8001\u5e2b, PHP\u88dc\u7fd2,CSS\u88dc\u7fd2,XML,Java\u88dc\u7fd2,MySQL\u88dc\u7fd2,graphic design\u88dc\u7fd2,\u4e2d\u5c0f\u5b78ICT\u88dc\u7fd2,\u4e00\u5c0d\u4e00\u79c1\u4eba\u88dc\u7fd2\u548cFreelance\u81ea\u7531\u5de5\u4f5c\u914d\u5c0d\u3002\\\"\/><figcaption>\u7acb\u523b\u8a3b\u518a\u53ca\u5831\u540d\u96fb\u8166\u88dc\u7fd2\u8ab2\u7a0b\u5427!<\/figcaption><\/figure>\r\n<\/br>Find A Teacher Form:\r\n<\/br>https:\/\/docs.google.com\/forms\/d\/1vREBnX5n262umf4wU5U2pyTwvk9O-JrAgblA-wH9GFQ\/viewform?edit_requested=true#responses\r\n<\/br><\/br>Email:\r\n<\/br>public1989two@gmail.com<br><br><br><br><br><br><br>\r\n<a href=www.itsec.hk style=color:#FFFFFF;>www.itsec.hk<\/a><br>\r\n<a href=\\\"www.itsec.vip\\\" style=color:#FFFFFF;>www.itsec.vip<\/a><br>\r\n<a href=\\\"www.itseceu.uk\\\" style=color:#FFFFFF;>www.itseceu.uk<\/a><br><\/p>","protected":false},"excerpt":{"rendered":"<div class=\"mh-excerpt\"><p>In this Django REST framework tutorial, you will create a rental platform API. The tutorial demonstrates how to use Python and Django REST framework in PyCharm to develop APIs. By the time you complete the tutorial, you will be able to answer the following questions: Prerequisites To successfully complete the Django REST framework tutorial, you\u2019ll [\u2026]<\/p>\n<\/div>","protected":false},"author":2036,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"slim_seo":{"title":"Building APIs With Django REST Framework - ITTeacherITFreelance.hk","description":"In this Django REST framework tutorial, you will create a rental platform API. The tutorial demonstrates how to use Python and Django REST framework in PyCharm"},"footnotes":""},"categories":[10700],"tags":[10776],"_links":{"self":[{"href":"https:\/\/itteacheritfreelance.hk\/wordpress\/index.php\/wp-json\/wp\/v2\/posts\/329336"}],"collection":[{"href":"https:\/\/itteacheritfreelance.hk\/wordpress\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/itteacheritfreelance.hk\/wordpress\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/itteacheritfreelance.hk\/wordpress\/index.php\/wp-json\/wp\/v2\/users\/2036"}],"replies":[{"embeddable":true,"href":"https:\/\/itteacheritfreelance.hk\/wordpress\/index.php\/wp-json\/wp\/v2\/comments?post=329336"}],"version-history":[{"count":1,"href":"https:\/\/itteacheritfreelance.hk\/wordpress\/index.php\/wp-json\/wp\/v2\/posts\/329336\/revisions"}],"predecessor-version":[{"id":329337,"href":"https:\/\/itteacheritfreelance.hk\/wordpress\/index.php\/wp-json\/wp\/v2\/posts\/329336\/revisions\/329337"}],"wp:attachment":[{"href":"https:\/\/itteacheritfreelance.hk\/wordpress\/index.php\/wp-json\/wp\/v2\/media?parent=329336"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/itteacheritfreelance.hk\/wordpress\/index.php\/wp-json\/wp\/v2\/categories?post=329336"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/itteacheritfreelance.hk\/wordpress\/index.php\/wp-json\/wp\/v2\/tags?post=329336"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}