Создание темы для вебсайта
Содержание
В этой статье мы рассмотрим, как использовать модуль website, который идет в стандартной поставке Community Edition.
Подготовка
Для того, чтобы использовать следующий пример, вам необходимо переключить текущий разрабатываемый проект на другую ветку.
Вот ее имя - 16.0-website-usage-example
Затем удалите текущую базу и создайте новую.
Убедитесь, что у вас не осталось вкладок со старыми сессиями
В файл конфигурации в параметры init_modules
и update_modules
добавьте имя модуля theme_airproof
Запустите менеджер с параметрами -d
, -i
, и -u
Перейдите откройте браузер по адресу http://127.0.0.1:8069
Небольшое вступление
Использование темы описано в официально документации вот тут. При попытке использовать это описание лично у меня возникло большое количество вопросов, которые не описаны в документации, поэтому эта статья(статьи) буду опираться ровно на те же разделы, которые есть в официальной документации, только уже с опорой на рабочий код, который вы можете найти в моем демо-репозитории.
Тема в odoo
Темой в odoo называется специальный модуль, который объявлен специальным образом:
- В ключе
category
файла__manifest__.py
необходимо указать значениеTheme
- В ключе
depends
файла__manifest__.py
необходимо добавить модульwebsite
- В имени модуля на первом месте должно стоять ключевое слово
theme_
Менеджер тем в odoo
Чтобы установить произвольную тему вам нужно выполнить следующие действия:
- Залогиниться
- Выбрать пункт меню
Website
- Нажмите
Edit
, чтобы открыть редактор темы
- Нажать
Theme
- Пролистать вниз и нажать
Switch Theme
В появившемся окне выбрать нужную тему:
Как видите, наша тема с именем Airproof
уже установлена, мы можем ее обновить, удалить или установить другую тему.
Первоначальные настройки темы
Данный раздел опирается на вот эту статью из официально документации.
Все первоначальные параметры указываются в файле primary_variables.scss
. Естественно его необходимо добавить в ассеты в файле __manifest__.py
:
Когда будете заполнять параметры обращайте внимание на ключи, которые заполняются в primary_variables.scss
файле.
Использование шрифтов
Так как шрифты это важная часть оформления сайта и, как правило, является базовой, то с них и начнем. Odoo может использовать самостоятельно использовать как шрифты от google: Здесь вы можете видеть пример использования шрифтов от google без дополнительных манипуляций. Достаточно просто правильно объявить их параметры и система сама их начнет использовать через публичное API
А вот пример того, как вы можете использовать любые другие шрифты локально:
- Объявляете в файле
__manifest__.py
в бандлеweb.assets_frontend
дополнительный файл который я назвалfonts.scss
. - Описывает базовые параметры шрифта, в том числе, указываете
url
относительно имени модуля - Добавляете описание шрифта в
primary_variables.scss
Для того, чтобы эти шрифты применились их необходимо правильно объявить:
- Объявляем шрифт по умолчанию
- Шрифт заголовков
- Шрифт в панели навигации
- Шрифт на кнопках
Результат использования шрифтов:
- Использование шрифта из коллекции Google
Nunito
- Использование собственного шрифта
AlumniSansPinstripe
Задание собственных ключевых цветов для темы
Так же для темы вы можете объявить базовые цвета. Это делается так же внутри файла primary_variables.scss
следующим образом:
- Объявление пяти базовых цветов
- Здесь могут быть объявлены вспомогательные цвета
- Данный набор цветов объявляется как
airproof
и подключается для использования в теме как набор цветов по умолчанию
Результат объявления базовых цветов:
Обратите что эти цвета используются по всем элементам сайта, а так же видны в веб-редакторе как основные цвета темы.
Продолжение следует...(эта статья будет писаться в несколько подходов, т.к. объем очень большой)
Компоновка элементов страницы
В данном разделе мы будем опираться на вот этот раздел документации. Глобально современный сайт, как правило, состоит из трех основных элементов:
- Заглавная часть (Header) В этой части как правило находятся контакты, ссылки на социальные сети, а так же основное меню сайта
- Собственно тело страницы (Webpage). Здесь находится контент конкретной страницы.
- Подвал (Footer). Здесь располагается информация о компании, контактах и другие ссылки, которые могут быть полезные посетителям, но находятся за рамками основного контента сайта.
Заглавная часть (Header)
- Обратите внимание для какой модели создается запись
- С помощью директивы
xpath
заменяем стандартныйheader
своим. - Пример изменения ссылок социальных медиа
- Вызов шаблона, который отображает кнопку аутентификации, с передачей параметров
Внимательно изучите шаблон заглавной части целиком. Здесь вы можете увидеть, что все элементы из которых состоит шаблон тоже используют вызов дополнительных шаблонов. Вы можете использовать такую же стратегию, а можете создавать описание html
прямо внутри текущего шаблона. Исходите из вашей собственной задачи.
Подвал (Footer)
- Обратите внимание для какой модели создается запись
- С помощью директивы
xpath
заменяем стандартныйfooter
своим. - Пример блока с призывом
- Пример блока с контактным телефоном
- Пример блока с почтой
- Пример блока с социальными медиа
- Пример блока с собственным логотипом
Обратите внимание, что в отличии от заглавной части здесь не используются дополнительные шаблоны, а все нужные блоки html
объявлены прямо тут
Тело страницы (Webpage)
- Обратите внимание как объявлена запись, если вы хотите объявить ее как
record
то она должна будет принадлежать моделиtheme.ir.ui.view
- С помощью директивы
xpath
заменяем стандартныйfooter
своим. - Объявляем переменные, которые будут указывать на необходимость рендерить
header
иfooter
. - Собственно тело страницы.
Элементы навигации
В данном разделе мы будем опираться на вот этот раздел документации. В этом разделе мы поговорим про элементы навигации, как их добавлять, убирать и менять
Создание элементов меню
- Удаляем элемент меню, который вел на страницу контактов
- Пример добавления элемента главного меню. Обратите внимание на поле с именем
parent_id
в нем вы можете увидеть, что применяется методsearch
с использованием домена, где происходит поиск по имени родительскогоurl
иid
вебсайта. Как было сказано ранее сайтов может быть больше чем один(вероятно поискid
сайта надо делать черезxml_id
, но это пример из официальной документации). В данном случае значение родительскогоurl=/default-main-menu
зарезервировано системой. Кстати контроллера для обслуживания данногоurl
не существует, поэтому система вернет404
страницу - Пункт меню
Еще
. Создается таким же образом как и предыдущий, но как вы видите он уже имеет дочерние пункты. Поэтому при нажатии на него показывается выпадающий список - Пункт меню, который ссылается на внешний сайт. Обратите внимание на значение поля
parent_id
, здесь уже применяется поиск нужногоid
с помощьюxml_id
, и для данного пункта меню родителем является предыдущий. - Еще один дочерний пункт меню, который возвращает
404
страницу
Мега-меню
Мега-меню представляет собой некоторый, достаточно большой, контейнер, куда можно уместить множество дополнительных пунктов меню, уже с помощью обычного html
, а так же любой другой произвольный контент.
- Атрибут меню, который указывает на то что этот пункт меню является мега-меню
- Класс, который добавляется к контейнеру, в который помещается контент мега-меню
- Контент мега-меню
Управление страницами
В данном разделе мы будем опираться на вот этот раздел документации. В этом разделе мы поговорим про создание отдельных страниц и их оформление
Уже существующие страницы
В стандартной поставке, внутри системы уже есть несколько предопределенных страниц:
- Страница ошибки 400
- Страница ошибки 403
- Страница ошибки 404
- Страница ошибки 500
- Страница Home
- Страница Contact us
Вы можете отключить уже определенные страницы следующим образом:
Для домашней страницы
<record id="website.homepage" model="ir.ui.view">
<field name="active" eval="False"/>
</record>
Для страницы контактов
<record id="website.contactus" model="ir.ui.view">
<field name="active" eval="False"/>
</record>
Так же вы можете изменить уже существующую страниц с помощью наследования и директивы XPath
- С помощью атрибута
inherit_id
переопределяем стандартную страницу404
- С помощью директивы
XPath
указываем что мы хотим заменить узелid="wrap"
содержимым нашей директивы - С помощью предопределенной переменной
additional_title
указываем название страницы - Пишем контент нашей переопределенной страницы
Предопределенные переменные для использования в страницах
Название страницы:
<t t-set="additional_title" t-value="'...'"/>
Meta описание:
<t t-set="meta_description" t-value="'...'"/>
Добавляем CSS
класс на страницу
<t t-set="pageName" t-value="'...'"/>
Прячем Заглавую часть (Header)
<t t-set="no_header" t-value="true"/>
Прячем Подвал (Footer)
<t t-set="no_footer" t-value="true"/>
Создание своей страницы
Для начала давайте добавим картинку, которая будет доступна для использования внутри системы:
- Указываем путь к файлу с изображением относительно имени нашего модуля
- Созданная запись с
id="img_about_01"
в моделиir.attachment
становится доступной в медиа каталоге. Атрибутpublic="True"
указывает на то, что этот ресурс будет доступен для всех посетителей сайта, а только внутренних
Теперь используя эту картинку в качестве фона создадим свою страницу:
- Наименование страницы, отображается в наименовании вкладки браузера
- Поле
is_published
со значениемTrue
указывает на то, что эта страница доступна всем посетителям сайта, а не только внутренним - Поле
type
со значениемqweb
указывает на то, что при формировании страницы будет использовать генератор шаблоновqweb
- Поле
header_overlay
со значениемTrue
указывает на то, что хедер не будет прилипать к верху как отдельный блок, а страница, будет как бы заходить за него - Использование ранее объявленной картинки, обратите внимание как указан
url
до нее/web/image/имя_модуля.id_записи_картинки
. Опытные читатель уже заметил что это полныйxml_id
записи этой же картинки. Т.е. все ресурсы объявленные как в примере выше, будут доступны поurl
созданному по следующему шаблону:/web/image/xml_d_записи
- Поле
url
со значениемabout-us
указывает на то, по какомуurl
будет открываться данная страница - Поле
key
должно хранить уникальный ключ для данной страницы(я пока не выяснил для чего конкретно, узнаете пишите)
Как добавлять виде описано тут Как добавлять иконки описано тут
Создание и управление отдельными блоками (сниппетами)
В данном разделе мы будем опираться на вот этот раздел документации. В этом разделе мы поговорим про создание отдельных блоков и настройке их поведения
Блоки
В odoo создан механизм для создания собственных блоков контента, которые вы можете создавать, а ваши пользователи применять у себя самостоятельно. Блоки делятся на следующие типы:
- Структурные блоки: дают возможность управлять основной структурой сайта
- Блоки описания функциональности: дают возможность создавать описание условий и функциональности товаров или услуг
- Блоки с динамическим контентом: это анимированные блоки, или связанные с бэкэндом
- Блоки вложенного контента: блоки, которые предназначены для размещения внутри других блоков
Увидеть все доступные на текущий момент блоки вы можете вот по этой ссылке:
http://127.0.0.1:8069/website/demo/snippets
Структура файлов
Файлы, которые будут описывать блоки должны находиться в следующих местах:
- В каталоге со статическими ресурсами создаете каталог
snippets
, где для каждого блока создаете отдельный каталог и файлы, которые нужны для его работы - В каталоге
views
тоже создаете каталогsnippets
, в котором будут основные шаблоны этих самых блоков
Создание блока
Создание блока начинается с создания его шаблона:
- Уникальный
id
шаблона - Уникальное имя класса шаблона
- Отображаемое имя блока в панели конструктора. Если не указано, будет применено название
Block
. - Используется системой для идентификации блока
- Тег
<section/>
используется для самостоятельных блоков, если же блок предназначен для размещения внутри других блоков, то тэг должен быть<div/>
Внутри блока вы можете использовать стандартную сетку Bootstrap
, как это сделать правильно описано вот тут
Теперь нам необходимо сделать так, чтобы наш новый блок появился в меню конфигуратора, и мы могли его использовать
- Наследуем шаблон с блоками (Здесь применяется стандартный механизм наследования для
xml
представлений) - Добавляем наш набор блоков (состоящий из одного блока) в перед стандартными блоками
- Тэг
<t/>
в котором мы указываемid="x_theme_snippets"
- видимо нужен для служебных целей, чтобы система могла его правильно пристыковать - Уже описываем собственно раздел с нашими блоками атрибут
id="x_theme_snippets_category"
так же нужно указывать, данный элемент мы уже можем видеть внутриDOM
модели браузера - Служебный тег
<t/>
который собственно и определяет уже наш блок. Обратите внимание что в качестве значения атрибутаt-snippet
указан полный xml_id, а так же атрибутt-thumbnail
где указан путь кsvg
файлу, относительно имени модуля. - Ключевые слова, которые нужны для поиска блока в общем списке
Про дополнительные опции можете прочитать тут
Теперь давайте перетянем на страницу наш блок и заглянем в его параметры:
- data-selector - позволяет прицепить к определенному элементу пункт меню редактора и добавлять дополнительные классы через конструкцию
data-select-<custom-attribute>
. В этом примере мы видим что для элемента с селекторомtable
при выборе какого либо пункта меню добавляются в нашем случаеclass="table-bordered"
для выбранногоBordered
. Обратите внимание на служебные теги с префиксомwe
данные теги указывают на то что это они предназначены для работы внутриWebEditor
.
Так же часто возникает ситуация, когда нужно использовать что-то более динамическое и в этом случае необходимо будет использовать javasсript
. Вот как это можно сделать:
- Для того, чтобы система знала какую именно функцию вызвать ее имя необходимо указать в качестве имени атрибута с ключевым словом
data
вначале, где разделителем слов должен быть дефис(kebab-case
), а имя функции вjs
должно быть написаноcamelCase
. В нашем случае атрибут с именемdata-start-table-func
вызовет функцию с именемstartTableFunc
- в js файле импортируем объект
options
изweb_editor.snippets.options
- Добавляем в реестр
options
свой собственный класс, который будет наследоватьoptions.Class
- Объявленная нами функция будет принимать на вход три параметра:
previewMode
- имеет булево значение, определяет, является ли в данный момент блок в режиме предпросмотраwidgetValue
- параметр, который является значением атрибута из пункта 1params
- объект, который описывает собственно объект настроек, какие параметры могут быть, какие функции содержатся и какие параметры могут быть выбраны
Создание и формами для произвольной модели
В данном разделе мы будем опираться на вот этот раздел документации. В этом разделе мы поговорим про создание форм на сайте, которые будут автоматически заполнять поля в у казанной модели.
Формы
Формы - отличный инструмент для того, чтобы получить обратную связь от ваших пользователей. В инструментарии вебсайта есть возможность создавать формы для заранее предопределенных моделей. Для этого вам достаточно следовать инструкции из официальной документации. Там указаны модели для которых вы можете сделать формы. Но что делать если мы хотим сделать форму для произвольной модели?. Ниже я расскажу как это можно сделать.
В файл конфигурации проекта в параметры init_modules
и update_modules
добавьте имя модуля website_first_module
Давайте создадим шаблон формы:
- Создаем пункт меню, который будет вызывать указанный адрес, а по этому адресу будет открываться наша страница с формой.
- Для того, чтобы наша форма отправляла данные в нужную нам модель необходимо указать в атрибуте
data-model_name="first.model"
имя модели, в нашем случае этоfirst.model
- Параметр
data-success-mode
указывает тип подтверждения при удачной отправке данных через форму в нашем случаеredirect
можем быть ещеmessage
но об этом позже - Параметр
data-success-page
нужен при использовании метода подтвержденияredirect
и указывает на какую страницу произойдет перенаправление пользователя - При оформлении полей необходимо у тега
input
указать атрибутname
в котором необходимо написать техническое имя поля (из python файла модели)
При открытии шаблона мы увидим три поля, которые можем заполнить. Для того, чтобы добавить эту фому в редактор сайта, необходимо заполнить дополнительные поля:
0. Выделенная прямоугольником запись показывает какие поля и как нужно заполнить для того, чтобы форма появилась в редакторе
- Указывается дополнительное поле для хранения дополнительной и мета информации. Чуть подробнее будет в следующем блоке
- Наименование формы можно видеть в редакторе
В целом можно пользоваться, но обратите внимание не следующий момент:
- Для того, система сама заполняла поля из полей формы, необходимо указать запуск функции для нужной вам модели, которая пометит поля в системе как доступные для заполнения из формы.
- Обратите внимание что мы заполнили 3 поля а значения записались только те, которые указаны в функции 1
- Третье значение тоже сохранилось но в текстовом виде в поле из пункта 1 предыдущего блока
- Поле для сохранения дополнительной информации с формы.
Обсуждение
Обсудить, указать на ошибки и опечатки можно здесь