Декабрь 2016

Этот курс закончился

Cписок курсов

Домашнее задание. Интернет-витрина

8 января 2017

Попробуем за 5 часов разработать настоящую интернет-витрину.

Постановка задачи

Сделаем интернет-витрину. Интернет-витрина — это почти как интернет-магазин, только попроще. У нас не будет рекомендованных товаров, систем оплаты, скидок, акций и прочего. Пусть наша витрина умеет следующее:

  1. Показывает товары, разбитые по категориям.
  2. Позволяет просматривать страницы товаров с более подробным описанием.
  3. Позволяет добавлять товары в корзину покупателя.
  4. Позволяет содержимое корзины оформить как заказ.
  5. При оформлении заказа посылает письмо оператору магазина.
  6. Хранит информацию о заказах.
  7. Позволяет оператору через панель администрирования менять состояния заказов.

Регистрации делать не будем — содержимое корзины будем хранить в сессии. Там же можно хранить данные пользователя, если он однажды уже делал заказ.

В качестве панели администрирования используем родную панель Django.

Структуры данных

В магазине находятся товары. Каждый товар относится к какой-то категории. Некоторые товары помечены как «особые» и выводятся на главной странице магазина.

Пользователь может выбрать один или несколько товаров в корзину. Когда в корзине есть хотя бы один товар, можно офромить заказ. При оформлении заказа содержимое корзины сохраняется в модели заказанный товар, и вместе с указанными покупателем данными о нём формирует непосредственно заказ.

У заказа есть понятние состояния (status). Состояние может быть одним из:

  • Принят, пока не обработан (New) — заказ совсем новый, оператор его ещё не видел
  • В обработке (In process) — оператор увидел заказ и начал что-то с ним делать
  • Готов к отправке (Ready to deliver) — заказ собран, ждёт курьера
  • Передан курьеру (Delivering) — оператор отдал заказ курьеру
  • Доставлен (Delivered) — курьер сообщил, что доставил заказ
  • Приостановлен (Suspended) — оператор приостановил работу над заказом (например, товар кончился)
  • Отменён (Cancelled) — оператор по каким-то причинам отменил заказа (напрмер, по просьбе покупателя)

Общая структура данных выглядит примерно вот так.

Схема данных для магазина

Часть информации хранится в моделях, как обычно. Однако корзина покупателя (то есть список выбранных для заказа товаров) хранится в сессии пользователя.

Структура сайта

Сайт состоит из следующих страниц.

Главная страница

Содержит список категорий товаров, а так же список товаров, помеченных как особые. Товары в списке представлены своим названием, маленькой картинкой, ценой и кратким описанием. Картинка и название — это ссылки, ведущие на страницу соответствующего товара.

Кроме того, в шаблоне предусмотрено так называемое «слайд-шоу», или «карусель» для «супер-особых товаров».

Просмотр категории

Почти то же, что на главной странице, но вместо особых товаров выводятся товары из указанной категории, а вместо слайд-шоу в начале страницы выводится название и описание категории.

Страница товара

На странице товара выводится большое изображение товара, название, цена, полное описание и кнопка «Добавить в корзину». Так же выводится список категорий товаров (категория, к которой относится текущий товар, подсвечивается).

При нажатии на кнопку «Добавить в корзину» происходит, во-первых, добавление товара в корзину, во-вторых, переход на страницу корзины.

Корзина

На этой странице выводится список находящихся в корзине товаров. Список выводится в виде таблицы. В кажой строке таблицы есть поле «Количество», которое позволяет покупателю указать, сколько единиц этого товара он хочет заказать. Соответственно, вся таблица — это форма. Подробнее см. ниже.

Под таблицей две кнопки: «Вернуться к покупкам» (ведёт на главную страницу) и «Оформить заказ» (ведёт на страницу оформления заказа). Кнопка «Оформить заказ» не появляется (или отключена), если корзина пуста.

Оформление заказа

Эта страница доступна только если корзина не пустая.

На ней находится форма с данными покупателя, которую покупатель должен запомнить. Все поля, кроме поля «Сообщение для оператора» (в модели заказа это поле notes), обязательные. Необходимо проконтролировать правильность заполнения формы.

Под формой показана (для контроля) сумма заказа, а так же две кнопки: «Назад к корзине» — ведёт на страницу корзины, и «Оформить заказ» — это кнопка-submit формы. Если в форме нет ошибок, пользователю выводится страница завершения оформления.

Завершение оформления

На этой странице пользователю выводится ссылка на страницу отслеживания вновь созданного заказа и его номер, а так же сообщение о том, что ему на e-mail отправлено письмо. В низу страницы есть кнопка перехода на главную страницу сайта.

Отслеживание заказа

Поскольку регистрации покупателя у нас не предусмотрено, надо как-то позволить покупателю видеть, что с его заказом. Для этого у каждого заказа есть уникальный код — набор случайных символов. По этому коду формируется ссылка на страницу отслеживания (например, http://my-shop.com/order/awrgfq34q4gqgr34/, здесь awrgfq34q4gqgr34 — и есть уникальный код заказа). На этой странице выводится номер заказа (он тоже уникальный, но состоит только из цифр, этот номер для общения с оператором, скажем, по телефону). Кроме того, выводится статус заказа (см. выше), все данные получателя, указанные при оформлении заказа, а так же таблица со списком товаров, входящих в заказ.

Простые информационные страницы

Кроме указанных выше динамических страниц сайт нашего магазина должен содержать и просто информационные страницы: О магазине, Доставка, Контакты и так далее. Эти страницы заполняются однократно и редко меняются. Их можно реализовать самостоятельно, либо воспользоваться готовым приложением Django Flatpages, которое поставляется в комплекте с Django.

Оформление сайта

Поскольку на вёрстку HTML у нас нет времени, воспользуемся готовым шаблоном. Скачайте этот файл и распакуйте его куда-нибудь:

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

Из этих отдельных HTML-страниц нужно сделать шаблоны. Причём желательно вынести общую часть в базовый шаблон, как мы обычно делали. Внимательно изучите вёрстку, найдите те места, в которые понадобится вставить Django-теги.

Находящиеся в архиве шаблоны сделаны на основе этого и этого бесплатных шаблонов с сайта Start Bootstrap. Шаблоны используют CSS-фрэймворк Bootstrap и JavaScript-библиотеку jQuery, а так же шрифты с сервиса Google Fonts.

Автор этих шаблонов — Дэвид Миллер, основатель Blackrock Digital. Они опубликованы под свободной лицензией MIT. Это значит, что необходимо упомянуть имя автора шаблона на вашем сайте.

Структура URL

Итак, нам понадобится обработать следующие адреса:

  • Главная страница
  • category/XX/ — просмотр товаров в категории с id = XX
  • item/XX/ — страница товара с id = XX
  • item/XX/buy/ — обработка добавления товара с id = XX в корзину. Перенаправляет на адрес cart/
  • cart/ — страница корзины (она же обрабатывает форму редактирования корзины)
  • cart/checkout/ — форма оформления заказа. Оформляет заказ. Если всё хорошо, перенаправляет на cart/checkout/done/
  • cart/checkout/done/ — страница с сообщением о завершении оформления заказа
  • order/XXXXXXXX/ — просмотр состояния заказа с кодом XXXXXXXX
  • about/ — информация о магазине
  • delivery/ — информация о доставке
  • contacts/ — контактные данные магазина

Технические моменты

Страница корзины

Как выше уже было упомянуто, страница корзины не так уж проста. На ней выводится таблица, содержащая названия товаров, их стоимость и их количество, причём количество можно редактировать.

Для редактирования в каждой строке таблица в стоблце «Количество» находится поле ввода (<input type="number">). То есть таблица является формой, по сути. Кроме того, для удобства покупателя, около каждой строки есть кнопка «Сохранить», которая является кнопкой отправки формы (<input type="submit">). Тот факт, что в одной форме множество кнопок «Submit», не должен вас смущать — этих кнопок в форме может быть сколько угодно, и все они выполняют одно действие — отправляют форму на обработку.

Сложность в другом: как назвать текстовые поля с количеством?

Например, можно воспользоваться следующим приёмом: будем при генерации таблицы в шаблоне давать этим полям имена вида qty_XXXXXX, здесь qty — сокращение от quantity, а вместо XXXXXX будем подставлять id соответствующего товара.

Кнопка корзины на каждой странице

Понятное дело, что сама кнопка вместе с верхней навигационной панелью останется в базовом шаблоне. Однако около кнопки неплохо бы писать, скажем, сколько товаров в корзине, или на какую сумму уже набрали. Неужели в любом представлении (view) придётся считать корзину и совать её в контекст шаблона? Неудобно же.

Да, неудобно. Поэтому тут мы воспользуемся тем, что у Django есть так назывемые Context Processor'ы (процессоры контекста). Это такие функции, которые применяюся к контексту шаблона и могут в него что-нибудь добавлять или менять. Именно один такой процессор добавляет нам в контекст переменную {{user}}, содержащую текущего пользователя.

Процессор контекста django.template.context_processors.request добавляет в котекст переменную {{request}}, содержащую HTTP-запрос со всем, что в нём есть, в том числе и с сессией: {{request.session}}. Например, если мы будем при любом изменении корзины считать сумму покупки и сохранять её в сессию как отдельную переменную:

total = 0.0
for item in self.items:
    # Код очень приблизительный
    total += item.price * item.quantity 
request.session["cart_total"] = total

то в шаблоне мы можем вывести сумму так:

{% load humanize %}
...
<a href="/cart/">
    <span class="glyphicon glyphicon-shopping-cart" aria-hidden="true"></span>
    Корзина (на {{request.session.cart_total|intcomma}} &#8381;)
</a>

Тут использован специальный фильтр intcomma из пакета django.contrib.humanize. Он приводит данное число к более удобочитаемому виду, добавляя разделители тысяч. Инструкции по включению этого фильтра смотрите здесь.

Символы &#8381; соответствуют знаку российского рубля (который ₽). Раз уж он есть, почему бы им не пользоваться.

Тег <span class="glyphicon glyphicon-shopping-cart" aria-hidden="true"></span> — это символ корзинки. См. документацию к Bootstrap за подробностями.

Где взять фото для товаров

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

  1. Маленькая фотография товара — это картинка размером 320×150 пикселей.
  2. Большая фотография товара — это картинка 800×300 пикселей.

И никак иначе (в противном случае, вёрстка поплывёт). Так что для каждого товара придётся подготовить по две фотографии. Где же их взять для проверки работы сайта?

В интернете много бесплатных фото. Есть даже сайты-генераторы, которые могут выдать вам случайное фото заданного размера и тематики. Например:

В будущем, конечно, стоит встроить этот функционал прямо в сервер.