Добавление 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