Generic views are another way of writing class-based views to write a fully functional CRUD API.
There are several generic views that offer a particular functionality, like displaying resources or creating a new resource and so on. All you must do is extend these generic views to make the API endpoints work.
from rest_framework import generics
Generic View Class | Supported Methods | Purpose |
---|---|---|
CreateAPIView | POST |
Create a new resource. |
ListAPIView | GET |
Display a collection of resources. |
RetrieveAPIView | GET |
Display a single resource. |
DestroyAPIView | DELETE |
Delete a single resource. |
UpdateAPIView | PUT , PATCH |
Replace or partially update a single resource. |
ListCreateAPIView | GET , POST |
Display a collection of resources and create a new resource. |
RetrieveUpdateAPIView | GET , PUT , PATCH |
Display a single resource and replace or partially update it. |
RetrieveDestroyAPIView | GET , DELETE |
Display a single resource and delete it. |
RetrieveUpdateDestroyAPIView | GET , PUT , PATCH , DELETE |
Display, replace or update, and delete a single resource. |
For instance, we want our API end point to be capable of both displaying and posting a resource, what class to be used.
Use CreateAPIView
for resource creation and ListAPIView
for getting the resource.
from rest_framework import generics
class CoursesView(generics.CreateAPIView, generics.ListAPIView):
Use ListCreateAPIView
to do the both
from rest_framework import generics
class CoursesView(generics.ListCreateAPIView):
theses generics classes needs two things:
queryset
: to retrieve all the recordsserializer_class
: to display and save the records.
that's all, pass theses two to the class and everything is managed by the generics.
# views.py
from rest_framework import generics
from .models import Course
from .serializers import CourseSerializer
class CoursesView(generics.ListCreateAPIView):
queryset = Course.objects.all()
serializer_class = CourseSerializer
# serializers.py
from rest_framework import serializersc
from .models import Course
class CourseSerializer(serializers.ModelSerializer):
class Meta:
model = Course
fields = ["id","course_name","slug"]
To limit the accessibility of the resource, we need to use permission classes on what and who can and to do so, we have two options:
- apply the permission classes on all methods like
GET, POST, PUT, DELETE
- apply the permission to certain kind of methods, for instance allowing only
GET
method. to go with this option, we need to override the get_permission method.
def get_permissions(self):
permission_classes = []
if self.request.method != 'GET':
permission_classes = [IsAuthenticated]
return [permission() for permission in permission_classes]
We can override the automatic behavior of default methods.
class CourseView(generics.ListCreateAPIView):
queryset = Course.objects.all()
serializer_class = CourseSerializer
def get(self, request, *args, **kwargs):
return Response(‘new response’)
The RetrieveAPIView is designed to retrieve a single object based on the pk (or other lookup field) provided in the request. The framework automatically filters the queryset based on the primary key or the lookup field provided in the URL.
class SingleCourse(generics.RetrieveAPIView):
queryset = Course.objects.all()
serializer_class = CourseSerializer
Define a url pattern
from django.urls import path
from .views import SingleCourse
urlpatterns = [
path("courses/<int:pk>",SingleCourse.as_view(), name="single_course"),
]
When posting data, generally there are two scenarios.
- straight forward, no relationship and all the fields match with what is expected
- when we have foreign relationships and we want to handel them explicitly, to do this, we need to override the default create method in
serializers.py
from rest_framework import serializers
from .models import Course, CourseCategory
class CategorySerializer(serializers.ModelSerializer):
class Meta:
model = CourseCategory
fields=["id","category_name"]
class CourseSerializer(serializers.ModelSerializer):
category_id = serializers.PrimaryKeyRelatedField(queryset = CourseCategory.objects.all(), write_only=True)
category = CategorySerializer(source="category_id", read_only=True)
class Meta:
model = Course
fields = ["id","course_name","slug","category_id","category"]
def create(self, validated_data):
category_id = validated_data.pop("category_id")
course = Course.objects.create(category_id=category_id, **validated_data)
return course
To do the extra work and send a custom message after successful creation, override the create method in views.py
.