Django Rest Framework
Django REST framework (DRF) is a powerful and flexible toolkit for building Web APIs. It is a third-party package for Django, the popular Python web framework. DRF makes it easy to build, test, and debug RESTful APIs written using the Django framework.
DRF provides a simple way to create RESTful APIs for your Django applications. It has a lot of built-in functionality that makes it easy to get started with building APIs.
Once you have DRF installed and added to your INSTALLED_APPS
, you can start using it in your Django views.
Understanding Requests and Responses
Django Rest Framework (DRF) allows you to interact with the API by sending HTTP requests and receiving HTTP responses. Understanding requests and responses is an important concept for building efficient and effective APIs using DRF.
Here is a beginner-friendly introduction for understanding requests and responses in DRF:
Requests
In DRF, a request is an HTTP message that is sent to the server by a client. It contains information such as the HTTP method (e.g. GET
, POST
, PUT
, PATCH
, DELETE
), the URL of the resource to be accessed, and any data or parameters that need to be passed to the server.
HTTP Methods
DRF supports four main HTTP methods, each of which is used for different purposes:
GET
: retrieves information from the serverPOST
: creates a new resource on the serverPUT
: updates an existing resource on the serverPATCH
: updates an existing resource field on the serverDELETE
: deletes a resource from the server
URL Patterns
In DRF, each resource is identified by a unique URL. URL patterns are used to match the URLs of incoming requests with the appropriate views or view functions that should handle them.
Responses
A response is the data that the server sends back to the client in response to a request. Responses in DRF are typically in the form of JSON or XML data, although other formats such as HTML or plain text can be used as well.
Status Codes
Responses in DRF include a status code that indicates the outcome of the request. Some common status codes include:
200 OK
: The request was successful and the data was returned201 Created
: A new resource was created as a result of the request204 No Content
: The request was successful but no data was returned400 Bad Request
: The request was invalid or incomplete401 Unauthorized
: The client was not authorized to make the request404 Not Found
: The requested resource was not found on the server500 Internal Server Error
: An error occurred on the server
Understanding these basic concepts is crucial for working with DRF and building efficient and effective APIs.
Serializers and Deserializers
Serializers and Deserializers are the core components in Django REST framework (DRF) that allow you to convert complex data types such as Django models into Python data types that can be easily rendered into JSON, XML or other content types.
Serializers
Serializers are used to convert Django models into Python data types that can be easily serialized into JSON or other content types. In DRF, serializers are used to define the structure of the output data by defining the fields that should be included in the output.
To use serializers in DRF, you first need to create a class that inherits from the serializers.Serializer
class. You then need to specify the fields that you want to include in the output by adding class level variables.
For example, consider a model called Manager
that has fields for name
, country
and no_of_titles
:
from rest_framework import serializers
class ManagerSerializer(serializers.Serializer):
name = serializers.CharField(max_length=100)
country = serializers.CharField(max_length=100)
no_of_titles = serializers.IntegerField()
class Meta:
model = Manager
fields = "__all__"
In this example, the ManagerSerializer class is defined to include three fields, name
, country
and no_of_titles
, each of which is specified as a CharField
or IntegerField
.
Deserializers
Deserializers are used to convert incoming data into Django models or Python objects. In DRF, deserializers are used to validate and parse the incoming data, and to create or update instances of Django models based on the input data.
To use deserializers in DRF, you need to create a class that inherits from the serializers.Deserializer
class. You then need to specify the fields that should be included in the input data, and the types of each of these fields, by adding class level variables.
For example, consider the same Manager
model as in the previous example:
from rest_framework import serializers
class ManagerDeserializer(serializers.Deserializer):
name = serializers.CharField(max_length=100)
country = serializers.CharField(max_length=100)
no_of_titles = serializers.IntegerField()
In this example, the ManagerDeserializer
class is defined to include the same three fields as in the ManagerSerializer
class, name
, country
and no_of_titles
.
To use the deserializer, you can pass the incoming data to its .save()
method, which will validate and parse the data, and return an instance of the Django model.
manager_data = {'name': 'Jurgen Klopp', 'country': 'Germany', 'no_of_titles': 5}
manager = ManagerDeserializer(data=manager_data).save()
In this example, the manager_data
dictionary is passed to the ManagerDeserializer
, which validates and parses the data and returns an instance of the Manager
model.
Viewsets and Routers
Django REST framework (DRF) provides a powerful and flexible framework for building APIs. It includes features such as authentication, serialization, query parameters, pagination, and more. One of the key features of DRF is Viewsets and Routers, which allow you to quickly build RESTful APIs with minimal code.
In DRF, a ViewSet
is a class-based view that provides a set of methods to handle incoming HTTP requests. The ViewSet
class should inherit from a base ViewSet
class provided by DRF, such as viewsets.ModelViewSet
, viewsets.ReadOnlyModelViewSet
, or viewsets.GenericViewSet
. The base ViewSet
class defines the basic methods for handling HTTP requests, such as list()
, create()
, retrieve()
, update()
, and destroy()
.
To use a ViewSet
, you will typically also need to define a serializer class to control how your models are represented in the API. A serializer class defines the fields to be included in the API, how to validate incoming data, and how to deserialize incoming data into model instances.
DRF also provides a Router class that makes it easy to map ViewSets
to URL patterns. A Router can be created using the DefaultRouter
or SimpleRouter
class, and it automatically generates the URL patterns for your ViewSets
based on their methods. You can then include the URL patterns in your Django URL configuration, and your ViewSets
will be ready to handle incoming requests.
Here is a simple example of how you might use a ViewSet
and Router
in DRF:
from rest_framework import viewsets
from rest_framework.routers import DefaultRouter
from .models import Manager
from .serializers import ManagerSerializer
class ManagerViewSet(viewsets.ModelViewSet):
queryset = Manager.objects.all()
serializer_class = ManagerSerializer
router = DefaultRouter()
router.register(r'managers', ManagerViewSet)
In this example, we create a ViewSet
class called ManagerViewSet
, which inherits from viewsets.ModelViewSet
. We also define a queryset
and serializer_class
property, which will be used by DRF to fetch the data and serialize the data for our API.
Next, we create a DefaultRouter
instance and register our ViewSet
with it. The register()
method maps the ViewSet
to a URL pattern and adds it to the router's URL patterns. In this case, the URL pattern will be /api/managers/
.
Finally, you would need to include the URL patterns in your Django URL configuration:
from django.urls import path, include
urlpatterns = [
path('api/', include(router.urls)),
]
With this setup, DRF will automatically generate the appropriate views and URL patterns for our Manager
model, and we can start using the API to fetch, create, update, and delete Manager
instances.
This is just a high-level overview of how ViewSets
and Routers
work in DRF, but you can learn more about these features in the DRF documentation.
Customizing responses using views and viewsets
Django Rest Framework (DRF) provides a lot of built-in features to customize the response of the API endpoints. One way to customize the responses is by using views and viewsets.
A view in DRF is a simple Python function that takes in a web request and returns a web response. A viewset, on the other hand, is a class that defines the behavior of a set of views.
Let's create a simple view to customize the response of an API endpoint.
from rest_framework import views
from rest_framework.response import Response
class CustomResponseView(views.APIView):
def get(self, request):
data = {
'message': 'Hello, World!'
}
return Response(data)
In the above code, we created a custom view CustomResponseView
that extends APIView
. This view has a simple get
method that takes in the request and returns a custom response in the form of a Response
object.
Similarly, we can also customize the response of an API endpoint using a viewset
.
from rest_framework import viewsets
from rest_framework.response import Response
class CustomResponseViewSet(viewsets.ViewSet):
def list(self, request):
data = {
'message': 'Hello, World!'
}
return Response(data)
In the above code, we created a custom viewset CustomResponseViewSet
that extends ViewSet
. This viewset
has a simple list
method that takes in the request and returns a custom response in the form of a Response object.
The list method corresponds to the GET
request of an API endpoint. Similarly, you can define other methods like create, retrieve, update, and destroy for other HTTP methods like POST
, GET
, PUT
, PATCH
, and DELETE
respectively.
With these simple examples, you can start customizing the response of your API endpoints using views and viewsets in DRF.
Working with relationships and nested serializers
Django Rest Framework (DRF) supports working with relationships and nested serializers. A relationship can be defined as one-to-many, many-to-one or many-to-many. Nested serializers allow to represent a model using other models as fields.
Create your Django models
class Club(models.Model):
name = models.CharField(max_length=100)
nick_name = models.CharField(max_length=100)
division = models.CharField(max_length=100)
country = models.CharField(max_length=100)
class Coach(models.Model):
name = models.CharField(max_length=100)
no_of_titles = models.IntegerField(default=0)
club = models.ForeignKey(Club, on_delete=models.SET_NULL)
In the above example, the Club
model has a one-to-many relationship with the Coach
model.
Create serializers for your models
class ClubSerializer(serializers.ModelSerializer):
class Meta:
model = Club
fields = '__all__'
class CoachSerializer(serializers.ModelSerializer):
club = ClubSerializer(many=False, read_only=True)
class Meta:
model = Coach
fields = '__all__'
Create views for your models
class ClubList(generics.ListCreateAPIView):
queryset = Club.objects.all()
serializer_class = ClubSerializer
class ClubDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = Club.objects.all()
serializer_class = ClubSerializer
class CoachList(generics.ListCreateAPIView):
queryset = Coach.objects.all()
serializer_class = CoachSerializer
class CoachDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = Coach.objects.all()
serializer_class = CoachSerializer
Add URLs for your views
from django.urls import path
urlpatterns = [
path('clubs/', ClubList.as_view(), name='club-list'),
path('clubs/<int:pk>/', ClubDetail.as_view(), name='club-detail'),
path('coaches/', CoachList.as_view(), name='coach-list'),
path('coaches/<int:pk>/', CoachDetail.as_view(), name='coach-detail'),
]
With the above setup, you will be able to retrieve a list of coaches and their respective clubs, as well as update, delete and create coaches and clubs.
Here is an example response to /coaches/
endpoint:
[
{
"id": 1,
"name": "Jurgen Klopp",
"no_of_titles": 5,
"club": {
"id": 1,
"name": "Liverpool",
"nick_name": "The Reds",
"division": "Premier League",
"country": "England"
},
},
{
"id": 2,
"name": "Frank Lampard",
"no_of_titles": 0,
"club": null,
}
]
In the serializers, many=False
means that the relationship is one-to-one, and read_only=True
means that the related field can only be retrieved, but not updated or created.
I hope this tutorial helps you get started with working with relationships and nested serializers in DRF!