될때까지

((WnB)) 10일차 : 호스트 집 등록 API, S3, transaction 본문

프로젝트/wecode2차 : WnB

((WnB)) 10일차 : 호스트 집 등록 API, S3, transaction

랖니 2022. 8. 10. 15:26
728x90

S3 계정 생성 방법 및 IAM

 Rom 테이블

Image 테이블

 

 

import boto3
import uuid

from django.views   import View
from django.db      import IntegrityError
from django.http    import JsonResponse

from core.utils     import signin_decorator  
from hosts.models   import Host
from rooms.models   import Category, Room, Facility, RoomFacility, RoomType, Image

from my_settings    import AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, IMAGE_URL, AWS_BUCKET_NAME

class HostView(View):
    
    # s3_client = boto3.client(
    #     's3',
    #     aws_access_key_id     = AWS_ACCESS_KEY_ID,
    #     aws_secret_access_key = AWS_SECRET_ACCESS_KEY
    # )
    
    @signin_decorator
    def post(self, request):
        """
        호스트가 집을 등록하는 API
        
        url : post http://127.0.0.1:8000/hosts/homes
        
        * 호스트인가?
            - 검증할 방법
                - 토큰을 만들 때 user.id를 payload에 넣어서 만들었음
                - 로그인 데코레이터에서 토큰 디코딩하여 담긴 유저 정보를 확인 후 request.user에 담아두었음
                    payload      = jwt.decode(token, settings.SECRET_KEY, settings.ALGORITHM)
                    request.user = User.objects.get(id = payload['id'])
                
                - 해당 user.id가 host 테이블에 있는 id인가 확인하기
                    if request.user.id__in = Hosts.objects.all()

                        - 네 호스트에요
                            - Homes 객체 생성
                            
                        - 아니요 호스트 아니에요
                            - 403 Forbidden
                
                - 중복된 이름의 숙소가 있는가 확잉ㄴ하기
                    - 네 중복입니다
                        - 400
                    - 아니요 새로운 이름입니다
                        - 201

        """

        ##### 왜그럴까???? 알아볼 것 : 여러개의 값 받기 테스트 
        ##케이스 1번.
        # data        = request.POST     
        # test        = data['test'].split(',')[:-1]
        # print('data', data)   # 포스트맨에서 raw로 테스트하면 안나와!! 에러발생 django.utils.datastructures.MultiValueDictKeyError: 'test'
        # print('test',test)    # 근데 포스트맨에서 form-Data로 테스트하면 나와!!
        
        ## 케이스 2번.
        # data = json.loads(request.body)     
        # test = data['test'].split(',')
        # print('test', test)     # 얘는 포스트맨에서 raw로 테스트하면 나와!! 

        # return JsonResponse({'message':'test'})
        # data = json.loads(request.body)  
          
        data = request.POST 

        # file = request.FILES['filename']
        
        # self.s3_client.upload_fileobj{
        #     file,
        #     "s3-test-"
        # }
        
        try:
            host = Host.objects.get(user=request.user)   
            
            # 사용자 정보 검증
            name              = data['name']
            address           = data['address']
            detail_address    = data['detail_address']
            price             = data['price']
            description       = data['description']
            latitude          = data['latitude']
            longitude         = data['longitude']
            maximum_occupancy = data['maximum_occupancy']
            bedroom           = data['bedroom']
            bathroom          = data['bathroom']
            bed               = data['bed']
            host              = data['host_id']    # 아래에서 except로 처리했음
            category          = data['category_id']
            room_type         = data['room_type_id']
            facilities        = [int(x) for x in data['facility_id'].split(',')]
            # print(facilities)   여러개의 facilites가 리스트로 담긴다!
            
            # 8/10 해야할 일 => 이미지 S3로 업로드 해결
            files = request.FILES.getlist('files')

            # 카테고리 ID 없는 경우 => 404
            if not Category.objects.filter(id=category).exists():
                return JsonResponse({'message':'CATEGORY_DOES_NOT_EXIST'}, status=404)
                
            # 룸타입 ID 없는 경우 => 404
            if not RoomType.objects.filter(id=room_type).exists():
                return JsonResponse({'message':'ROOM_TYPE_DOES_NOT_EXIST'}, status=404)
                
            # 편의시설 ID 없는 경우 => 404
            for facility in facilities:
                if not Facility.objects.filter(id=facility).exists():
                    return JsonResponse({'message':'FACILITY_DOES_NOT_EXIST'}, status=404)
           
            # 룸 생성
            room, created = Room.objects.get_or_create(
                name = name,
                defaults = {
                    "address"           : address,
                    "detail_address"    : detail_address,
                    "price"             : price,
                    "description"       : description,
                    "latitude"          : latitude,
                    "longitude"         : longitude,
                    "maximum_occupancy" : maximum_occupancy,
                    "bedroom"           : bedroom,
                    "bathroom"          : bathroom,
                    "bed"               : bed,
                    "host"              : Host.objects.get(id=host),
                    "category"          : Category.objects.get(id=category),
                    "room_type"         : RoomType.objects.get(id=room_type)
                }
            )
            
            # 생성되지 않았다 => 똑같은 이름을 가진 객체가 있다 => 중복된 이름의 숙소가 있다 404
            if not created:
                return JsonResponse({'message':'ROOM_NAME_ALREADY_EXIST'}, status=400)
                  
            # 룸과 facilities 중간 테이블 생성
            created_room_id = Room.objects.latest('id').id    
            
            # facilities에는 str형의 리스트들이 여러개가 담겨있음. 
            # [1, 2, 3, 4, 5]
            # 이걸 int형으로 바꿔서 하나씩 RoomFacility 테이블에 추가어떻게 할래 => 반복문 사용
            for facility_id in facilities:
                RoomFacility.objects.create(
                    room_id = created_room_id,
                    room_facility_id = facility_id
                )  

            # 이미지 생성
            for file in files:
                file._set_name(str(uuid.uuid4()))
                s3r = boto3.resource('s3', aws_access_key_id = AWS_ACCESS_KEY_ID, aws_secret_access_key = AWS_SECRET_ACCESS_KEY)
                s3r.Bucket(AWS_BUCKET_NAME).put_object( Key = host + '/%s'%(file), Body=file, ContentType='jpg')
                Image.objects.create(
                    url = IMAGE_URL + f'{host}{file}',
                    room_id = created_room_id
                )
                
            images = Image.objects.filter(room_id = created_room_id).all()

            data = {
                "id"               : room.id,
                "address"          : room.address,
                "detail_address"   : room.detail_address,
                "price"            : room.price,
                "description"      : room.description,
                "latitude"         : room.latitude,
                "longitude"        : room.longitude,
                "maximum_occupancy": room.maximum_occupancy,
                "bedroom"          : room.bedroom,
                "bathroom"         : room.bathroom,
                "bed"              : room.bed,
                "host_name"        : room.host.user.first_name,
                "category_name"    : room.category.name,
                "room_type_name"   : room.room_type.name,
                "room_images"      : [image.url for image in images]
            }
            
            # 룸 생성
            return JsonResponse({'message':'SUCCESS', 'room':data}, status=201)

        except Host.DoesNotExist:
            return JsonResponse({'message':'HOST_DOES_NOT_EXIST'}, status=404)
        
        except KeyError:
            return JsonResponse({'message':'KEY_ERROR'}, status=400)
        
        except IntegrityError:
            return JsonResponse({'message':'UNKNOWN_DATA'}, status=400)
728x90