본문 바로가기

프로그래밍/Django개발(MAC OS)

Django Rest API 서버 만들기 요약 - Day 2

반응형

2022.05.08 - [프로그래밍/Django개발(MAC OS)] - Django Rest API 서버 만들기 요약 - Day 1

 

Django Rest API 서버 만들기 요약 - Day 1

Django를 활용하여 REST API 서버를 만드는 방법에 대해서 정리하기 위한 포스팅입니다. 개인적으로 사용하기 위한 것이라ㅠㅠ 정보 전달보다는 전체적으로 어떻게 학습 했는지를 봐주시면 좋을 것

kgu0724.tistory.com

 

어제에 이어서  Rest API 서버 만들기를 시작해보도록 하겠습니다.

@api_view(["GET", "POST"])
def rooms_view(request):
    if request.method == "GET":
        rooms = Room.objects.all()[:5]
        serializer = ReadRoomSerializer(rooms, many=True).data
        return Response(serializer)
    elif request.method == "POST":
        if not request.user.is_authenticated:
            return Response(status=status.HTTP_401_UNAUTHORIZED)
        serializer = WriteRoomSerializer(data=request.data)
        if serializer.is_valid():
            room = serializer.save(user=request.user)
            room_serializer = ReadRoomSerializer(room).data
            return Response(data=room_serializer, status=status.HTTP_200_OK)
        else:
            return Response(status=status.HTTP_400_BAD_REQUEST)

어제 api_view 데코레이터를 활용하여 FBV로 구성을 했다면, 이를 APIView를 활용하여 CBV로 한번 만들어 볼 것입니다. 
어떤 것이 좋을 지는 개인의 코딩 스타일에 따라 다를 것 같습니다.

 

  • CBV (APIView)만들기
from rest_framework.views import APIView


class RoomsView(APIView):

    def get(self, request):
        rooms = Room.objects.all()[:5]
        serializer = ReadRoomSerializer(rooms, many=True).data
        return Response(serializer)

    def post(self, request):
        if not request.user.is_authenticated:
            return Response(status=status.HTTP_401_UNAUTHORIZED)
        serializer = WriteRoomSerializer(data=request.data)
        if serializer.is_valid():
            room = serializer.save(user=request.user)
            room_serializer = ReadRoomSerializer(room).data
            return Response(data=room_serializer, status=status.HTTP_200_OK)
        else:
            return Response(status=status.HTTP_400_BAD_REQUEST)


class RoomView(APIView):
    def get(self, request, pk):
        try:
            room = Room.objects.get(pk=pk)
            serializer = ReadRoomSerializer(room).data
            return Response(serializer)
        except Room.DoesNotExist:
            return Response(status=status.HTTP_404_NOT_FOUND)

    def put(self, request):
        pass

    def delete(self, request):
        pass

 

그러나 여기서 RoomView에서 Put, Delete를 하기 위해서는 get에서 사용했던 것처럼 Room Object를 계속 불러와야 되는데, 이렇게 하지 않고 별도의 함수 get_room(self, pk)함수를 만들어 줍니다.

class RoomView(APIView):

    def get_room(self, pk):
        try:
            room = Room.objects.get(pk=pk)
            return room
        except Room.DoesNotExist:
            return None

    def get(self, request, pk):
        room = self.get_room(pk)
        if room is not None:
            serializer = ReadRoomSerializer(room).data
            return Response(serializer)

    def put(self, request, pk):
        room = self.get_room(pk)
        if room.user != request.user:
            return Response(status=status.HTTP_403_FORBIDDEN)
            if room is not None:
                serializer = WriteRoomSerializer(
                    room, data=request.data, partial=True)
                if serializer.is_valid():
                    serializer.save()
            else:
                return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
            return Response()
        else:
            return Response(status=status.HTTP_404_NOT_FOUND)


    def delete(self, request, pk):
        room = self.get_room(pk)
        if room is not None:
            if room.user != request.user:
                return Response(status=status.HTTP_403_FORBIDDEN)
            room.delete()
            return Response(status=status.HTTP_200_OK)
        else:
            return Response(status=status.HTTP_404_NOT_FOUND)

 

WriteSerializer에서 값을 validation 하기 위해서 validate 함수와 update함수를 오버라이딩해서 사용할 것입니다.

여기서 주의할 점은 validate 같은 경우에는 create와 update 둘 다 동시에 실행되기 때문에, update때에는 별도의 처리를 해주는 것이 좋습니다. 두개를 구별하는 방법은 update의 경우 instance를 반드시 보내야 하기 떄문에, instance의 유무를 통해서 validation을 분기해주시면 됩니다.

class WriteRoomSerializer(serializers.Serializer):

    name = serializers.CharField(max_length=140)
    address = serializers.CharField(max_length=140)
    price = serializers.IntegerField()
    beds = serializers.IntegerField(default=1)
    lat = serializers.DecimalField(max_digits=10, decimal_places=6)
    lng = serializers.DecimalField(max_digits=10, decimal_places=6)
    bedrooms = serializers.IntegerField(default=1)
    bathrooms = serializers.IntegerField(default=1)
    check_in = serializers.TimeField(default="00:00:00")
    check_out = serializers.TimeField(default="00:00:00")
    instant_book = serializers.BooleanField(default=False)

    def create(self, validated_data):
        return Room.objects.create(**validated_data)

    def validate(self, data):
        if not self.instance:
            check_in = data.get("check_in")
            check_out = data.get("check_out")
            if check_in == check_out:
                raise serializers.ValidationError(
                    "Not enough time between changes")
        else:
            return data

그럼 update validate를 해보도록 하겠습니다.

그전에 앞서 문제였던 부분은, validate 함수가 update할 때에는 작동을 하지 않는 다는 점이였는데, update 할때에도 검증을 하기 위해서는 조금의 변경이 필요합니다. instance가 있을때, 아닐때로 나눠주면 되겟죠? data.get함수는 python 문법인데, 값이 있으면 그 값을 리턴하는 거고, 없으면 뒤에 있는 인자를 사용하는 것입니다.

def validate(self, data):
        if self.instance:
            check_in = data.get("check_in", self.instance.check_in)
            check_out = data.get("check_out", self.instance.check_out)
        else:
            check_in = data.get("check_in")
            check_out = data.get("check_out")
        if check_in == check_out:
            raise serializers.ValidationError("Not enough time between changes")
        return data

 

그다음에 업데이트를 해보도록 하겠습니다.

수동으로 하는 방법이긴 하지만, instance를 각각 지정해주는 방식으로 update를 해주고 여기서 주의할 점은 반드시 instance를 그대로 리턴해줘야 된다는 것입니다.

#rooms/serializers.py

	def update(self, instance, validated_data):
        instance.name = validated_data.get("name", instance.name)
        instance.address = validated_data.get("address", instance.address)
        instance.price = validated_data.get("price", instance.price)
        instance.beds = validated_data.get("beds", instance.beds)
        instance.lat = validated_data.get("lat", instance.lat)
        instance.lng = validated_data.get("lng", instance.lng)
        instance.bedrooms = validated_data.get("bedrooms", instance.bedrooms)
        instance.bathrooms = validated_data.get("bathrooms", instance.bathrooms)
        instance.check_in = validated_data.get("check_in", instance.check_in)
        instance.check_out = validated_data.get("check_out", instance.check_out)
        instance.instant_book = validated_data.get(
            "instant_book", instance.instant_book
        )
        instance.save()
        return instance
#rooms/views.py

 def put(self, request, pk):
        room = self.get_room(pk)
        if room.user != request.user:
            return Response(status=status.HTTP_403_FORBIDDEN)
            if room is not None:
                serializer = WriteRoomSerializer(
                    room, data=request.data, partial=True)
                if serializer.is_valid():
                    room = serializer.save()
                    return Response(ReadRoomSerializer(room).data)
            else:
                return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
            return Response()
        else:
            return Response(status=status.HTTP_404_NOT_FOUND)

serializer.save()를 하면, 앞서 했던 update함수에서 instance를 받아와서 업데이트 된 값을 Response해주면 됩니다. 

#2.5까지 했습니다

 

 

반응형