17. Django REST API#

  • A RESTful API is an architectural style for an application programming interface that uses HTTP requests to access and use data.

  • That data can be used to GET , PUT , POST and DELETE data types, which refers to reading, updating, creating and deleting operations related to resources.

  • Django Rest API Documentation

  • Video Tutorial

17.1. Basic Construction#

17.1.1. Setting Up Your Django REST Framework (DRF)#

  1. First, install Django REST Framework if you haven’t already:

    pip install djangorestframework
    
  2. Add rest_framework to your INSTALLED_APPS in django_project/settings.py:

    INSTALLED_APPS = [
        ...
        'rest_framework',
        ...
    ]
    

17.1.2. Serializers#

Serializers define how the model instances are converted to JSON.

  • Create a new file serializers.py in your app directory, in our case, under blog folder

    # blog/serializers.py
    
    from .models import Post,Comment
    from rest_framework import serializers
    
    class PostSerializer(serializers.ModelSerializer):
        class Meta:
            model = Post
            fields = ["id","title","author","content","date_posted"]
            
    class PostUpdateSerializer(serializers.ModelSerializer):
        class Meta:
            model = Post
            fields = ["id","title","author","content","date_posted"]
            read_only_fields  = ["id","author"]
            
            
    class CommentSerializer(serializers.ModelSerializer):
        class Meta:
            model = Comment
            fields = ["id","post","author","content","date_posted"]
            
    class CommentUpdateSerializer(serializers.ModelSerializer):
        class Meta:
            model = Comment
            fields = ["id","post","author","content","date_posted"]
            read_only_fields  = ["id","post","author"]
    

17.1.3. Create views for Post (Generic Views)#

  • Use Django REST Framework’s generic views for Post to handle common actions like create, retrieve, update, and delete.

  • queryset: This attribute defines the set of data that the view will operate on.

  • serializer_class: This attribute specifies the serializer class that will be used to convert the queryset into JSON format.

    # blog/views.py
    ...
    from rest_framework import generics
    from .models import Post
    from .serializers import PostSerializer

    ...
    class PostListCreateAPIView(generics.ListCreateAPIView):
        queryset = []
        serializer_class = PostSerializer
        
    class PostRetrieveDestroyAPIView(generics.RetrieveDestroyAPIView):
        queryset = Post.objects.all()
        lookup_field = 'pk'
        serializer_class = PostSerializer
        
    class PostUpdateAPIView(generics.UpdateAPIView):
        queryset = Post.objects.all()
        lookup_field = 'pk'
        serializer_class = PostUpdateSerializer

17.1.4. Views for Comment (Customized APIView)#

  • Add the following code to blog/views.py to handle Comment retrieval with APIView.

    class CommentAPIView(views.APIView):
        def get(self,request,format = None):
            content = request.query_params.get("content", "")
            date_posted = request.query_params.get("date_posted", "")
            date_posted_after = request.query_params.get("date_posted_after", "")
            date_posted_before = request.query_params.get("date_posted_before", "")
            
            comments = Comment.objects.all()
            
            if content:
                comments = comments.filter(content__icontains=content)
            
            if date_posted:
                comments = comments.filter(date_posted__date=date_posted)
            
            if date_posted_after:
                comments = comments.filter(date_posted__date__gt=date_posted_after)
            
            if date_posted_before:
                comments = comments.filter(date_posted__date__lt=date_posted_before)
                
            comments = comments.order_by('date_posted')[:5]
                
            serializer = CommentSerializer(comments,many = True)
            return response.Response(serializer.data,status=status.HTTP_200_OK)
            
    
        def post(self, request, format=None):
            serializer = CommentSerializer(data=request.data)
            if serializer.is_valid():
                serializer.save()
                return response.Response(serializer.data, status=status.HTTP_201_CREATED)
            return response.Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
    

17.1.5. URL Configuration#

  • Set up the URL Pattern

    urlpatterns = [
        ...
        path('api/post/create', PostListCreateAPIView.as_view(), name='api-post-create'),
        path('api/post/<int:pk>', PostRetrieveDestroyAPIView.as_view(), name='api-post-qd'),
        path('api/post/<int:pk>/update/', PostUpdateAPIView.as_view(), name='api-post-update'),
        path('api/comment/', CommentAPIView.as_view(), name='api-comment')
    ]
    
  • Test API functionality

    curl -X POST http://localhost:8000/api/post/create
    {"title":["This field is required."],"author":["This field is required."],"content":["This field is required."]}
    
    curl -X GET http://localhost:8000/api/post/1
    {"id":1,"title":"First Post","author":2,"content":"This is the content of the first post1","date_posted":"2024-07-01T13:40:17.920961Z"}
    
    curl -X GET http://localhost:8000/api/comment/?content=insights
    [{"id":13,"post":9,"author":3,"content":"Great insights, thank you!","date_posted":"2024-07-01T10:40:00Z"},{"id":36,"post":4,"author":3,"content":"Thanks for the insights!","date_posted":"2024-07-01T12:40:00Z"}]
    

17.2. Advanced Querying and Filtering#

  • For more advanced querying, such as searching with wildcards, consider using Django Filters or adding custom query parameters.

17.2.1. Setting Up Your Django REST Filter Framework#

  1. First, install the required Framework if you haven’t already:

    pip install django-filter
    
  2. Add django-filter to your INSTALLED_APPS in django_project/settings.py:

    INSTALLED_APPS = [
        ...
        'django-filter',
        ...
    ]
    

17.2.2. Set another Post List View for content query#

  • filter_backends: This attribute lists the filter backends that will be used to apply filtering, searching, and ordering to the queryset.

    • DjangoFilterBackend: Provides filtering based on specified fields. It is part of the django-filter package.

    • filters.SearchFilter: Allows searching across specified fields using a query parameter.

    • filters.OrderingFilter: Enables ordering of the results based on specified fields.

  • filterset_fields: This attribute defines the fields that can be used for filtering the queryset.

  • ordering_fields: This attribute defines the fields that can be used for ordering the results.

    class PostListAPIView(generics.ListAPIView):
        queryset = Post.objects.all()
        serializer_class = PostSerializer
        filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]
        filterset_fields = ['author']
        search_fields = ['title', 'content']
        ordering_fields = ['date_posted']
    

17.2.3. URL Configuration#

  • Set up the URL Pattern

    urlpatterns = [
        ...
        path('api/post/', PostListAPIView.as_view(), name='api-post-list'),
        ...
    ]
    
  • Test API functionality

    GET /api/post/?author=2&search=First&ordering=date_posted
    
    HTTP 200 OK
    Allow: GET, HEAD, OPTIONS
    Content-Type: application/json
    Vary: Accept
    
    [
        {
            "id": 1,
            "title": "First Post",
            "author": 2,
            "content": "This is the content of the first post1",
            "date_posted": "2024-07-01T13:40:17.920961Z"
        },
        {
            "id": 32,
            "title": "Getting Started with TensorFlow",
            "author": 2,
            "content": "TensorFlow is an open-source platform for machine learning. This tutorial shows you how to get started with TensorFlow and build your first model.",
            "date_posted": "2024-07-02T17:41:45.215499Z"
        }
    ]
    

17.3. Authentication and Permissions#

  • In this section, we will add authentication and permissions to secure your API.

  • Reading Material

17.3.1. Set the setting#

  • REST_FRAMEWORK: This is a dictionary where you configure global settings for Django REST Framework (DRF).

  • DEFAULT_AUTHENTICATION_CLASSES: This setting defines the default authentication classes that will be used to authenticate the users making requests to your API. It includes:

    • SessionAuthentication: Uses Django’s session framework for authentication. It is suitable for browser-based clients.

    • TokenAuthentication: Uses token-based authentication, where each request is authenticated using a token. This is more suitable for non-browser clients, such as mobile apps.

  • DEFAULT_PERMISSION_CLASSES: This setting defines the default permission classes that will be used to authorize the users making requests to your API.

    • IsAuthenticated: This permission class ensures that only authenticated users can access the API endpoints. If a user is not authenticated, they will receive a 401 Unauthorized response.

      # django_project/setting.py
      REST_FRAMEWORK = {
          'DEFAULT_AUTHENTICATION_CLASSES': [
              'rest_framework.authentication.SessionAuthentication',
              'rest_framework.authentication.TokenAuthentication',
          ],
          'DEFAULT_PERMISSION_CLASSES': [
              'rest_framework.permissions.IsAuthenticated',
          ],
      }