Перейти к содержимому

Интеграция модуля с RedsolutionCMS

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

Итак, вы решили добавить свой модуль в Redsolution CMS. Первое время мы ещё будем работать над API установщика, поэтому следите за изменениями в документации.

Организация

Для того чтобы ваш модуль распознавался как подключаемый в Redsolution CMS, надо, чтобы его название содержало redsolutioncms. Если вы не хотите публиковать модуль с таким названием, то можете опубликовать установщик отдельно, прописав в его зависимостях свой модуль.

В списке все модули поделены на категории. Категорию для своего модуля можно задать, если в его документации встретится ссылка вида /classifiers/<classifier>. Пока мы задали лишь несколько категорий:

  • frontpage — приложения, которые могут быть главной страницей;
  • content — приложения, которые так или иначе связаны с контентом на сайте;
  • utilities — вспомогательные приложения;
  • templates — шаблоны.

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

Как уже упоминалось, для того чтобы CMS после загрузки модуля поняла, как настраивать модуль, необходимо указать точку входа. Сделать это можно в setup.py:

setup(
    entry_points={
        'redsolutioncms': ['myapp = myapp.redsolution_setup', ],
    },
)

Redsolution CMS ищет точку входа с названием redsolutioncms. В примере выше CMS попытается импортировать myapp.redsolution_setup. Если в этом модуле есть импортируемый модуль urls, то CMS будет считать модуль настраиваемым и предложит ссылку для настройки на третьем шаге.

Структура настройщика

Теперь о самом модуле myapp.redsolution_setup. Мы рассмотрим пример с настройщиком для приложения обратной связи redsolutioncms.django.feedback. Мы сделаем сразу интерфейс для настройки.

Модели

Для моделей есть базовый класс redsolutioncms.models.BaseSettings и менеджер redsolutioncms.models.BaseSettingsManager. Метод get_settings у менеджера возвращает или создаёт настройки по умолчанию. Из модуля настройки можно импортировать настройки самой Redsolution CMS:

from redsolutioncms.models import CMSSettings
cms_settings = CMSSettings.objects.get_settings()

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

Текст модели и её менеджера для настройщика модуля будет выглядеть примерно так:

from django.db import models
from django.utils.translation import ugettext_lazy as _
from redsolutioncms.models import CMSSettings, BaseSettings, BaseSettingsManager

class FeedbackSettingsManager(BaseSettingsManager):
    def get_settings(self):
        if self.get_query_set().count():
            return self.get_query_set()[0]
        else:
            feedback_settings = self.get_query_set().create()
            return feedback_settings

class FeedbackSettings(BaseSettings):
    use_direct_view = models.BooleanField(
        verbose_name=_('Use dedicated view to render feedback page'),
        default=True
    )
    objects = FeedbackSettingsManager()

Админка

Для интерактивной настройки мы решили использовать уже готовые классы админки Django. Для того чтобы дать пользователю выбрать значение флага, нужно создать класс ModelAdmin и прописать его в urls.py настройщика.

Текст admin.py:

from django.contrib import admin
from feedback.redsolution_setup.models import FeedbackSettings
from redsolutioncms.admin import CMSBaseAdmin

class FeedbackSettingsAdmin(CMSBaseAdmin):
    model = FeedbackSettings

Да, такой короткий. И текст urls.py, в котором создаётся на лету объект админки и пользователю показывают страницу изменения свойств объекта:

from django.conf.urls.defaults import patterns, url
from feedback.redsolution_setup.admin import FeedbackSettingsAdmin

admin_instance = FeedbackSettingsAdmin()
urlpatterns = patterns('',
    url(r'^$', admin_instance.change_view, name='feedback_index'),
)

Однако создание модели это половина работы. Модели настройщиков хранят значения настроек, на этапе создания интегрируются друг с другом и предоставляют интерактивный интерфейс. Конечным же продуктом будут файлы проекта. Зачастую изменения надо вносить только в settings.py и urls.py. Изменения вносятся на этапе сборки.

Сборка

За сборку настроек отвечает файл make.py, он обязательный. Сборка проходит в три этапа.

  1. Premake. На этом этапе подготавливаются начальные значения переменных, создаются папки, Redsolution CMS создаёт базовый шаблон и так далее. В premake располагайте те функции, которые должны отработать прежде всех остальных.
  2. Make. Основной этап сборки. Redsolution CMS создаёт проект, рендерит шаблоны, затем остальные модули делают то же самое. Некоторые из модулей копируют медиа файлы в папку проекта на этой стадии.
  3. Postmake. Заключительная стадия. Она введена для тех операций, которые предполагают почти собранный проект. На этой стадии Redsolution CMS генерирует карты сайта для модулей, обрабатывает начальные данные приложений и так далее. Некоторые приложения копируют медиа файлы и на этой стадии.

Для записи настроек в файлы проекта созданы методы объектов CMSSettings.

render_to

cms_settings.render_to(file_name, template_name, dictionary=None, mode='a+')

Генерирует контент в заданный файл по указанному шаблону. Параметры:

  • file_name — имя файла, в который ведётся запись;
  • template_name — путь к шаблону;
  • dictionary — словарь для отрисовки шаблона;
  • mode — режим записи. Для перезаписи передайте mode='w'.

В этой функции file_name может быть списком, при записи этот список будет соединён функцией os.path.join в путь до файла. Например:

cms_settings = CMSSettings.objects.get_settings()
feedback_settings = FeedbackSettings.objects.get_settings()
cms_settings.render_to('settings.py', 'feedback/redsolutioncms/settings.pyt', {
    'feedback_settings': feedback_settings,
})

copy_file

cms_settings.copy_file(dst, src, mode='wb')

Копирует или дописывает контент указанного файла. Параметры: dst — файл куда писать (здесь не работает трюк со списком), src — исходный файл, mode — режим записи. Эта функция может пригодиться, если вам нужно скопировать, например, начальные данные:

cms_settings.copy_file(
    join(cms_settings.project_dir, 'fixtures', 'initial_data.json'),
    join(dirname(__file__), 'fixtures', 'project_data', 'initial_data.json'),
    mode='a',
)

copy_dir

cms_settings.copy_dir(dst, src, merge=True)

Функция для копирования каталогов. Параметры: dst — каталог куда записывать, src — исходный каталог, merge — режим перезаписи. Если merge=True, только новые файлы дописываются в каталог; если merge=False, то целевой каталог полностью замещается исходным. Этой функцией удобно пользоваться для копирования стилей или медиа файлов:

cms_settings = CMSSettings.objects.get_settings()
cms_settings.copy_dir(
    os.path.join(cms_settings.project_dir, 'media',),
    os.path.join(os.path.dirname(__file__), 'templates', 'classic', 'media'),
    merge=True
)

Пример make класса

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

from redsolutioncms.make import BaseMake
from redsolutioncms.models import CMSSettings
from feedback.redsolution_setup.models import FeedbackSettings
from os.path import dirname, join
import shutil

class Make(BaseMake):
    def make(self):
        super(Make, self).make()
        cms_settings = CMSSettings.objects.get_settings()
        feedback_settings = FeedbackSettings.objects.get_settings()
        cms_settings.render_to('settings.py', 'feedback/redsolutioncms/settings.pyt', {
            'feedback_settings': feedback_settings,
        })
        cms_settings.render_to('urls.py', 'feedback/redsolutioncms/urls.pyt', {
            'feedback_settings': feedback_settings,
        })

    def postmake(self):
        super(Make, self).postmake()
        cms_settings = CMSSettings.objects.get_settings()
        feedback_settings = FeedbackSettings.objects.get_settings()
        feedback_media_dir = join(dirname(dirname(__file__)), 'media')
        project_media_dir = join(cms_settings.project_dir, 'media')
        try:
            shutil.rmtree(join(project_media_dir, 'feedback'))
        except OSError:
            pass
        if 'redsolutioncms.django.server.config' not in cms_settings.installed_packages:
            shutil.copytree(
                join(feedback_media_dir, 'feedback'),
                join(project_media_dir, 'feedback'),
            )

make = Make()