Section 1. 상품 상세 보기
1. Class-based View 생성
- DetialView 상속 (from django.views.generic import DetailView)
- queryset 에서 URL 을 통해 들어온 pk 값을 갖는 행을 출력함
2. URL 파싱
- path('product/<int:pk>/', ProductDetail.as_view()) 추가
- 상품의 pk 값을 URL 로 보내면 view 에서 해당 pk 값을 갖는 상품만을 출력 (django 자동)
3. Template 생성
{ product.description|safe}} # safe : html 태그 및 base 64 이미지 파일 변환
4. 상품 상세 보기 화면
Section 2. 상품 주문
1. 상품 주문 원리
- 상품 상세 보기에서 수량을 지정하고 주문하기 버튼을 누르는 방식
- 상품 상세 보기에서 주문하는 user / product / quantity 값이 form을 통해 POST 요청
- 상품을 보는 user 와 해당 상품 product 의 값이 자동으로 POST 요청
- 상품 상세 보기 GET 방식과 상품 주문 POST 방식을 나누어서 처리
2. form 생성
- 상품 주문 시에는 수량만 지정하고 user 와 product의 정보는 자동으로 보내지기 때문에 product 의 form 요소를 HiddenInput 형식으로 지정하고 id 값이기 때문에 IntegerField 지정
- user 의 session 값을 얻기 위해서 __init__ 생성자를 통해 form 이 생성될 때 request 를 전달 받음
- 트랜잭션을 통해서 order 를 생성하고 주문된 수량만큼 해당 product 의 재고에서 차감
- 수량을 지정하지 않거나 로그인 상태가 아니라면 상세보기를 다시 출력하도록 product 값 저장 해 놓음
def __init__(self,request, *args, **kwargs): # form이 생성될 때 request 값 또한 입력으로 받음
super().__init__(*args,**kwargs) # 원래의 __init__ 수행하고
self.request = request # 입력으로 받은 request를 form의 변수로 저장
user = self.request.session.get('user') # form의 변수로 request를 저장했으니 self로 접근 (from django.db import transaction)
with transaction.atomic(): # 해당 indent 부분 트랜잭션 처리
3. Class-based View 생성
- form_invalid() - form 에 대한 유효성 검사가 실패할 때 수행되는 함수(form 에 error 존재)
- 수량을 지정하지 않거나 로그인 상태가 아니라면 해당 상품 상세보기를 다시 출력
- get_form_kwargs() - POST 형식일 때 입력된 form 의 값들을 전달하는 함수
- 자동으로 입력된 product 의 정보와 사용자가 직접 지정한 수량에 request 값을 추가함
def form_invalid(self, form): # 원래의 invalide 기능은 template_name 에 지정된 template 에 error 정보 렌더링
form.data.get('product') # form.product 로도 접근 가능
get_form_kwargs(self, **kwargs): # kwargs 매개변수 생략 가능 (부모의 함수에도 존재 X)
4. 상품 상세 보기 Template 수정
- form 요소 출력
- product 는 HiddenInput 이므로 label 을 표시하지않고 사용자가 값을 지정할 수 없기 때문에 자동으로 해당 product 의 정보가 넘어가도록 value 속성에 {{product.id}} 지정
- 주문하기 버튼을 누르면 해당 form 값들을 가지고 /order/create/ 로 요청
5. 상품 상세보기 View 수정
- 상품 상세보기 View 는 DetailView 이므로 화면에 form 또한 출력하기 위해서 Template 으로 보내지는 data 에 form 을 추가해서 보내야 함
- get_context_data() - template 에 data 를 보내는 함수
- 상품 주문에서 form 이 생성될 때 __init__() 에서 request 를 입력 받았으므로 에러 방지를 위해서 똑같이 request 를 넘겨줌
from order.forms import RegisterForm as OrderForm # Product 의 RegisterForm 과의 구별을 위해
context['form'] = OrderForm(self.request) # OrderForm 으로 앨리어싱
6. URL 파싱
- path('order/create/', OrderCreate.as_view()) 추가
7. 수정된 상품 상세 보기 화면
Section 3. 상품 주문 처리 로직
1. 상품 상세 보기 화면
- 개발자 도구로 확인하면 자동으로 product form 요소 value 값에 product 값 지정됨
- 수량 10개 지정 후 주문하기 버튼 누르기
2. GET vs POST 방식
- 둘 의 차이점을 확인하기 위해 form 이 생성될 때 값을 확인하도록 print 로 각각 출력
- GET 방식 (상세보기 화면 요청)
- request 값 존재
- args, kwargs 값 존재 X
- POST 방식 (주문하기 요청)
- request 값 존재
- args, kwargs 값 존재
3. get_form_kwargs
- POST 방식일 때 __init__ 으로 보내지는 값들 확인을 위해 print
- 결과
- 'data' : <QueryDict\:product,quqntity> form 에 입력된 값들
- 'request':<WSGIRequest> 추가한 request 값
- 따라서 kw로 request 를 보냈다고 해서 form 에서 cleaned.data.get() 으로 접근 불가능
4. 주문 결과
- 자동으로 재고가 90개로 변경됨