장고로 쇼핑몰 만들기 (주문)

팔리동·2021년 4월 15일
1

장고로 쇼핑몰 만들기(주문 part)

product-views.py

class ProductDetail(DetailView):
    template_name = 'product_detail.html'
    queryset = Product.objects.all()   # 모든 제품에서 하나씩 꺼내서 쓸 것이기에 queryset을 쓴다. 
    context_object_name = 'product'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)

        context['form'] = OrderForm(self.request)  # orderform에서 받은 값을 'form'으로 템플릿에 전달한다. 
        return context                             # view 함수이기 때문에 request가 있으니 폼을 생성할 때 request를 전달한다. 
  • 디테일 페이지에서 주문하기 버튼을 만들고 수량을 폼으로 받을 것이기 때문에 product-views에 작성한다.

  • get_context_data메소드는 OrderForm에서 받아온 값을 context['form']에 저장해서 템플릿에 보낸다.

  • self.request도 폼에 실어 보낸다.

주문하기 폼 생성

order-forms.py

class RegisterForm(forms.Form):
    def __init__(self, request, *args, **kwargs):
        super().__init__(*args, **kwargs)           # form에 request를 전달 받기 위해 만들었다. 
        self.request = request
        

    quantity = forms.IntegerField(
        error_messages={
            'required' : '수량을 입력해주세요.'
        }, label='수량'
    )
    product = forms.IntegerField(
        error_messages={
            'required' : '상품가격을 입력해주세요.'
        }, label='상품가격', widget=forms.HiddenInput # 화면에는 보이지 않는 인풋
    )
   

    def clean(self):
        cleaned_data = super().clean()
        quantity = cleaned_data.get('quantity')
        product = cleaned_data.get('product')
        fcuser = self.request.session.get('user')

        if quantity and product and fcuser:
            with transaction.atomic():
                prod = Product.objects.get(pk=product)
                order = Order(
                    quantity=quantity,
                    product=prod,               # 주문한 상품의 객체를 주문모델의 상품필드에 저장         
                    fcuser=Fcuser.objects.get(email=fcuser)
                )
                order.save()
                prod.stock -= quantity
                prod.save()

        else: 
            self.product = product
            self.add_error('quantity', '수량을 입력해주세요')
            self.add_error('product', '값을 입력해주세요.')
    
  • __init__메소드를 상속받아서 폼에 request를 전달받는다.

  • product필드에 widget=forms.HiddenInput은 인풋태그를 감춘다.

transaction

데이터베이스의 상태를 변화시키기 위한 작업의 단위를 의미한다. 트랜잭션은 간단히 말해서 작업의 완전성을 보장해주는 것이다. 트랜잭션의 작업 셋을 완벽하게 처리하지 못할 경우 다시 원상태로 복구해서 작업 셋의 일부만 적용되는 것을 막기 위한 기능이다.

templates

<form method="POST" action="/order/create/">
            {% csrf_token %} 
            {% for field in form %}
            <div class="form-group">
              {% ifnotequal field.name 'product' %}
              <label for="{{ field.id_for_label }}">{{field.label}}</label>
              {% endifnotequal %}
              <input
                type="{{ field.field.widget.input_type }}"
                class="form-control"
                id="{{ field.id_for_label}}"
                placeholder="{{ field.label }}"
                name="{{field.name}}"
                value="{% ifequal field.name 'product' %}{{product.id}}{% endifequal %}"
              />
            </div>
            {% if field.errors %}
            <span style="color: red">{{ field.errors }}</span>
            {% endif %} {% endfor %}
            <button type="submit" class="btn btn-primary">주문하기</button>
          </form>
        </li>
        <li class="list-group-item">가격: {{ product.price|intcomma }} 원</li>
  • 주목해서 봐야할 점
  • input태그의 value값에 prduct의 id값을 넣은 점(view함수에 전달된다.)
  • ifnotequal을 사용해서 필드네임이 'product'면 label을 표시 안했다.

view

class OrderCreate(FormView): 
    form_class = RegisterForm
    success_url = '/product/'

    def form_invalid(self, form):
        return redirect('/product/' + str(form.product))  # forms.py에서 self.product = product product는 html태그에서 value값이 id값이므로 숫자가 넘어간다.


    def get_form_kwargs(self, **kwargs):   # 폼을 생성할 떄 어떤 인자값을 전달해줄지 알려주는 함수 
        kw = super().get_form_kwargs(**kwargs)  
        kw.update({
            'request': self.request      # 기존에 생성된 인자값에 request를 추가해준다. 
        })
        return kw 
        
class OrderList(ListView):
    template_name = 'order.html' 
    context_object_name = 'order_list'

    def get_queryset(self, **kwargs):  # queryset을 오버라이딩해서 로그인한 사람의 정보만 표시하게 한다. 
        queryset = Order.objects.filter(fcuser__email=self.request.session.get('user'))
        return queryset

OrderCreate

  • return redirect('/product/' + str(form.product)) 입력값이 안채워지면 상품 상세페이지로 옮겨간다.

  • POST방식일 때(이전에 디테일페이지에 폼은 GET방식이다.)
    폼에서 보낼 때 request가 있는데 view에서 처리를 하는데 상속받은 FormView에 request가 없으므로 get_form_kwargs 메소드로 생성을 해준다.

OrderList

  • queryset을 사용해서 로그인한 사용자의 주문정보만 표시하게 한다.

templates(orderlist)

{% extends "base.html" %} 
{% load humanize %} 
{% block contents %}
<div class="row mt-5">
  <div class="col-12">
    <table class="table table-light">
      <thead class="thead-light">
        <tr>
          <th scope="col">#</th>
          <th scope="col">상품명</th>
          <th scope="col">수량</th>
          <th scope="col">주문날짜</th>
        </tr>
      </thead>
      <tbody class="text-dark">
        {% for order in order_list %}
        <tr>
          <th scope="row">{{ order.id }}</th>
          <th>{{ order.product }}</th>
          <th>{{ order.quantity|intcomma }} 개</th>
          <th>{{ order.register_date|date:'Y-m-d H:i' }}</th>
        </tr>
        {% endfor %}
      </tbody>
    </table>
  </div>
</div>
{% endblock %}
  • 기존 상품리스트 템플릿을 고쳐서 만들었다.
  • view에서 context_object_name을 order_list로 설정했기 때문에 for문을 저렇게 작성했다.
profile
배움의 기록

0개의 댓글