1. 혼자 만들어보는 Zara - 상품 수정

Kiyong Lee·2021년 12월 16일
0

개인프로젝트

목록 보기
9/9

혼자 만들어보는 Zara - 상품 수정


1. views.py

    @login_required
    def post(self, request, product_id) :
        try :
            
            user = request.user
            
            if user.role_id != RoleID.ADMIN.value :
                return JsonResponse({'message' : 'PERMISSION_DENIED'}, status=403)

            with transaction.atomic() :
                data = json.loads(request.body)
                
                thumbnail_url = data.get('thumbnail', None)
                name          = data.get('name')
                sales         = data.get('sales')
                product       = Product.objects.select_related('thumbnail').get(id=product_id)
                
                if thumbnail_url :
                    thumbnail = product.thumbnail_set.get()
                    thumbnail.url = thumbnail_url
                    thumbnail.updated_at = timezone.now()
                    thumbnail.save()
                    
                if sales :
                     product.price = F('price') * (100-int(sales)) / 100
                     product.save()
                    
                if name :
                    product.name = name
                    product.save()
                
                product.updated_at = timezone.now()
   
            return JsonResponse({'message' : 'SUCCESS'}, status=201)
            
        except Product.DoesNotExist :
            return JsonResponse({'message' : 'PRODUCT_DOES_NOT_EXIST'}, status=400)

2. 상세설명

우선, 상품수정은 일반유저가 할 수 없기 때문에 로그인 유저의 토큰을 통해 등급을 확인합니다.

일반 유저면 403 Forbidden 에러가 발생합니다.

수정의 경우, PATCHPUT이 있지만 POST를 많이 사용한다고 하여 POST를 선택했습니다.

ProductThumbnail의 경우, ProductThumbnail을 역참조하기 때문에
prefetch_related를 쓰려고 했으나, OneToOneField에서 역참조 관계는
select_related를 사용하기 때문에 select_related를 사용했습니다.

product_id를 통해 thumbnail에 접근할 때, 1대1 관계기 때문에 역참조관계에서
쿼리셋이 아닌 Thumbnail 객체를 가져와야 했고, 그래서 product.thumbnail_set.get()
사용했습니다.

수정날짜의 경우, auto_now=True를 설정하지 않아서 수정시간을 업데이트했습니다.
auto_now=True를 하면 데이터 생성할 때 updated_atcreated_at 날짜가 들어가기 때문입니다.

그리고 F객체를 써봤는데, 원래 가격이야 수정된 가격을 입력하면 되지만
F객체 사용을 위해 할인율을 입력하는거로 일부로 코드 작성했습니다.

일반 가격을 입력하면 product.price에 직접 입력하여 장고가 수행하는 과정이 하나 더 늘어나고,
F객체를 사용하면 DB의 값에서 작업을 수행하기 때문에 쿼리수를 줄일 수 있습니다.

예를 들어 쿼리를 가져오면 위에가 F객체, 아래가 일반 값 저장인데

product.price = product.price * (100-int(sales)) / 100

 "price" = (("products"."price" * 70) / 100) WHERE "products"."id" = 1; args=('2021-12-09 19:09:51.685829', 6, 'LIMITED EDITION 올 블랙 코트', 70, 100, 1)
 "price" = 82320                             WHERE "products"."id" = 1; args=('2021-12-09 19:09:51.685829', 6, 'LIMITED EDITION 올 블랙 코트', 82320, 1)

이렇게 DB에서 연산처리를 하게 되는 것입니다.

이걸 통해 경쟁조건(race condition)을 피할 수 있는데, 조회수를 예를 들면

  1. 현재 조회수(page.read_count = 1)
  2. A 스레드 조회(page.read_count = 1 + 1 )
  3. B 스레드 조회(page.read_count = 1 + 1 )

원래는 A, B에서 클릭했으니 3이 되어야 하는데 파이썬 기준으로 하다 보니
경쟁 조건이 발생합니다. 타이밍이나 순서에 따라 결과값에 영향을 주기 때문입니다.

하지만 F객체를 쓰게 된다면, A 스레드에서 DB 기준으로 +1 하므로 2가 되고
B 스레드에서 DB 기준으로 +1 하기 때문에 3이됩니다.


수정을 기준으로 기본적으로 구현할 사항들은 모두 종료되었습니다.

분명 모르는 부분이 아직 많기 때문에 리팩토링할 부분이 반드시 존재하고

꾸준한 공부를 통해 더 발전된 코드를 작성할 예정입니다.

profile
ISTJ인 K-개발자

0개의 댓글

관련 채용 정보