Django/DRF

DRF Image DB 저장, 스웨거 적용

Jong_seoung 2023. 10. 10. 23:50
반응형

 

Django에서 user와 profile_image가 1대 1 관계일 때 이미지를 경로에 저장하는 방법이다. - 이후 DB에 저장하려면 프론트로 보낸 URL을 DB에 저장하면 된다.

 

UpdateAPIView를 상속 받아서 사용하였고 UpdateAPIView에는 PUT과 PATCH가 있는데 나는 PUT 만 사용할 예정이었기 때문에 allowed_methodes를 추가하여 주었다.

 

DRF에서는 파일 찾기로 파일을 보내는게 정상적으로 잘 되었는데 스웨거에서는 자꾸 파일을 FILE 이라는 JSON형식으로 받아서 많은 시간을 소비하였는데 APIView를 UpdateAPIView로 변경하니깐 바로 정상적으로 작동되었다.

아마 APIView에서 파라미터로 원하는 값이 JSON형식이여서 스웨거에서 자동으로 그렇게된 것 같다.

 

 

전체 코드

import uuid
from django.conf import settings
from django.core.files.storage import FileSystemStorage
from rest_framework import serializers
from rest_framework.generics import UpdateAPIView
from rest_framework.parsers import MultiPartParser
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework_simplejwt.authentication import JWTAuthentication


class ProfileImageSerializer(serializers.Serializer):
    profile_image = serializers.ImageField()


class ProfileImageAPI(UpdateAPIView):
    serializer_class = ProfileImageSerializer
    authentication_classes = [JWTAuthentication]
    permission_classes = [IsAuthenticated]
    parser_classes = (MultiPartParser,)
    allowed_methods = ["PUT"]

    def put(self, request, *args, **kwargs):
        image_file = request.FILES.get("profile_image")

        if not image_file:
            return Response({"error": "No image Files"}, status=400)

        fs = FileSystemStorage(location=settings.MEDIA_ROOT)
        random_filename = f"profile_images/user/{uuid.uuid4()}.webp"

        filename = fs.save(random_filename, image_file)

        file_url = fs.url(filename)

        return Response({"file_url": file_url}, status=200)

 

코드 설명

class ProfileImageSerializer(serializers.Serializer):
    profile_image = serializers.ImageField()


class ProfileImageAPI(UpdateAPIView):
    serializer_class = ProfileImageSerializer
    authentication_classes = [JWTAuthentication]
    permission_classes = [IsAuthenticated]
    parser_classes = (MultiPartParser,)
    allowed_methods = ["PUT"]

ProfileImageSerializer 클래스는 Django의 serializers.Serializer를 상속받아 데이터 타입을 변환해 주었다.

 

ProfileImageAPI 클래스

  • serializer_class - 이 뷰에서 사용할 시리얼 라이저 클래스를 지정한다.
  • authentication_class - API 엔드포인트에 대한 사용자 인증 방법을 지정한다. 위에서는 JSON Web Token을 사용하였다.
  • parser_class - 클라이언트가 요청을 보낼 때 사용할 파서 클래스를 지정한다. 위에서는 이미지를 받기 위해서 멀티 파서를 사용했다. 이 부분이 스웨거에서 이미지를 파일 찾기로 받기 위해서 중요한 부분이다. 실제로 많이 헤맨부분이다.
  • allowed_methodes - 위에서 설명했듯 엔드포인트에 허용되는 HTTP 메서드이다. PUT 만 사용할 것이기 때문에 PUT 만 넣어주었다.
    def put(self, request, *args, **kwargs):
        image_file = request.FILES.get("profile_image")

        if not image_file:
            return Response({"error": "No image Files"}, status=400)

        fs = FileSystemStorage(location=settings.MEDIA_ROOT)
        random_filename = f"profile_images/user/{uuid.uuid4()}.webp"

        filename = fs.save(random_filename, image_file)

        file_url = fs.url(filename)

        return Response({"file_url": file_url}, status=200)

클라이언트가 전송한 파일을 서버에 저장하고 저장된 URL을 리턴해주는 구문이다.

  • image_file = request.FILES.get("profile_image"): 클라이언트로부터 전송된 파일을 얻는다.
  • if not image_file : 전송된 파일이 없으면 에러를 리턴한다. (상태코드 400)
  • fs = FileSystemStorage(location=settings.MEDIA_ROOT) : 파일 저장을 위한 파일 시스템 스토리지 객체를 생성한다.
  • filename = fs.save(random_filename, image_file) : image_file을 random_filename으로 저장한다.
  • return Resopnse({"file_url": file_url}, status=200) : file_url을 리턴한다. (상태코드 200)
반응형