TIL 240501

hyeo71·2024년 5월 1일
0

2024 내배캠 AI 트랙

목록 보기
86/108

Pagination

데이터가 많아지면 한 페이지에서 모든 정보를 확인하기엔 불편함이 있기 때문에 원하는 갯수만큼 page를 나눠서 출력하도록 했다.

APIViewsettings.py에서 전역설정해도 적용이 안되기 때문에 직접 해야한다. 여러가지 pagination 방법 중 나는 PageNumberPagination을 사용할 것이다.

pagination 부분은 따로 파일을 만들어서 저장하여 Mixin해서 사용한다.

pagination.py


class PaginationHandlerMixin(object):
    @property
    def paginator(self):
        if not hasattr(self, '_paginator'):
            if self.pagination_class is None:
                self._paginator=None
            else:
                self._paginator=self.pagination_class()
        else:
            pass
        return self._paginator
    
    def paginate_queryset(self, queryset):
        if self.paginator is None:
            return None
        return self.paginator.paginate_queryset(queryset, self.request, view=self)
    
    def get_paginated_response(self, data):
        assert self.paginator is not None
        return self.paginator.get_paginated_response(data)

views.py


class ProductPagination(PageNumberPagination):
    page_size=5

class ProductsAPIView(APIView, PaginationHandlerMixin):
    permission_classes = [IsAuthenticatedOrReadOnly]
    pagination_class=ProductPagination

    def get(self, request):
        products = Product.objects.all()
        page=self.paginate_queryset(products)
        if page is not None:
            serializer=self.get_paginated_response(ProductSerializer(page, many=True).data)
        else:
            serializer = ProductSerializer(products, many=True)
        return Response(serializer.data)

Logout

로그아웃은 토큰을 blacklist를 하는 방법을 사용하여 Logout을 구현한다.

Reference logout 2의 블로그를 참고하여 simple_jwt을 사용하면 간단히 구현이 가능하다.

urls.py

from rest_framework_simplejwt.views import TokenBlacklistView

urlpatterns = [
  ...
  path('logout/', TokenBlacklistView.as_view(), name='token_blacklist'),
  ...
]

하지만 문제가 발생했다.

Method Not Allowed (POST): /accounts/login/

해당 오류의 원인을 찾아 구글링을 하던 중 Reference logout 3의 블로그를 찾았고 url이 원인인 것 같아 기존 api/accounts/logoutapi/accounts/auth/logout으로 변경하니 작동이 잘 되었다.

하지만 TokenBlackListView를 사용하니 결과 메세지가 비어서 출력되어 이를 출력하기 위해 Reference logout 2의 방식으로 변경하기로 했다.

views.py

class LogoutAPIView(APIView):
    permission_classes = [IsAuthenticated]

    def post(self, request):
        token = RefreshToken(request.data.get("refresh"))
        token.blacklist()
        return Response({"ok": "Bye!"}, status=status.HTTP_200_OK)

urls.py도 이에 맞게 변경

위와 같이 바꾸어 blacklist가 되면 해당 메세지가 출력되도록 구현하였다.


profile Custom Permission

회원 정보 수정을 위해 product에서 한 것처럼 Custom Permission을 만들어서 사용하려 하는데
permission이 제대로 동작하지 않았다. product와 무엇이 다른지 알기 위해 해당 코드의 변수를 출력해보기로 했다.

accounts/permissions.py

class IsOwnerOrReadOnly(permissions.BasePermission):
    def has_object_permission(self, request, view, obj):
        if request.method in permissions.SAFE_METHODS:
            return True
        print(type(obj.username), obj.username)
        print(type(obj), obj)
        print(type(request.user), request.user)
        print(obj.username == request.user)
        return obj.username == request.user


모두 값으로는 admin이 나오지만 기존의 obj.usernamerequest.user의 타입이 달라서 True를 반환하지 못했고 objrequest.user는 타입도 같지만 어째서인지 이도 False를 반환하였다.(objrequest.user는 왜 False....)

그래서 나는 반환되는 request.user를 string으로 바꾸는 방법으로 이를 해결하고 True를 반환하여 프로필 데이터를 수정하는 것을 구현했다.
return obj.username == request.user => return obj.username == str(request.user)


Reference

pagination
logout 1
logout 2
logout 3

0개의 댓글