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
andDELETE
data types, which refers to reading, updating, creating and deleting operations related to resources.
17.1. Basic Construction#
17.1.1. Setting Up Your Django REST Framework (DRF)#
First, install Django REST Framework if you haven’t already:
pip install djangorestframework
Add
rest_framework
to yourINSTALLED_APPS
indjango_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
forPost
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 thequeryset
intoJSON
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 withAPIView
.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#
First, install the required Framework if you haven’t already:
pip install django-filter
Add
django-filter
to yourINSTALLED_APPS
indjango_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 thequeryset
.DjangoFilterBackend
: Provides filtering based on specified fields. It is part of thedjango-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 thequeryset
.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.
17.3.1. Set the setting#
REST_FRAMEWORK
: This is a dictionary where you configure global settings forDjango 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', ], }