Django CMS插件关联对象编辑自动发布功能实现咨询
Hey there! Let's work through your problem—you want all edits to related objects (whether via TabularInline, CMS plugin edit views, or the admin) to route through the Admin interface, and have those changes auto-publish to the front end without needing manual site publish clicks. Here's a step-by-step solution tailored to Django CMS and Django Admin:
First, we need to make sure any attempt to edit related objects redirects or links directly to the Admin, instead of using custom CMS plugin forms.
For TabularInline (Admin Native)
TabularInline is already an Admin component, so edits here will naturally use the Admin flow. Just ensure your Inline is properly configured in your parent model's Admin class:
from django.contrib import admin from .models import ParentModel, RelatedModel class RelatedModelInline(admin.TabularInline): model = RelatedModel extra = 1 class ParentModelAdmin(admin.ModelAdmin): inlines = [RelatedModelInline] admin.site.register(ParentModel, ParentModelAdmin)
For CMS Plugin Edit Views
Replace any inline edit forms in your CMS plugin's edit popup with links to the Admin. First, update your plugin to pass related objects to the template:
from cms.plugin_base import CMSPluginBase from cms.plugin_pool import plugin_pool from .models import MyPluginModel from django.utils.translation import gettext_lazy as _ class MyPlugin(CMSPluginBase): model = MyPluginModel name = _("My Custom Plugin") render_template = "myapp/plugin.html" change_form_template = "myapp/plugin_edit.html" # Custom edit template def render_edit(self, context, instance, placeholder): context['related_objects'] = instance.related_objects.all() return super().render_edit(context, instance, placeholder)
Then create the custom edit template (myapp/plugin_edit.html) with Admin links:
{% extends "cms/plugins/edit.html" %} {% block plugin_content %} <h3>Related Objects</h3> {% for obj in related_objects %} <div> {{ obj.title }} <a href="{% url 'admin:myapp_relatedmodel_change' obj.id %}" target="_blank">Edit in Admin</a> </div> {% empty %} <p>No related objects yet. <a href="{% url 'admin:myapp_relatedmodel_add' %}?page={{ placeholder.page.id }}" target="_blank">Add New in Admin</a></p> {% endfor %} {% endblock %}
This forces users to edit related objects directly in the Admin, ensuring all requests follow the Admin workflow.
To auto-publish after saving related objects, we'll use Django signals (or override Admin save methods) to trigger page publishing whenever a related object is updated.
Option 1: Use Django Signals (Global Trigger)
Create a post_save signal that finds all CMS pages using the modified related object and publishes them:
from django.db.models.signals import post_save from django.dispatch import receiver from cms.models import Page, CMSPlugin from .models import RelatedModel, MyPluginModel @receiver(post_save, sender=RelatedModel) def auto_publish_related_changes(sender, instance, **kwargs): # Find all plugin instances linked to the modified related object plugin_instances = MyPluginModel.objects.filter(related_objects=instance) for plugin in plugin_instances: cms_plugin = plugin.cmsplugin_ptr page = cms_plugin.placeholder.page # Publish the page if it has a draft version if page and page.publisher_is_draft: page.publish(user=None) # Pass a user object if you need audit logs
Option 2: Override Admin Save Method (Admin-Only Trigger)
If you only want auto-publish when edits happen via the Admin, override the save_model method in your RelatedModel's Admin class:
from django.contrib import admin from .models import RelatedModel class RelatedModelAdmin(admin.ModelAdmin): def save_model(self, request, obj, form, change): super().save_model(request, obj, form, change) # Reuse the publish logic from the signal above plugin_instances = MyPluginModel.objects.filter(related_objects=obj) for plugin in plugin_instances: page = plugin.cmsplugin_ptr.placeholder.page if page and page.publisher_is_draft: page.publish(user=request.user) # Use the current admin user for logs admin.site.register(RelatedModel, RelatedModelAdmin)
- Permissions: Ensure users have both
changepermissions for the related model andpublishpermissions for CMS pages. - Bulk Edits: For bulk edits in the Admin, add a custom action to trigger publishing for all modified objects.
- Performance: If a related object is used on many pages, use async tasks (like Celery) to handle publishing in the background and avoid blocking the Admin interface.
- Draft/Live Sync: Add checks to skip publishing if the page's draft and live versions are already identical.
内容的提问来源于stack exchange,提问作者Lukasz Jagodzinski

