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.

Warning

Screenshots are not in sync with the 3.0 UI at the moment, they will be updated once the new UI will be finalized; for the same reason, you’ll find minor difference in the UI description.

Quickstart

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 (slotname) which can be a of type string, allowing you to configure which plugins can be used in this placeholder (configuration is the same as for placeholders in the CMS) or you can also provide a callable like so:

  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 '+' to allow 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 on the frontend editor only after saving each instance.

Admin Integration

Changed in version 3.0.

If you install this model in the admin application, you have to use the mixin PlaceholderAdminMixin together with, and must precede, ModelAdmin so that the interface renders correctly:

  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)

Warning

Since 3.0 placeholder content can only be modified from the frontend, and thus placeholderfields must not be present in any fieldsets, fields, form or other modeladmin fields definition attribute.

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 be sure to have a look at ‘admin/placeholders/placeholder/change_form.html’ on how to display the language tabs.

If you need other fields then the placeholders translated as well: django CMS has support for django-hvad. If you use a TranslatableModel model be sure to not include the placeholder fields in 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

Now 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_to_response
  2. from django.template.context import RequestContext
  3. from myapp.models import MyModel
  4. def my_model_detail(request, id):
  5. object = get_object_or_404(MyModel, id=id)
  6. return render_to_response('my_model_detail.html', {
  7. 'object': object,
  8. }, context_instance=RequestContext(request))

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 append ?edit to the page’s URL. This will make the frontend editor top banner appear, and will eventually require you to login.

If you need change ?edit to custom string (eq: ?admin_on) you may set CMS_TOOLBAR_URL__EDIT_ON variable in yours settings.py to "admin_on".

Also you may change ?edit_off or ?build to custom string with set CMS_TOOLBAR_URL__EDIT_OFF or CMS_TOOLBAR_URL__BUILD variables in yours settings.py.

Notice: when you changing CMS_TOOLBAR_URL__EDIT_ON or CMS_TOOLBAR_URL__EDIT_OFF or CMS_TOOLBAR_URL__BUILD please be careful because you may replace reserved strings in system (eq: ?page). We recommended you use unique strings for this option (eq: secret_admin or company_name).

You are now using the so-called frontend edit mode:

edit-banner

Once in Front-end editing mode, switch to Structure mode, and you should be able to see an outline of the placeholder, and a menu, allowing you to add plugins to them. The following screenshot shows a default selection of plugins in an empty placeholder.

frontend-placeholder-add-plugin

Adding the plugins automatically update the model content and they are rendered in realtime.

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

Permissions

To be able to edit placeholder user has to be staff member and either has to have edit permission on model that contains PlaceholderField or has to have edit permission on that specific object of that model.

Model permissions are usually added through default django auth application and its admin interface. On the other hand, object permission can be handled by writing a custom Auth Backend as described in django docs

For example, if there is a UserProfile model that contains placeholder field then custom backend can have following has_perm method that grants all rights to current user only on his 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