Skip to content

Instantly share code, notes, and snippets.

@firdavsDev
Last active November 6, 2025 12:28
Show Gist options
  • Select an option

  • Save firdavsDev/46c3bb9b6829e988ecadede08ab3116b to your computer and use it in GitHub Desktop.

Select an option

Save firdavsDev/46c3bb9b6829e988ecadede08ab3116b to your computer and use it in GitHub Desktop.

Problem

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 Viewlarda 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.

Solution

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)

# Usage Example:
# class ExampleView(CustomResponseMixin, APIView):
#     def get(self, request):
#         data = MyModel.objects.all()
#         serializer = MyModelSerializer(data, many=True)
#         serializer.is_valid(raise_exception=True)
#         data = serializer.data
#         return self.success(
#             message="Files retrieved successfully",
#             data=data,
#             paginate=True,
#             request=request,
#             view=self
#         )

Bu yondashuv sizga har bir Response uchun toza va izchil natijalar olishga yordam beradi. 🚀

from rest_framework.pagination import PageNumberPagination
from rest_framework.response import Response
class CustomResponseMixin:
"""Custom response mixin.
Usage:
class MyAPIView(CustomResponseMixin, APIView):
- return self.success(message="Operation successful", data=serializer.data, status_code=200)
- return self.success(
message="Files retrieved successfully",
data=serializer.data,
paginate=True,
request=request,
view=self,
status_code=200
)
- return self.error(message="An error occurred", detail=str(e), status_code=400)
"""
@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,
status_code: int = 200,
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("Required `request` and `view`.")
paginated_data, pagination_details = CustomResponseMixin._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=status_code)
@staticmethod
def error(message: str, detail: str = None, status_code: int = 400) -> Response:
"""
Xatolik response yaratadi.
"""
response = {
"status": "error",
"message": message,
"detail": detail,
}
return Response(data=response, status=status_code)
# Usage Example:
# class ExampleView(CustomResponseMixin, APIView):
# def get(self, request):
# data = MyModel.objects.all()
# serializer = MyModelSerializer(data, many=True)
# serializer.is_valid(raise_exception=True)
# data = serializer.data
# return self.success(
# message="Files retrieved successfully",
# data=data,
# paginate=True,
# request=request,
# view=self
# )
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment