Skip to content

Instantly share code, notes, and snippets.

@firdavsDev
Last active March 4, 2025 05:36
Show Gist options
  • Save firdavsDev/46c3bb9b6829e988ecadede08ab3116b to your computer and use it in GitHub Desktop.
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)

# 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. 🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment