Oldingi loyihalarimda frontendchilar bilan muayyan response formatiga kelishib olib ishlardik. Ya’ni har bir response quyidagicha bo‘lishi kerak edi:
{
"message": "All good",
"status_code": 200,
"data": [{...}]
}
Buning uchun men common
app ichiga utils.py
faylida quyidagicha yozib qo‘ygan edim:
SUCCESS_BODY = dict(
message="Login successfully",
status_code=status.HTTP_200_OK,
)
FAILURE_BODY = dict(
message="Login failed",
status_code=status.HTTP_400_BAD_REQUEST,
)
Va View
larda shu obyektlardan foydalanganman:
SUCCESS_BODY["message"] = "Login successful"
SUCCESS_BODY["data"] = user_serializer.data
except Exception as e:
FAILURE_BODY["message"] = str(e)
return Response(FAILURE_BODY, status=status.HTTP_400_BAD_REQUEST)
Bir qarashda hammasi yaxshi, lekin muammo bor. Chunki dict
obyektlari globalda saqlanganligi sababli ularda conflict bo‘lishi mumkin.
Misol uchun:
-
Login View (data mavjud)
SUCCESS_BODY["message"] = "Login successful" SUCCESS_BODY["data"] = user_serializer.data return Response(SUCCESS_BODY, status=200)
-
Update View
SUCCESS_BODY["message"] = "Updated successfully" return Response(SUCCESS_BODY, status=200)
Agar bu view’lar ketma-ket chaqirilsa, update
view’imizda login
view’dagi data
ham saqlanib qolib, response’da noto‘g‘ri natija qaytishi mumkin. Bu esa frontendchilarni chalg‘itadi.
from dataclasses import asdict, dataclass
from rest_framework import status
@dataclass
class ResponseBody:
message: str = "Success"
status_code: int = status.HTTP_200_OK
def to_dict(self, **extra_data):
data = asdict(self) # `dataclass` obyektini `dict`ga o‘girish
data.update(extra_data)
return data
# Global obyekt yaratish
# SUCCESS_BODY = ResponseBody(message="Success", status_code=200)
# FAILURE_BODY = ResponseBody(message="Failed", status_code=400)
# View'larda foydalanish
# response_data = SUCCESS_BODY.to_dict(id=123, message="Completed")
# return Response(response_data, status=200)
Agar ma’lumotni pagination shaklida berishni istasangiz, quyidagi yechimdan foydalanishingiz mumkin:
from rest_framework.pagination import PageNumberPagination
from rest_framework.response import Response
class CustomResponse:
@staticmethod
def _paginate_data(data, request, view, page_size: int = 10):
"""
Berilgan querysetni paginate qilish uchun yordamchi metod.
"""
paginator = PageNumberPagination()
paginator.page_size = page_size
paginated_data = paginator.paginate_queryset(data, request, view=view)
pagination_details = {
"count": paginator.page.paginator.count,
"next": paginator.get_next_link(),
"previous": paginator.get_previous_link(),
}
return paginated_data, pagination_details
@staticmethod
def success(
message: str,
data=None,
paginate: bool = False,
request=None,
view=None,
page_size: int = 10,
) -> Response:
"""
Muvaffaqiyatli response yaratadi, pagination qo‘llash mumkin.
Agar `paginate=True` bo‘lsa, `request` va `view` argumentlari kerak bo‘ladi.
"""
response = {
"status": "success",
"message": message,
}
# Pagination ishlatish
if paginate and data is not None:
if request is None or view is None:
raise ValueError("Pagination uchun `request` va `view` talab qilinadi.")
paginated_data, pagination_details = CustomResponse._paginate_data(
data, request, view, page_size
)
response["pagination"] = pagination_details
response["data"] = paginated_data
elif data is not None:
response["data"] = data
return Response(response, status=200)
@staticmethod
def error(message: str, status_code: int = 400) -> Response:
"""
Xatolik response yaratadi.
"""
response = {
"status": "error",
"message": message,
}
return Response(data=response, status=status_code)
# View'larda qo‘llash:
# return CustomResponse.success(
# message="Files retrieved successfully",
# data=serializer.data,
# paginate=True,
# request=request,
# view=self
# )
Bu yondashuv sizga har bir Response
uchun toza va izchil natijalar olishga yordam beradi. 🚀