6. Представления каталога
3 октября 2016 г. 15:47
Сейчас мы знаем как создавать модели продукта и знаем как администрировать их, давайте взглянем на то, как управлять ими в наших представлениях.
Во время редактирования CMS страницы, в которой используется плагин "Список продуктов" (products list view), откройте Расширенные настройки и выберите пункт "Список продуктов" (Products List) в поле "Приложение".
Затем выберите шаблон, в котором есть хотя бы один заполнитель. Щёлкните по кнопке "Смотреть на сайте" (View on site), чтобы изменить режим редактирования на сайте. Отыщите главный заполнитель и добавьте плагин Строка (Row) и Столбец (Column) из секции Bootstrap. В колонку добавьте дочерний плагин под названием Список продуктов (Catalog List Views) из раздела Интернет-магазин. А затем опубликуйте страницу. Пока ещё мы не увидим наши товары.
6.1. Добавление товаров в категорию
Откройте карточку товара в административной части сайта. Отыщите поле выбора многие-ко-многим под названием Cms Страницы (Cms pages) в разделе Категории (Categories). Выберите страницы, где каждыйы продукт будет показываться.
После перезагрузки списка товаров, присвоенные продукты будут показаны. Убедитесь, что они активны, иначе они не будут показываться.
Во вложенных категориях продукаты также будут видны и на родительских страницах.
6.1.1. Сериализаторы модели продукта
Мы уже научились написать классы и менеджеры для моделей, но что для чего тогда сериализаторы?
В djangoSHOP нет разницы будут ли представления рендерить информацию о продукте как HTML или JSON. Это даёт нам преимущество использовать бизнес-логику при рендеринге статичного HTML, одностраничного приложения, где используется AJAX для передачи запросов и ответов или нативное приложение интернет-магазина на мобильных устройствах. Это, кстати, является одним из самых больших преимуществ во время работы с RESTful API и благодаря djangorestframework нам даже не надо писать Django представления где-либо.
Например, попытайтесь открыть представление списка товаров или карточку товара любого из доступных товаров в интернет магазине. Затем в адресной строки браузера добавьте ?format=api or ?format=json к текущему URL. Тем самым срендерится информация о продукте, но без HTML.
REST API представление очень удобно при разработке. Если вы хотите скрыть это на вашей боевой системе, то в settingy.py удалите 'rest_framework.renderers.BrowsableAPIRenderer' из REST_FRAMEWORK['DEFAULT_RENDERER_CLASSES'].
В каталоге интернет-магазина нам нужна некоторая функциональность для рендера представления списка всех продуктов и нам нужно представление карточки товара для рендера каждого типа продукта. Фреймворк djangoSHOP поставляет два таких сериализатора
6.2. Сериализация для Представления списка продуктов (Products List View)
Для каждого продукта, которого мы хотим отобразить в списке продуктов, нам нужен сериализатор, который сконвертирует содержимое важных полей продукта. Обычно это id, имя и цена, ссылка на карточку товара, короткое описание и превью товара.
DjangoSHOP фреймворк не знает, какие эти поля должны быть сериализованы, поэтому требуется некоторая помощь программиста:
# myshop/product_serializers.py from shop.rest.serializers import ProductSummarySerializerBase from myshop.models.polymorphic.product import Product class ProductSummarySerializer(ProductSummarySerializerBase): class Meta: model = Product fields = ('id', 'product_name', 'product_url', 'product_type', 'product_model', 'price')
Все эти поля должны быть извлечены прямо из модели продукта за исключением превью товара. Это так, потому что мы ещё не знаем окончательное разрешение нашего изображения внутри HTML элемента, такого как <img src="..."> и мы конечно хотим изменить размер используя PIL/Pillow. Лёгкий способ решить эту проблему заключается в использовании SerializerMethodField. Просто расширьте класс выше:
class ProductSummarySerializer(ProductSummarySerializerBase): media = SerializerMethodField() def get_media(self, product): return self.render_html(product, 'media')
Как и следовало ожидать, render_html присваивает HTML-фрагмент в поле media в упорядоченное представление нашего продукта. Этот метод использует шаблон для визуализации HTML. Имя этого шаблона строится по следующим правилам:
- Отыскать папку, название которой указано в settings.SHOP_APP_LABEL в нижнем регистре. Если папка не найдена, то использовать папку, названную shop.
- Найти подпапку, названную products.
- Найти шаблон “label-product_type-postfix.html”. Эти три подполя различаются следуя правилу: * label: комопнент интернет-магазина, например, catalog, cart, order. * product_type: имя класса в нижнем регистре модели продукта, например, smartcard, smartphone или если нет такого шаблона, тогда только product. * postfix: Это произвольное имя передается с помощью функции рендера. Как и в приведенном выше примере, это строка media.
Замечание: это возможно покажется "не по стилю rest" для рендера HTML фрагментов через REST сериализатор и передачу его через JSON клиенту. Тем не менее, мы как-то должны изменить размер изображения, назначенные к нашему продукту согласно дизайну сайта. Самый простой способ - это использовать библиотеку easythumbnails и его templatetag {%thumbnail product.sample_image ... %} для создания миниатюры заданных размеров.
Шаблон для отображения media фрагмента кода может выглядеть следующим образом:
myshop/products/catalog-smartcard-media.html {% load i18n thumbnail djng_tags %} {% thumbnail product.sample_image 100x100 crop as thumb %} <img src="{{ thumb.url }}" width="{{ thumb.width }}" height="{{ thumb.height }}">
Шаблон представления списка продуктов может содержать следующий цикл по выводу продуктов:
{% for product in data.results %} <div class="shop-list-item"> <a href="{{ product.product_url }}"> <h4>{{ product.product_name }}</h4> {{ product.media }} <strong>{% trans "Price" %}: {{ product.price }}</strong> </a> </div> {% endfor %}
Тег {{ product.media }} вставляет HTML фрагмент, который подготовлен сериализатором, о котором говорилось выше. Сериализатор может добавть более чем один SerializerMethodField. Это может быть полезно, если представление список товаров будет рендерить различные типы продукта, используя различные шаблоннные фрагменты.
6.3. Сериализация для представления карточки товара (Product’s Detail View)
Сериализатор для представления карточки товара очень похож на сериализатор представления Списка товаров. В примере ниже мы наоборот хотим показать все поля, которые заданы в модели, за исключением некоторых полей. Показывать поля таким образом имеет смысл, так как мы хотим выстовить всевозможные детали.
from shop.rest.serializers import ProductDetailSerializerBase class ProductDetailSerializer(ProductDetailSerializerBase): class Meta: model = Product exclude = ('active',)
6.4. AddToCartSerializer
Вместо использования сериализатора карточки товара, бизнес логику для добавления продукта в корзину была перемещена в специальный сериализатор. Это сделано так, потому что djangoSHOP не может предполагать, что продукты будут добавлены в корзину только с карточки товара. Нам также нужен способ, чтобы добавить более чем один вариант продукта в корзину с каждой страницы карточки товара.
Для этих целей djangoSHOP содержит AddToCartSerializer. Он может быть переопределён для специальных требований продукта, но для стандартного приложения он просто должен работает из коробки.
Убедитесь, что контекст для рендера продукта содержит ключевую ссылку на объект продукта. ProductDetailSerializer делает это по умолчанию. Затем добавьте
{% include "shop/catalog/product-add2cart.html" %}
в подходящее место в шаблоне, которое рендерит представление карточки товара
Сейчас включённый add-to-cart шаблон содержит форму с несколькими входящими полями и несколькими директивами AngularJS, которые обмениваются данными с конечной точкой, подключенной к AddToCartSerializer. Он обновляет подытог всякий раз, когда клиент изменяет количество и отображает хорошее всплывающее окно, когда элемент добавляется в корзину. Конечно, этот шаблон может быть расширен с произвольным HTML.
Эти директивы Angular JS требуют некоторого JavaScript кода, который размещён в fileshop/js/catalog.js. Он ссылается автоматически с использованием выше описанного шаблона.
[1] Специально в b2b сайтов (бизнес-бизнес сайтов), это обычно делается в представлениях списка товаров.
6.4.1. Соединение сериализаторов с классами представления
Теперь, когда мы объявили сериализаторы для представлений списка товаров и карточки товара, нам нужно сделать последний шаг, который заключается в том, чтобы обеспечить доступ их через CMS страницы. Запомните, так как мы выбрали использовать CMS старницы как категории, мы вынуждены установить специальный djangoCMS apphook:
# myshop/cms_apps.py from cms.app_base import CMSApp from cms.apphook_pool import apphook_pool class ProductsListApp(CMSApp): name = _("Products List") urls = ['myshop.urls.products'] apphook_pool.register(ProductsListApp)
Этот apphook указывает на список URLs, которые содержаться в urlpattern:
# myshop/urls/products.py from django.conf.urls import url from rest_framework.settings import api_settings from shop.rest.filters import CMSPagesFilterBackend from shop.rest.serializers import AddToCartSerializer from shop.views.catalog import (CMSPageProductListView, ProductRetrieveView, AddToCartView) urlpatterns = [ url(r'^$', CMSPageProductListView.as_view( serializer_class=ProductSummarySerializer, )), url(r'^(?P<slug>[\w-]+)$', ProductRetrieveView.as_view( serializer_class=ProductDetailSerializer )), url(r'^(?P<slug>[\w-]+)/add-to-cart', AddToCartView.as_view()), ]</slug></slug>
Эти шаблоны URL соединяют сериализаторы продукта с представлениями каталога, чтобы назначить их конечную точку. Дополнительное примечание: Класс фильтра CMSPagesFilterBackend используется для ограничения продуктов для конкретных страниц CMS, следовательно, его можно рассматривать как распределитель продукта по категориям.
Представляю вашему вниманию книгу, написанную моим близким другом Максимом Макуриным: Секреты эффективного управления ассортиментом.
Книга предназначается для широкого круга читателей и, по мнению автора, будет полезна специалистам отдела закупок и логистики, категорийным и финансовым менеджерам, менеджерам по продажам, аналитикам, руководителям и директорам, в компетенции которых принятие решений по управлению ассортиментом.
Комментарии: 0