Дикий Григорий

Full-stack веб-разработчик

Интернет-магазин на Django. Корзина пользователя. Часть 4

Доброго времени суток! Сегодня мы продолжим работу над нашей корзиной пользователя. По плану мы должны заняться отображением корзины, добавить возможность добавления и удаления товаров. Начнем с того, что создадим форму для того, чтобы пользователь выбирал количество товара. Для этого создадим в директории cart файл forms.py со следующим содержанием:

from django import forms
PRODUCT_QUANTITY_CHOICES = [(i, str(i)) for i in range(1, 21)]
class CartAddProductForm(forms.Form):
    quantity = forms.TypedChoiceField(choices=PRODUCT_QUANTITY_CHOICES, coerce=int)
    update = forms.BooleanField(required=False, initial=False, widget=forms.HiddenInput)

Мы создали форму в которой хранится два поля. Одно поле предназначено для выбора количества товара, а второе поле проверяет если товар ранее был добавлен в корзину.

Теперь когда мы создали форму мы можем заняться ее отображением, для этого давайте добавим в views.py следующее содержание:

from django.shortcuts import render, redirect, get_object_or_404
from django.views.decorators.http import require_POST
from shop.models import Product
from .cart import Cart
from .forms import CartAddProductForm
@require_POST
def CartAdd(request, product_id):
    cart = Cart(request)
    product = get_object_or_404(Product, id=product_id)
    form = CartAddProductForm(request.POST)
    if form.is_valid():
        cd = form.cleaned_data
        cart.add(product=product, quantity=cd['quantity'],
                                  update_quantity=cd['update'])
    return redirect('cart:CartDetail')

Эта вьюха добавляет товар в корзину. В качестве параметра она принимает запрос и идентификатор товара. Здесь мы используем декоратор require_POST для того, чтобы принимать только POST запросы. Нам также нужна возможность удалять товары, давайте добавим в views.py следующий код:

def CartRemove(request, product_id):
    cart = Cart(request)
    product = get_object_or_404(Product, id=product_id)
    cart.remove(product)
    return redirect('cart:CartDetail')

Теперь когда мы создали две функции для добавления и удаления товаров из корзины, настала пора создать вьюху для отображения корзины. Добавим в наш views.py код:

def CartDetail(request):
    cart = Cart(request)
    return render(request, 'cart/detail.html', {'cart': cart})

Эта функция получает экземпляр корзины пользователя и передает его в качестве параметра в шаблон. Теперь давайте создадим пути URL, для этого нужно создать и заполнить следующим urls.py:

from django.conf.urls import url
from . import views
urlpatterns = [
    url(r'^remove/(?P<product_id>\d+)/$', views.CartRemove, name='CartRemove'),
    url(r'^add/(?P<product_id>\d+)/$', views.CartAdd, name='CartAdd'),
    url(r'^$', views.CartDetail, name='CartDetail'),
]

И теперь когда мы прописали URL нашего приложения нужно включить этот файл в главный url в директории myshop:

urlpatterns = [
    ...
    url(r'^cart/', include('cart.urls', namespace='cart')),
    url(r'^', include('shop.urls', namespace='shop'))
]

Теперь когда все подготовлено для работы корзины пользователя, настала пора создать шаблоны для отображения корзины. Для этого давайте создадим следующую структуру файлов в директории cart:

templates/
    cart/
        detail.html

Заполним файл detail.html следующим текстом:

{% extends "shop/base.html" %}
{% block title %}
  Ваша корзина товаров
{% endblock %}
{% block content %}
  <h1>Ваша корзина товаров</h1>
  <table class="cart">
    <thead>
      <tr>
        <th>Изображение</th>
        <th>Продукт</th>
        <th>Количество</th>
        <th>Удалить</th>
        <th>Полная цена</th>
        <th>Цена</th>
      </tr>
    </thead>
    <tbody>
      {% for item in cart %}
        {% with product=item.product %}
          <tr>
            <td>
              <a href="{{ product.get_absolute_url }}">
                <img src="{{ product.image.url }}" alt="" />
              </a>
            </td>
            <td>{{ product.name }}</td>
            <td>{{ item.quantity }}</td>
            <td><a href="{% url "cart:CartRemove" product.id %}">Удалить</a></td>
            <td class="num">{{ item.price }} руб.</td>
            <td class="num">{{ item.total_price }} руб.</td>
          </tr>
        {% endwith %}
      {% endfor %}
        <tr class="total">
          <td>Total</td>
          <td colspan="4"></td>
          <td class="num">{{ cart.get_total_price }} руб.</td>
        </tr>
    </tbody>
  </table>
  <p class="text-right">
    <a href="{% url "shop:ProductList"%}" class="btn">Продолжить Шопинг</a>
    <a href="#">Оформить заказ</a>
  </p>
{% endblock %}

Теперь нам надо изменить сам шаблон вывода товара и добавить кнопку "Добавить в корзину", но для начала отредактируем views.py в папке shop:

from cart.forms import CartAddProductForm
...
# Страница товара
def ProductDetail(request, id, slug):
    product = get_object_or_404(Product, id=id, slug=slug, available=True)
    cart_product_form = CartAddProductForm()
    return render_to_response('shop/product/detail.html',
                             {'product': product,
                              'cart_product_form': cart_product_form})

И изменим вывод в файле shop/product/detail.html в папке шаблонов в директории shop:

....
<p class="price">{{ product.price }} руб.</p>
<form action="{% url "cart:CartAdd" product.id %}" method="post">
    {{ cart_product_form }}
    {% csrf_token %}
    <input type="submit" value="Добавить в корзину">
</form>

На сегодня все, в следующем уроке мы улучшим корзину пользователя. В итоге вы должны получить после добавления в корзину следующее:

И страница заказ товаров:


Репозиторий проекта: github