7👍
Given a plugin instance,instance.get_plugin_instance()
method returns a tuple containing:
- instance – The plugin instance
- plugin – the associated plugin class instance
get_plugin_instance
so something like this to get the parent object:
instance, plugin_class = object.parent.get_plugin_instance()
3👍
Option 1
Looking at the source code of CMSPluginBase
, you might be able to use the implementation of get_child_classes
. Unfortunately, that method really only returns the class names, so you cannot use it directly. But I think it actually does iterate over the child instances to get the class names:
def get_child_classes(self, slot, page):
from cms.utils.placeholder import get_placeholder_conf
template = page and page.get_template() or None
# config overrides..
ph_conf = get_placeholder_conf('child_classes', slot, template, default={})
child_classes = ph_conf.get(self.__class__.__name__, self.child_classes)
if child_classes:
return child_classes
from cms.plugin_pool import plugin_pool
installed_plugins = plugin_pool.get_all_plugins(slot, page)
return [cls.__name__ for cls in installed_plugins]
What you’d be interested in would be these two lines:
from cms.plugin_pool import plugin_pool
installed_plugins = plugin_pool.get_all_plugins(slot, page)
Option 2
Another way (the one I am using in my code) is to use signals, though this also requires finding the correct objects. The code is not very readable imho (see my lingering inline comments), but it works. It was written a while ago but I am still using it with django-cms 3.2.3.
The placeholder names really are the names that you have configured for your placeholders. It’s certainly preferable to move that into the settings or somewhere. I’m not sure why I haven’t done that, though.
I’d be interested in your solution!
# signals.py
import itertools
import logging
from cms.models import CMSPlugin
from cms.plugin_pool import plugin_pool
from django.db import ProgrammingError
from django.db.models.signals import post_save
logger = logging.getLogger(__name__)
_registered_plugins = [CMSPlugin.__name__]
def on_placeholder_saved(sender, instance, created, raw, using, update_fields, **kwargs):
"""
:param sender: Placeholder
:param instance: instance of Placeholder
"""
logger.debug("Placeholder SAVED: %s by sender %s", instance, sender)
# TODO this is totally ugly - is there no generic way to find out the related names?
placeholder_names = [
'topicintro_abstracts',
'topicintro_contents',
'topicintro_links',
'glossaryentry_explanations',
]
fetch_phs = lambda ph_name: _fetch_qs_as_list(instance, ph_name)
container = list(itertools.chain.from_iterable(map(fetch_phs, placeholder_names)))
logger.debug("Modified Placeholder Containers %s (%s)", container, placeholder_names)
if container:
if len(container) > 1:
raise ProgrammingError("Several Containers use the same placeholder.")
else:
# TODO change modified_by (if possible?)
container[0].save()
def _fetch_qs_as_list(instance, field):
"""
:param instance: a model
:param field: optional field (might not exist on model)
:return: the field values as list (not as RelatedManager)
"""
qs = getattr(instance, field)
fields = qs.all() if qs else []
return fields
def on_cmsplugin_saved(sender, instance, created, raw, using, update_fields, **kwargs):
"""
:param sender: CMSPlugin or subclass
:param instance: instance of CMSPlugin
"""
plugin_class = instance.get_plugin_class()
logger.debug("CMSPlugin SAVED: %s; plugin class: %s", instance, plugin_class)
if not plugin_class.name in _registered_plugins:
post_save.connect(on_cmsplugin_saved, sender=plugin_class)
_registered_plugins.append(plugin_class.name)
logger.info("Registered post_save listener with %s", plugin_class.name)
on_placeholder_saved(sender, instance.placeholder, created, raw, using, update_fields)
def connect_existing_plugins():
plugin_types = CMSPlugin.objects.order_by('plugin_type').values_list('plugin_type').distinct()
for plugin_type in plugin_types:
plugin_type = plugin_type[0]
if not plugin_type in _registered_plugins:
plugin_class = plugin_pool.get_plugin(plugin_type)
post_save.connect(on_cmsplugin_saved, sender=plugin_class)
post_save.connect(on_cmsplugin_saved, sender=plugin_class.model)
_registered_plugins.append(plugin_type)
_registered_plugins.append(plugin_class.model.__name__)
logger.debug("INIT registered plugins: %s", _registered_plugins)
post_save.connect(on_cmsplugin_saved, sender=CMSPlugin)
You have to setup these signals somewhere. I’m doing this in my urls.py, though the app config might be the suitable location for it? (I’m trying to avoid app configs.)
# This code has to run at server startup (and not during migrate if avoidable)
try:
signals.connect_existing_plugins()
except db.utils.ProgrammingError:
logger.warn('Failed to setup signals (if your DB is not setup (not tables), you can savely ignore this error.')
- [Django]-Best way to incorporate external django app into a project and safely make local changes
- [Django]-Django – Custom Template Tag passing keyword args
- [Django]-Issue with returning Cyrillic symbols from MSSQL via unixODBC and FreeTDS
- [Django]-CSS missing from django admin pages on development server after execution of drop database
- [Django]-Feature differentiation: Rails / Django
3👍
By the fact that children plugins always inherit the context. In the parent template you be able to do:
{% with something=instance.some_parent_field %}
{% for plugin in instance.child_plugin_instances %}
{% render_plugin plugin %}
{% endfor %}
{% endwith %}
And use something in your child template.
- [Django]-Django-CKeditor: How to show RichTextFields in templates
- [Django]-Why can’t Internet Explorer access my Django Development Server that’s accessible externally (i.e. not on localhost?)
- [Django]-Exception while installing packages in Python
- [Django]-How do I treat django's TemporaryUploadedFile as a regular python file
- [Django]-Is there a way to transfer images between Django Rest Framework and Flutter app?