25
loading...
This website collects cookies to deliver better user experience
This article has some disadvantages and some conceptual errors that I could only notice after writing it. However, there are also beautiful advantages. I invite you to read the comments exchanged with @rouilj , and be free to participate in the discussion.
/users/{user_id}/
pointed to some view/controller (class method or function) that accepts PUT operation. Proceed with some verification to see what kind of changes are requested to do, and then you will execute the right task./users/{user_id}/change-email/
, /users/{user_id}/change-username/
, … and point each endpoint to respective function.That’s why I suggest you to use action query parameter.
# imports...
# -------------------------------------
UPDATE_ACTIONS = (
'change-email',
'change-username'
)
class UserDetailAPIView(APIView):
pass
UPDATE_ACTIONS
list is great because it’s can bring us the flexibility to disable (if necessary) an action just by comment the action line.class UserDetailAPIView(APIView):
def put(self, request, id):
# this will get the object and check related permissions between
# the authenticated account and the object
user = self.get_object(id)
# I defined my action query parameter name as 'action'
# but you can call something else
if (action := request.GET.get('action')) in UPDATE_ACTIONS:
# following python naming convention
action_method = action.replace('-', '_')
if hasattr(self, action_method)
return getattr(self, action_method)(user)
raise ValidationError(_('Update action temporarily unavailable'))
raise ValidationError(_('Unrecognized update action'))
UPDATE_ACTION
. I will show you in abstract way.class UserDetailAPIView(APIView):
def change_email(self, user):
## change email business logic
## run bg task
return Response(self.serializer_class(
user, context={'request': self.request}).data,
status=status.HTTP_202_ACCEPTED)
def change_username(self, user):
## change username business logic
## run bg task
return Response(self.serializer_class(
user, context={'request': self.request}).data,
status=status.HTTP_202_ACCEPTED)
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.exceptions import ValidationError
from rest_framework.permissions import IsAuthenticated
from rest_framework import status
from django.utils.translation import gettext_lazy as _
from user.serializers import UserDetail
from user.permissions import AuthenticatedUserIsOwner
# --------------------------------------------
UPDATE_ACTIONS = (
'change-email',
'change-username'
)
class UserDetailAPIView(APIView):
serializer_class = UserDetail
permission_classes = (
IsAuthenticated,
AuthenticatedUserIsOwner
)
# ---------------------------------------
# API Calls
def put(self, request, id):
# this will get the object and check related permissions between
# the authenticated account and the object
user = self.get_object(id)
# I defined my action query parameter name as 'action'
# but you can call something else
if (action := request.GET.get('action')) in UPDATE_ACTIONS:
# following python naming convention
action_method = action.replace('-', '_')
if hasattr(self, action_method)
return getattr(self, action_method)(user)
raise ValidationError(_('Update action temporarily unavailable'))
raise ValidationError(_('Unrecognized update action'))
# ---------------------------------------
# Update Actions
def change_email(self, user):
## change email business logic
## run bg task
return Response(self.serializer_class(
user, context={'request': self.request}).data,
status=status.HTTP_202_ACCEPTED)
# ---------------------------------------
def change_username(self, user):
## change username business logic
## run bg task
return Response(self.serializer_class(
user, context={'request': self.request}).data,
status=status.HTTP_202_ACCEPTED)