The GenericAPIView class is often used with Mixins, classes that provide further functionalities to our views, increasing their capabilities.
The Mixin Classes provide action methods such as .list() or .create() rather than defining the handler methods, such as .get() or .post() directly, as is usually done with the APIView class.
class EbookListCreateAPIView(mixins.ListModelMixin,
mixins.CreateModelMixin,
generics.GenericAPIView):
queryset = Ebook.objects.all()
serializer_class = EbookSerializer
# define handler methods
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
return self.create(request, *args, **kwargs)
The folllowing attributes control the basic view behavior.
queryset
: the queryset that should be used for returninb objects from this viewserializer_class
lookup_field
lookup_url_kwarg
pagination_class
filter_backends
: a list of filter backend classes that should be used for filtering the querysetEach one of the concrete view classes extends the GenericAPIView class and Mixins that offer the functionalities that the class is meant to provide.
RetrieveUpdateAPIView for example will extend the GenericAPIView class as well as RetrieveModelMixin and UpdateModelMixin.
Used for create-only endpoints.
Used for read-only endpoints to represent a collection of model instances.
Used for read-only endpoints to represent a single model instance.
Used for delete-only endpoints for a single model instance.
Used for update-only endpoints for a single model instance.
Used for read-write endpoints to represent a collection of model instances.
Used for read or update endpoints to represent a single model instance.
Used for read or delete endpoints to represent a single model instance.
Used for read-write-delete endpoints to represent a single model instance.
.save()
Sometimes you wnat your view code to inject additional data at the point of saving an instance. This additional data could be a foreign key object, current time, or anything else that is not part of the request data.
You can do so by including additional keyword arguments when calling .save()
.
serializer.save(owner=request.user)
serializer.save(author=author)
.save()
directlyIn some cases .create()
and .update()
methods may not be meaningful. This can be the case when sending a verification email to a user, instead of creating new instances.
By overriding .save()
directly, you can make the method more meaningful.
class ContactForm(serializers.Serializer):
email = serializers.EmailField()
message = serializers.CharField()
def save(self):
email = self.validated_data['email']
message = self.validated_data['message']
send_email(from=email, message=message)
Permission system can be managed globally in settings.py
, or locally (per view) in each view class.
Using built-in permissions,
class EbookListCreateAPIView(generics.ListCreateAPIView):
queryset = Ebook.objects.all()
serializer_class = EbookSerializer
permission_classes = [permissions.IsAuthenticatedOrReadOnly]
Or create a custom permission class for more precise access permissions,
// In permissions.py
class IsAdminUserOrReadOnly(permissions.IsAdminUser):
def has_permission(self, request, view):
// IsAdminUser's has_permission method
is_admin = super().has_permission(request, view)
return request.method in permissions.SAFE_METHODS or is_admin
// SAFE_METHODS = ('GET', 'HEAD', 'OPTIONS')
// In views.py
class EbookListCreateAPIView(generics.ListCreateAPIView):
queryset = Ebook.objects.all()
serializer_class = EbookSerializer
permission_classes = [IsAdminUserOrReadOnly]
class IsReviewAuthorOrReadOnly(permissions.BasePermission):
def has_object_permission(self, request, view, obj):
if request.method in permissions.SAFE_METHODS:
return True
return obj.review_author == request.user
The pagination style may be set globally, using the DEFAULT_PAGINATION_CLASS
and PAGE_SIZE
settings keys.
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',
'PAGE_SIZE': 100
}
Or, you can also set a pagination class for an individual view by using the pagination_class
attribute.
// In pagination.py
from rest_framework.pagination import PageNumberPagination
class SmallSetPagination(PageNumberPagination):
page_size = 3
If no ordering is provided, pagination may yield inconsistent results with an unordered object list. To prevent potential errors, provide ordering.
class EbookListCreateAPIView(generics.ListCreateAPIView):
queryset = Ebook.objects.all().order_by("-id")
serializer_class = EbookSerializer
permission_classes = [IsAdminUserOrReadOnly]
pagination_class = SmallSetPagination