Добавление copy_relations за пределами плагина с помощью signals в django cms

6 июля 2021 г. 8:59

В django-cms иногда необходимо добавить или расширить copy_relations() в модели стороннего плагина для обработки внешних ключей: ForeignKey, OneToOneField или ManyToManyField.

Например, есть некое стороннее приложение (cms плагин) text_block с моделью TextBlock:

# models.py
class TextBlock(CMSPlugin):
    title = models.CharField(_('Title'), max_length=255)
    content = models.TextField(_('Content'))


# cms_plugins.py
class TextBlockPlugin(CMSPluginBase):
    model = TextBlock
    name = 'TextBlock'
    render_template = 'text_block.html'

И нам нужно добавить какое-нибудь дополнительное поле, например, description (описание).

Для этого добавляем в проект новое приложение, например, text_block_ext с моделью TextBlockExt:

class TextBlockExt(models.Model):
    text_block = models.OneToOneField(TextBlock, on_delete=models.CASCADE)
    description = models.TextField(_('Description'))

Ext (в слове TextBlockExt) - это сокращение слова Extension (расширение) - обычно я так называю модели, которые расширяют чью-либо функциональность.

Теперь надо добавить поле description в форму редактирования TextBlock. Это можно сделать с помощью добавления inline объекта admin-класса для модели TextBlock и перерегистрации админ-класса в файле cms_plugins.py:

from text_block.cms_plugins import TextBlockPlugin as BaseTextBlockPlugin
from text_block_ext.models import TextBlockExt


plugin_pool.unregister_plugin(BaseTextBlockPlugin)


class TextBlockExtInline(admin.StackedInline):
    model = TextBlockExt
    extra = 1
    can_delete = False
    verbose_name = _('Additional options')
    verbose_name_plural = _('Additional options')


@plugin_pool.register_plugin
class TextBlockPlugin(BaseTextBlockPlugin):
    render_template = 'text_block_ext.html'
    inlines = (TextBlockExtInline, )

При добавлении / редактировании плагина TextBlock теперь мы увидим наш инлайн-объект с полем description. Введя какое-нибудь значение и сохранив объект, мы увидим, что наш шаблон выдаёт сохранённые данные, например, в таком шаблоне:

<div class="text_block">
    <h2>{{ instance.title }}</h2>
    {% instance.textblockext.description %}<div>Description = {{ instance.textblockext.description }}</div>{% endif %}
    <div>{{ instance.content }}</div>
</div>

Но проблема в том, что при публикации страницы мы не увидим сохранённого поля description, так как django-cms при публикации не обрабатывает внешние ключи. Обычным способом это делается через добавление copy_relations() в модель плагина, но так как у нас сторонний плагин, то нужно как-то обработать внешние ключи.

Добавление сигнала post_publish в наше приложение

К счастью, django-cms предоставляет сигнал post_publish, в котором мы можем добраться до нашего опубликованного компонента и добавить внешний ключ TextBlockExt. Добавляем получатель сигнала в text_block_ext/signals.py, где обработаем внешние ключи:

from django.dispatch import receiver
from cms.signals import post_publish
from text_block.models import TextBlock


@receiver(post_publish)
def copy_relations(sender, instance, language, **kwargs):
    published_text_blocks = TextBlock.objects.filter(placeholder__page=instance.publisher_public)
    for published_text_block in published_text_blocks:
        text_block_parent = TextBlock.objects.get(id=published_text_block.parent_instance_id)
        if hasattr(text_block_parent, 'textblockext'):
            text_block_ext = text_block_parent.textblockext
            text_block_ext.id = None

            published_text_block.textblockext = text_block_ext
            published_text_block.textblockext.save()

У опубликованного плагина есть свойство parent_instance_id, через который можно получить неопубликованный плагин text_block_parent: TextBlock.objects.get(id=published_text_block.parent_instance_id). Чтобы скопировать text_block_ext, нужно просто к id присвоить None. И далее уже к published_text_block.textblockext присваиваем скопированный text_block_ext.

Теперь после публикации страницы опубликованные плагины получат объект text_block_ext.

Возможности сигнала post_publish не ограничивается добавлением кастомных copy_relations() для сторонних моделей. В сигнале можно много разных полезных для сайта функций выполнять, например, генерировать свежую версию sitemap.xml, производить оповещение главному редактору сайта о том, что была произведена публикация сайта или обновлять статистику по опубликованным страницам и т. д.

Оцените статью

0 из 5 (всего 0 оценок)

captcha
Отмеченные звёздочкой поля ( * ) являются обязательными для заполнения.

Спасибо за ваш отзыв!

После нажатия кнопки "Отправить" ваше сообщение будет доставлено мне на почту.

Автор статьи

Артём Мальцев

Веб-разработчик, владеющий знаниями языка программирования Python, фреймворка Django, системы управления содержимым сайта Django CMS, платформы для создания интернет-магазина Django Shop и многих различных приложений, использующих эти технологии.

Права на использование материала, расположенного на этой странице https://vivazzi.pro/ru/it/copy-relations-signals/:

Разрешается копировать материал с указанием её автора и ссылки на оригинал без использования параметра rel="nofollow" в теге <a>. Использование:

Автор статьи: Артём Мальцев
Ссылка на статью: <a href="https://vivazzi.pro/ru/it/copy-relations-signals/">https://vivazzi.pro/ru/it/copy-relations-signals/</a>

Больше: Правила использования сайта

Представляю вашему вниманию книгу, написанную моим близким другом Максимом Макуриным: Секреты эффективного управления ассортиментом.

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

Комментарии: 0

Вы можете оставить комментарий как незарегистрированный пользователь.

Но зарегистрировавшись, вы сможете:

  • получать оповещения об ответах
  • просматривать свои комментарии
  • иметь возможность использовать все функции разработанных сервисов

Для комментирования от своего имени войдите или зарегистрируйтесь на сайте Vuspace

Отправить

На данный момент нет специального поиска, поэтому я предлагаю воспользоваться обычной поисковой системой, например, Google, добавив "vivazzi" после своего запроса.

Попробуйте

Выберите валюту для отображения денежных единиц