.. _placeholders_outside_cms: How to use placeholders outside the CMS ======================================= Placeholder fields are special model fields that django CMS uses to render user-editable content (plugins) in templates. That is, it's the place where a user can add text, video or any other plugin to a webpage, using the same frontend editing as the CMS pages. .. versionchanged:: 4.0 Since django CMS 4.0 the toolbar offers preview and edit endpoints for Django models which contain Placeholders. - This allows for models (such as django CMS Alias) which do not have a user-facing view to still contain placeholders. - However, it requires the registration of frontend-editable models with django CMS. - Also, views need to tell the toolbar if they contain a frontend-editable model. Placeholders can be viewed as containers for :class:`~cms.models.pluginmodel.CMSPlugin` instances, and can be used outside the CMS in custom applications using the :class:`~cms.models.fields.PlaceholderRelationField`. By defining a :class:`~cms.models.fields.PlaceholderRelationField` on a custom model you can take advantage of the full power of :class:`~cms.models.pluginmodel.CMSPlugin` in one or more placeholders. .. warning:: Django CMS 3.x used a different way of integrating placeholders. It's ``PlaceholderField("slot_name")`` needs to be changed into a ``PlaceholderRelationField`` (available since django CMS 4.x). Two ways to render model placeholders ------------------------------------- A quick glossary: - A **slot** is the string name that identifies a placeholder in a template (for example ``"content"``). Slot names are also used by :setting:`CMS_PLACEHOLDER_CONF` to configure which plugins can be inserted. - A **placeholder** is the per-instance container (a :class:`~cms.models.placeholdermodel.Placeholder` object) that holds the plugins for a given slot on a given model instance. - The **structure board** is django CMS's frontend editor view where editors add, remove and reorder plugins. django CMS offers two template tags for placeholders on your own models: - :ttag:`placeholder` — *declares and renders* in one step. The same template is both what your view renders and what django CMS scans to discover slot names for the structure board. - :ttag:`render_placeholder` — *only renders* a placeholder instance that the model exposes as a property (typically via :func:`~cms.utils.placeholder.get_placeholder_from_slot`). Because this tag does not declare its slot, the model also needs a separate declaration-only template for the structure board to discover the slots. **Prefer Approach 1 for new models.** Use Approach 2 only when you're integrating with code that already uses :ttag:`render_placeholder`, or when you want each placeholder exposed as a named model property. Both approaches share the same :class:`~cms.models.fields.PlaceholderRelationField` and the toolbar integration described in :ref:`toolbar_object` below. Approach 1: Using ``{% placeholder %}`` --------------------------------------- Step 1 — Add a :class:`~cms.models.fields.PlaceholderRelationField` and a ``get_template()`` method pointing to the template you'll create in Step 2. This is the template your view will render and that django CMS will scan for slot declarations: .. code-block:: python from django.db import models from cms.models.fields import PlaceholderRelationField class MyModel(models.Model): # your fields placeholders = PlaceholderRelationField() def get_template(self): return "my_app/my_model_template.html" Step 2 — Create that template. It declares the slots your model owns with the :ttag:`placeholder` tag, alongside any other markup you need — the same tags are used both to declare the slots (so django CMS can list them in the structure board) and to render their content: .. code-block:: html+django {# templates/my_app/my_model_template.html #} {% load cms_tags %}
{{ my_obj.description }}
{% endif %} {% endwith %} .. note:: If you want to render plugins from a specific language, you can use the tag like this: .. code-block:: html+django {% load cms_tags %} {% render_placeholder mymodel_instance.my_placeholder language 'en' %} Adding the slots to the model ----------------------------- To let django CMS' frontend editor know which placeholders the model contains, declare them in a second template, only needed for rendering the structure mode, called, say, ``templtes/my_app/my_model_structure.html``: .. code-block:: html+django {% load cms_tags %} {% placeholder "slot_name" %} The important bit is to include all slot names for the model in the structure template. Other parts of the templte are not necessary. Add the structure mode template to the model -------------------------------------------- Let the model know about this template by declaring the ``get_template()`` method: .. code-block:: class MyModel(models.Model): ... def get_template(self): return "my_app/my_model_structure.html" ... .. _register_model_frontend_editing: Registering the model for frontend editing ------------------------------------------ .. versionadded:: 4.0 The final step is to register the model for frontend editing. Since django CMS 4 this is done by adding a :class:`~cms.app_base.CMSAppConfig` class to the app's `cms_config.py` file: .. code-block:: python from cms.app_base import CMSAppConfig from . import models, views class MyAppConfig(CMSAppConfig): cms_enabled = True cms_toolbar_enabled_models = [(models.MyModel, views.render_my_model)] .. note:: If using class based views, use the stub view in ``cms_toolbar_enabled_models`` attribute. .. code-block:: python cms_toolbar_enabled_models = [(models.MyModel, views.my_model_endpoint_view)] Adding content to a placeholder ------------------------------- Placeholders can be edited from the frontend by visiting the page displaying your model (where you put the :ttag:`placeholder` or :ttag:`render_placeholder` tag), then appending ``?toolbar_on`` to the page's URL. This will make the frontend editor top banner appear (and if necessary will require you to login). Once in frontend editing mode, the interface for your application's ``PlaceholderFields`` will work in much the same way as it does for CMS Pages, with a switch for Structure and Content modes and so on. .. _placeholder_object_permissions: Permissions ~~~~~~~~~~~ To be able to edit a placeholder user must be a ``staff`` member and needs either edit permissions on the model that contains the :class:`~cms.models.fields.PlaceholderRelationField`, or permissions for that specific instance of that model. Required permissions for edit actions are: - to ``add``: require ``add`` **or** ``change`` permission on related Model or instance. - to ``change``: require ``add`` **or** ``change`` permission on related Model or instance. - to ``delete``: require ``add`` **or** ``change`` **or** ``delete`` permission on related Model or instance. With this logic, an user who can ``change`` a Model's instance but can not ``add`` a new Model's instance will be able to add some placeholders or plugins to existing Model's instances. Model permissions are usually added through the default Django ``auth`` application and its admin interface. Object-level permission can be handled by writing a custom authentication backend as described in `django docs