[drf]airbnb api - 8 Create Room

Hyeseong·2021년 3월 24일
0
post-thumbnail

이전 작성하였던 APIView를 모두 지우고 근원적 로직에 대한 이해를 위해서 메뉴얼한 방식으로 회귀해보겠습니다.
즉, 노가다 코딩에 가까운 방식을 쓰겠다는 거쥬.

아! 참고해야 할 점은 자동으로 잡아줬던? 페이지네이션을 이제 일일히 작성해줘야된다는 말이에요.
왜냐구요? generic view를 사용해서 페이지네이션을 구현했기때문에 이제 제네릭뷰를 날려버릴 거기 때문이조.(제네릭뷰는 페이지의 정보를 갖고 있는거조.)

FBV

뷰를 새롭게 함수형으로 짜보겠습니다.
GET으로 분기할때 ReadRoomSerializer()클래스의 필수 인자 2개를 작성하고 마지작 도트 연산자로 data속성에 접근해주는 부분 유의해주세요.

또한 만약 포스트맨으로 {name:'hyeseong'}으로 JSON객체를 보내게 되면 POST로 분기문을 만나고 request.data로 콘솔에 찍어서 확인해 보게 되면{name:'hyeseong'}이라고 나오게 됩니다.

짧게 말하자면 @api_view()를 통해서 JSON객체가 -> python dictionary로 변형된 걸 확인 할 수 있어요.

한가지 더 확인해야 할 사항은 POST, PUT같이 데이터를 클라이언트로부터 받아와 디비에 저장해야하는 경우 if serializer.is_valid():와 같이 유효성 검사를 반드시 해줘야해요.

rooms/views.py

from rest_framework.generics import RetrieveAPIView
from rest_framework.decorators import api_view
from rest_framework.response import Response
from rest_framework import status
from .models import Room
from .serializers import ReadRoomSerializer, WriteRoomSerializer


@api_view(["GET", "POST"]) # 허용되는 HTTP METHOD 정의
def rooms_view(request):
    if request.method == "GET": # GET Method일 경우 분기
        rooms = Room.objects.all() # 쿼리셋을 받아 올게요.
        serializer = ReadRoomSerializer(rooms, many=True).data 
        return Response(serializer)
    elif request.method == "POST": # POST Method일 경우 분기
        serializer = WriteRoomSerializer(data=request.data)
        if serializer.is_valid():
            return Response(status=status.HTTP_200_OK)
        else:
            return Response(status=status.HTTP_400_BAD_REQUEST)


class SeeRoomView(RetrieveAPIView):

    queryset = Room.objects.all()
    serializer_class = ReadRoomSerializer

is_valid() 유효성 검사를 확인 하기 위해서 아래와 같이 포스트 요청을 보낼게요.

어쨋든 통상 이렇게 유효성 검사를 통과하면 200과 400 status code를 Response클래스에 담아 리턴해주면 되는게 큰 골자입니다.

rooms/serializers.py

기존 작성했던 RoomSerializer를 ReadRoomSerializer로 이름을 바꿀게요.

POST 요청을 작성해주기 위해서 WriteRoomSerializer를 만들게요.
models.py와 사실상 똑같다고 봐도 무방하네요.

ModelSerializer vs Serializer

지금 두개의 클래스가 있는데 상속받은 클래스의 차이로 엄청나게 코드수가 달라지는걸 확인 할 수 있어요.

from rest_framework import serializers
from users.serializers import UserSerializer
from .models import Room


class ReadRoomSerializer(serializers.ModelSerializer): # GET 요청시 처리할 시리얼라이저

    user = UserSerializer()

    class Meta:
        model = Room
        exclude = ("modified",)


class WriteRoomSerializer(serializers.Serializer): # POST요청시 처리할 시리얼라이저

    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)

rooms/urls.py

from django.urls import path
from . import views
app_name = "rooms"

urlpatterns = [
    path("", views.rooms_view),
    path("<int:pk>/", views.SeeRoomView.as_view()),
]

어느정도 FBV로 작성한 시리얼라이저와 뷰를 마무리를 지어 봐야 할 것 같네요.

시작하기 앞서 models.py파일안에서 Meta 클래스의 ordering 변수의 값을 내림차순으로 출력되도록 마이나스를 앞에 붙일게요.

rooms/models.py

    photo_number.short_description = "Photo Count"

    class Meta:
        ordering = ["pk"]
        ordering = ["-pk"]


class Photo(CoreModel):

Serializer method

기본적으로 create(), update(), save() 요 메서드를 Serializer클래스에서 사용하게 되는데요.

serializer.save(user=request.user) 메서드를 사용하면 기본적으로 create, update두가지를 구분해서 작동해주게되요.

  • 뭔가를 만들어준다면, Serializer클래스에서 정의한 create()메서드를 자!동!으로 호출하여 로직을 실행해주게되요.

  • 뭔가를 변경한다면 반대로 update() 메서드를 감지해서 자!동!으로 호출해서 로직을 실행하겠조?

결론, view로직에서 절대 create(), update()메서드를 호출하는 일은 없음! save()메서드를 사용함!

참고로, 시리얼라이저(인스턴스).data는 HTTP method body에 담아 보낸 값들을 말함니다.

rooms/views.py

...
...

@api_view(["GET", "POST"])
def rooms_view(request):
    if request.method == "GET":
        rooms = Room.objects.all()[:5] # 모든 객체를 보여주기에 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) # 여기서 받은 룸은 create 메소드에서 반환한 인스턴스를 말함
            room_serializer = ReadRoomSerializer(room).data # 알맹이에 해당함. HTTP 메서드에서 바디로 보낸 값들과 기타등등
            return Response(data=room_serializer, status=status.HTTP_200_OK)
        else:
            return Response(status=status.HTTP_400_BAD_REQUEST)
            
class SeeRoomView(RetrieveAPIView):
...
...

serializer.save(user=request.user) 의 키워드 파라미터는 WriteRoomSerializer클래스 안의 create(self, validated_data)메서드의 validated_data에 해당되요.

rooms/serializers.py

...
...

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)

어드민에서 관리자로 로그인을 하고 진행할게요.
어느정도 갈무리가 되었다면 아래와 같이 확인해 볼 수 있어요.

admin에서 확인해보조.

profile
어제보다 오늘 그리고 오늘 보다 내일...

0개의 댓글