Placeholders outside the CMS

Placeholders 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.

Placeholders can be viewed as containers for CMSPlugin instances, and can be used outside the CMS in custom applications using the PlaceholderField.

By defining one (or several) PlaceholderField on a custom model you can take advantage of the full power of CMSPlugin.

Get started

You need to define a PlaceholderField on the model you would like to use:

  1. from django.db import models
  2. from cms.models.fields import PlaceholderField
  3. class MyModel(models.Model):
  4. # your fields
  5. my_placeholder = PlaceholderField('placeholder_name')
  6. # your methods

The PlaceholderField has one required parameter, a string slotname.

The slotname is used in templates, to determine where the placeholder’s plugins should appear in the page, and in the placeholder configuration CMS_PLACEHOLDER_CONF, which determines which plugins may be inserted into this placeholder.

You can also use a callable for the slotname, as in:

  1. from django.db import models
  2. from cms.models.fields import PlaceholderField
  3. def my_placeholder_slotname(instance):
  4. return 'placeholder_name'
  5. class MyModel(models.Model):
  6. # your fields
  7. my_placeholder = PlaceholderField(my_placeholder_slotname)
  8. # your methods

Warning

For security reasons the related_name for a PlaceholderField may not be suppressed using '+'; this allows the cms to check permissions properly. Attempting to do so will raise a ValueError.

Note

If you add a PlaceholderField to an existing model, you’ll be able to see the placeholder in the frontend editor only after saving the relevant instance.

Admin Integration

Changed in version 3.0.

Your model with PlaceholderFields can still be edited in the admin. However, any PlaceholderFields in it will only be available for editing from the frontend. PlaceholderFields must not be present in any fieldsets, fields, form or other ModelAdmin field’s definition attribute.

To provide admin support for a model with a PlaceholderField in your application’s admin, you need to use the mixin PlaceholderAdminMixin along with the ModelAdmin. Note that the PlaceholderAdminMixin must precede the ModelAdmin in the class definition:

  1. from django.contrib import admin
  2. from cms.admin.placeholderadmin import PlaceholderAdminMixin
  3. from myapp.models import MyModel
  4. class MyModelAdmin(PlaceholderAdminMixin, admin.ModelAdmin):
  5. pass
  6. admin.site.register(MyModel, MyModelAdmin)

I18N Placeholders

Out of the box PlaceholderAdminMixin supports multiple languages and will display language tabs. If you extend your model admin class derived from PlaceholderAdminMixin and overwrite change_form_template have a look at admin/placeholders/placeholder/change_form.html to see how to display the language tabs.

If you need other fields translated as well, django CMS has support for django-hvad. If you use a TranslatableModel model be sure to not include the placeholder fields amongst the translated fields:

  1. class MultilingualExample1(TranslatableModel):
  2. translations = TranslatedFields(
  3. title=models.CharField('title', max_length=255),
  4. description=models.CharField('description', max_length=255),
  5. )
  6. placeholder_1 = PlaceholderField('placeholder_1')
  7. def __unicode__(self):
  8. return self.title

Be sure to combine both hvad’s TranslatableAdmin and PlaceholderAdminMixin when registering your model with the admin site:

  1. from cms.admin.placeholderadmin import PlaceholderAdminMixin
  2. from django.contrib import admin
  3. from hvad.admin import TranslatableAdmin
  4. from myapp.models import MultilingualExample1
  5. class MultilingualModelAdmin(TranslatableAdmin, PlaceholderAdminMixin, admin.ModelAdmin):
  6. pass
  7. admin.site.register(MultilingualExample1, MultilingualModelAdmin)

Templates

To render the placeholder in a template you use the render_placeholder tag from the cms_tags template tag library:

  1. {% load cms_tags %}
  2. {% render_placeholder mymodel_instance.my_placeholder "640" %}

The render_placeholder tag takes the following parameters:

  • PlaceholderField instance
  • width parameter for context sensitive plugins (optional)
  • language keyword plus language-code string to render content in the specified language (optional)

The view in which you render your placeholder field must return the request object in the context. This is typically achieved in Django applications by using RequestContext:

  1. from django.shortcuts import get_object_or_404, render
  2. def my_model_detail(request, id):
  3. object = get_object_or_404(MyModel, id=id)
  4. return render(request, 'my_model_detail.html', {
  5. 'object': object,
  6. })

If you want to render plugins from a specific language, you can use the tag like this:

  1. {% load cms_tags %}
  2. {% render_placeholder mymodel_instance.my_placeholder language 'en' %}

Adding content to a placeholder

Changed in version 3.0.

Placeholders can be edited from the frontend by visiting the page displaying your model (where you put the render_placeholder tag), then appending ?edit 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.

There is no automatic draft/live functionality for general Django models, so content is updated instantly whenever you add/edit them.

Options

If you need to change ?edit to a custom string (say, ?admin_on) you may set CMS_TOOLBAR_URL__EDIT_ON variable in your settings.py to "admin_on".

You may also change other URLs with similar settings:

  • ?edit_off (CMS_TOOLBAR_URL__EDIT_OFF)
  • ?build (CMS_TOOLBAR_URL__BUILD)
  • ?toolbar_off (CMS_TOOLBAR_URL__DISABLE)

When changing these settings, please be careful because you might inadvertently replace reserved strings in system (such as ?page). We recommended you use safely unique strings for this option (such as secret_admin or company_name).

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 PlaceholderField, 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

For example, if there is a UserProfile model that contains a PlaceholderField then the custom backend can refer to a has_perm method (on the model) that grants all rights to current user only based on the user’s UserProfile object:

  1. def has_perm(self, user_obj, perm, obj=None):
  2. if not user_obj.is_staff:
  3. return False
  4. if isinstance(obj, UserProfile):
  5. if user_obj.get_profile()==obj:
  6. return True
  7. return False