'content'
¶
Default: 60
Cache expiration (in seconds) for show_placeholder
and page_url
template tags.
Note
This settings was previously called CMS_CONTENT_CACHE_DURATION
This document refers to version 2.3.8
This document assumes you are familiar with Python and Django. It should outline the steps necessary for you to follow the Introductory Tutorial.
Note
When installing the django CMS using pip, Django, django-mptt django-classy-tags, django-sekizai, south and html5lib will be installed automatically.
Warning
The instructions here install certain packages, such as PIL, Django, South and django CMS globally, which is not recommended. We recommend you use virtualenv instead. If you choose to do so, install Django, django CMS and South inside a virtualenv.
If you’re using Ubuntu (tested with 10.10), the following should get you started:
sudo aptitude install python2.6 python-setuptools python-imaging
sudo easy_install pip
sudo pip install Django==1.4 django-cms south
Additionally, you need the Python driver for your selected database:
sudo aptitude python-psycopg2
or
sudo aptitude install python-mysql
This will install PIL and your database’s driver globally.
You have now everything that is needed for you to follow the Introductory Tutorial.
TODO (Should setup everything up to but not including “pip install django-cms” like the above)
TODO.
We recommend using PostgreSQL or MySQL with django CMS. Installing and maintaining database systems is outside the scope of this documentation, but is very well documented on the systems’ respective websites.
To use django CMS efficiently, we recommend:
Placeholder rescan is skipped when loading fixtures.
Fixed a bug when the Django setting USE_THOUSAND_SEPARATOR = True, which caused placeholders primary keys to be formatted according to locale, breaking frontend editing.
Warning
Upgrading from previous versions
2.3.7 now requires django-sekizai>=0.7
(up from 0.6.1
) due to a
cache-related fix backported from 2.4.
The correct django-sekizai
version should be automatically installed
(if not already present), but please do check when upgrading.
When a page is saved and cache is enabled, an explicit cache clear used to be called, causing performance issues when you have thousand of users on your website. This is no longer the case: cache is now versioned and as a result massive cache invalidation is not needed anymore
Backported from 2.4 a management command for fixing MPTT tree data.
The command can be run with:
manage.py cms fix-mptt
2.3.4 fixes a critical issue with WymEditor that prevented it from load it’s JavaScript assets correctly.
The Norwegian translations are now available as nb
, which is the new
(since 2003) official language code for Norwegian, replacing the older and
deprecated no
code.
If your site runs in Norwegian, you need to change your LANGUAGES
settings!
On Django 1.4, and with USE_TZ=True
the django CMS now uses timezone aware
date and time objects.
In earlier versions, publishing a page that has the same slug (URL) as another (published) page could lead to errors. Now, when a page which would have the same URL as another (published) page is published, the user is shown an error and they’re prompted to change the slug for the page.
The change form for pages would throw errors if the user editing the page does not have the permission to publish this page. This issue was resolved.
Further the page change form would not correctly pre-popluate the slug field if
DEBUG
was set to False
. Again, this issue is now resolved.
2.3.3 restores Python 2.5 suppport for the django CMS.
Python 2.5 support will be dropped in django CMS 2.4.
Google map plugin now supports width and height fields so that plugin size can be modified in the page admin or frontend editor.
Zoom level is now set via a select field which ensure only legal values are used.
Warning
Due to the above change, level field is now marked as NOT NULL, and a datamigration has been introduced to modify existing googlemap plugin instance to set the default value if level if is NULL.
In django CMS 2.3 we dropped support for Django 1.2. Django 1.3.1 is now the minimum required Django version. Django CMS 2.3 also introduces Django 1.4 support.
Thanks to the work by Andrew Schoen the page tree in the admin now loads lazily, significantly improving the performance of that view for large sites.
The toolbar JavaScript dependencies should now be properly isolated and no longer pollute the global JavaScript namespace.
The cancel button in plugin change forms no longer saves the changes, but actually cancels.
Tests can now be run using setup.py test
or runtests.py
(the latter
should be done in a virtualenv with the proper dependencies installed).
Check runtests.py -h
for options.
A serious bug where a text plugin with inline plugins would lose all the inline plugins when moved to a different placeholder has been fixed.
or
clause in the placeholder
tag now works correctly on non-cms
pages.PageSelectWidget
correctly orders pages again.span
tag).django-reversion
must now be at version 1.6django-sekizai
must be at least at version 0.6.1django-mptt
version 0.5.1 or 0.5.2 is requiredThis feature was deprecated in version 2.2 and removed in 2.3. Code like this will not work anymore:
plugin_pool.register_plugin([FooPlugin, BarPlugin])
Instead, use multiple calls to register_plugin
:
plugin_pool.register_plugin(FooPlugin)
plugin_pool.register_plugin(BarPlugin)
The CMS_FLAT_URLS
setting is deprecated and will be removed in version 2.4.
The moderation feature (CMS_MODERATOR = True
) will be deprecated in 2.4 and
replaced with a simpler way of handling unpublished changes.
django-mptt
now a proper dependency¶django-mptt is now used as a proper dependency and is no longer shipped with the django CMS. This solves the version conflict issues many people were experiencing when trying to use the django CMS together with other Django apps that require django-mptt. django CMS 2.2 requires django-mptt 0.5.1.
Warning
Please remove the old mptt
package from your Python site-packages
directory before upgrading. The setup.py
file will install the
django-mptt package as an external dependency!
The django CMS 2.2 supports both Django 1.2.5 and Django 1.3.
You can now give view permissions for django CMS pages to groups and users.
django-sekizai
instead of PluginMedia¶Due to the sorry state of the old plugin media framework, it has been dropped in favor of the more stable and more flexible django-sekizai, which is a new dependency for the django CMS 2.2.
The following methods and properties of cms.plugins_base.CMSPluginBase
are affected:
cms.plugins_base.CMSPluginBase.PluginMedia
cms.plugins_base.CMSPluginBase.pluginmedia
cms.plugins_base.CMSPluginBase.get_plugin_media()
Accessing those attributes or methods will raise a
cms.exceptions.Deprecated
error.
The cms.middleware.media.PlaceholderMediaMiddleware
middleware was also
removed in this process and is therefore no longer required. However you are now
required to have the 'sekizai.context_processors.sekizai'
context processor
in your TEMPLATE_CONTEXT_PROCESSORS
setting.
All templates in CMS_TEMPLATES
must at least contain the js
and
css
sekizai namespaces.
Please refer to the documentation on Handling media in custom CMS plugins and the django-sekizai documentation for more information.
The toolbar no longer hacks itself into responses in the middleware, but rather
has to be enabled explicitly using the {% cms_toolbar %}
template tag from
the cms_tags
template tag library in your templates. The template tag
should be placed somewhere within the body of the HTML (within <body>...</body>
).
This solves issues people were having with the toolbar showing up in places it shouldn’t have.
The static files (css/javascript/images) were moved from /media/
to
/static/
to work with the new django.contrib.staticfiles
app in Django
1.3. This means you will have to make sure you serve static files as well as
media files on your server.
Warning
If you use Django 1.2.x you will not have a django.contrib.staticfiles
app. Instead you need the django-staticfiles backport.
Upgrade both your version of django CMS and Django by running the following commands.
pip install --upgrade django-cms==2.2 django==1.3.1
If you are using django-reversion make sure to have at least version 1.4 installed
pip install --upgrade django-reversion==1.4
Also, make sure that django-mptt stays at a version compatible with django CMS
pip install --upgrade django-mptt==0.5.1
settings.py
¶The following changes will need to be made in your settings.py file:
ADMIN_MEDIA_PREFIX = '/static/admin'
STATIC_ROOT = os.path.join(PROJECT_PATH, 'static')
STATIC_URL = "/static/"
Note
These are not django CMS settings. Refer to the Django documentation on staticfiles for more information.
Note
Please make sure the static
subfolder exists in your
project and is writable.
Note
PROJECT_PATH is the absolute path to your project. See Installing and configuring django CMS in your Django project for instructions on how to set PROJECT_PATH.
Remove the following from TEMPLATE_CONTEXT_PROCESSORS
:
django.core.context_processors.auth
Add the following to TEMPLATE_CONTEXT_PROCESSORS
:
django.contrib.auth.context_processors.auth
django.core.context_processors.static
sekizai.context_processors.sekizai
Remove the following from MIDDLEWARE_CLASSES
:
cms.middleware.media.PlaceholderMediaMiddleware
Remove the following from INSTALLED_APPS
:
publisher
Add the following to INSTALLED_APPS
:
sekizai
django.contrib.staticfiles
Make sure to add sekizai tags and cms_toolbar
to your CMS templates.
Note
cms_toolbar
is only needed if you wish to use the front-end editing. See Backwards incompatible changes for more information
Here is a simple example for a base template called base.html
:
{% load cms_tags sekizai_tags %}
<html>
<head>
{% render_block "css" %}
</head>
<body>
{% cms_toolbar %}
{% placeholder base_content %}
{% block base_content%}{% endblock %}
{% render_block "js" %}
</body>
</html>
Run the following commands to upgrade your database
python manage.py syncdb
python manage.py migrate
Add the following to urls.py
to serve static media when developing:
if settings.DEBUG:
urlpatterns = patterns('',
url(r'^media/(?P<path>.*)$', 'django.views.static.serve',
{'document_root': settings.MEDIA_ROOT, 'show_indexes': True}),
url(r'', include('django.contrib.staticfiles.urls')),
) + urlpatterns
Also run this command to collect static files into your STATIC_ROOT
:
python manage.py collectstatic
This guide assumes your machine meets the requirements outlined in the Installation section of this documentation.
Should you run into trouble and can’t figure out how to solve it yourself, you
can get help from either our mailinglist or IRC channel #django-cms
on
the irc.freenode.net
network.
Gathering the requirements is a good start, but we now need to give the CMS a Django project to live in, and configure it.
The following assumes your project will be in ~/workspace/myproject/
.
Set up your Django project:
cd ~/workspace
django-admin.py startproject myproject
cd myproject
python manage.py runserver
Open 127.0.0.1:8000 in your browser. You should see a nice “It Worked” message from Django.
Open the file ~/workspace/myproject/settings.py
.
To make your life easier, add the following at the top of the file:
# -*- coding: utf-8 -*-
import os
gettext = lambda s: s
PROJECT_PATH = os.path.abspath(os.path.dirname(__file__))
Add the following apps to your INSTALLED_APPS
.
This includes django CMS itself as well as its dependenices and
other highly recommended applications/libraries:
'cms'
, django CMS itself'mptt'
, utilities for implementing a modified pre-order traversal tree'menus'
, helper for model independent hierarchical website navigation'south'
, intelligent schema and data migrations'sekizai'
, for javascript and css managementAlso add any (or all) of the following plugins, depending on your needs:
'cms.plugins.file'
'cms.plugins.flash'
'cms.plugins.googlemap'
'cms.plugins.link'
'cms.plugins.picture'
'cms.plugins.snippet'
'cms.plugins.teaser'
'cms.plugins.text'
'cms.plugins.video'
'cms.plugins.twitter'
Warning
Adding the 'cms.plugins.snippet'
plugin is a potential security hazard.
For more information, refer to Snippet.
The plugins are described in more detail in chapter Plugins reference. There are even more plugins available on the django CMS extensions page.
In addition, make sure you uncomment (enable) 'django.contrib.admin'
you may also wish to use django-filer and its components with the django CMS plugin
instead of the cms.plugins.file
, cms.plugins.picture
,
cms.plugins.teaser
and cms.plugins.video
core plugins. In this
case you should not add them to INSTALLED_APPS
but add the following
instead:
'filer'
'cmsplugin_filer_file'
'cmsplugin_filer_folder'
'cmsplugin_filer_image'
'cmsplugin_filer_teaser'
'cmsplugin_filer_video'
If you opt for the core plugins you should take care that directory to which
the CMS_PAGE_MEDIA_PATH
setting points (by default cms_page_media/
relative to MEDIA_ROOT
) is writable by the user under which Django
will be running. If you have opted for django-filer there is a similar requirement
for its configuration.
If you want versioning of your content you should also install django-reversion
and add it to INSTALLED_APPS
:
'reversion'
You need to add the django CMS middlewares to your MIDDLEWARE_CLASSES
at the right position:
MIDDLEWARE_CLASSES = (
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'cms.middleware.multilingual.MultilingualURLMiddleware',
'cms.middleware.page.CurrentPageMiddleware',
'cms.middleware.user.CurrentUserMiddleware',
'cms.middleware.toolbar.ToolbarMiddleware',
)
You need at least the following TEMPLATE_CONTEXT_PROCESSORS
:
TEMPLATE_CONTEXT_PROCESSORS = (
'django.contrib.auth.context_processors.auth',
'django.core.context_processors.i18n',
'django.core.context_processors.request',
'django.core.context_processors.media',
'django.core.context_processors.static',
'cms.context_processors.media',
'sekizai.context_processors.sekizai',
)
Note
This setting will be missing from automatically generated Django settings files, so you will have to add it.
Point your STATIC_ROOT
to where the static files should live
(that is, your images, CSS files, Javascript files, etc.):
STATIC_ROOT = os.path.join(PROJECT_PATH, "static")
STATIC_URL = "/static/"
For uploaded files, you will need to set up the MEDIA_ROOT
setting:
MEDIA_ROOT = os.path.join(PROJECT_PATH, "media")
MEDIA_URL = "/media/"
Note
Please make sure both the static
and media
subfolders exist in your
project and are writable.
Now add a little magic to the TEMPLATE_DIRS
section of the file:
TEMPLATE_DIRS = (
# The docs say it should be absolute path: PROJECT_PATH is precisely one.
# Life is wonderful!
os.path.join(PROJECT_PATH, "templates"),
)
Add at least one template to CMS_TEMPLATES
; for example:
CMS_TEMPLATES = (
('template_1.html', 'Template One'),
('template_2.html', 'Template Two'),
)
We will create the actual template files at a later step, don’t worry about it for now. Simply paste this code into your settings file.
Note
The templates you define in CMS_TEMPLATES
have to exist at runtime and
contain at least one {% placeholder <name> %}
template tag to be useful
for django CMS. For more details see Creating templates
The django CMS allows you to edit all languages for which Django has built in translations. Since these are numerous, we’ll limit it to English for now:
LANGUAGES = [
('en', 'English'),
]
Finally, set up the DATABASES
part of the file to reflect your
database deployment. If you just want to try out things locally, sqlite3 is the
easiest database to set up, however it should not be used in production. If you
still wish to use it for now, this is what your DATABASES
setting should look like:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(PROJECT_PATH, 'database.sqlite'),
}
}
You need to include the 'cms.urls'
urlpatterns at the end of your
urlpatterns. We suggest starting with the following urls.py
:
from django.conf.urls.defaults import *
from django.contrib import admin
from django.conf import settings
admin.autodiscover()
urlpatterns = patterns('',
(r'^admin/', include(admin.site.urls)),
url(r'^', include('cms.urls')),
)
if settings.DEBUG:
urlpatterns = patterns('',
url(r'^media/(?P<path>.*)$', 'django.views.static.serve',
{'document_root': settings.MEDIA_ROOT, 'show_indexes': True}),
url(r'', include('django.contrib.staticfiles.urls')),
) + urlpatterns
django CMS uses templates to define how a page should look and what parts of it are editable. Editable areas are called placeholders. These templates are standard Django templates and you may use them as described in the official documentation.
Templates you wish to use on your pages must be declared in the CMS_TEMPLATES
setting:
CMS_TEMPLATES = (
('template_1.html', 'Template One'),
('template_2.html', 'Template Two'),
)
If you have followed this tutorial from the beginning, this code should already be in your settings file.
Now, on with the actual template files!
Fire up your favorite editor and create a file called base.html
in a folder called templates
in your myproject directory.
Here is a simple example for a base template called base.html
:
{% load cms_tags sekizai_tags %}
<html>
<head>
{% render_block "css" %}
</head>
<body>
{% cms_toolbar %}
{% placeholder base_content %}
{% block base_content %}{% endblock %}
{% render_block "js" %}
</body>
</html>
Now, create a file called template_1.html
in the same directory. This will use
your base template, and add extra content to it:
{% extends "base.html" %}
{% load cms_tags %}
{% block base_content %}
{% placeholder template_1_content %}
{% endblock %}
When you set template_1.html
as a template on a page you will get two
placeholders to put plugins in. One is template_1_content
from the page
template template_1.html
and another is base_content
from the extended
base.html
.
When working with a lot of placeholders, make sure to give descriptive names to your placeholders so you can identify them more easily in the admin panel.
Now, feel free to experiment and make a template_2.html
file! If you don’t
feel creative, just copy template_1 and name the second placeholder something
like “template_2_content”.
The django CMS handles media files (css stylesheets and javascript files)
required by CMS plugins using django-sekizai. This requires you to define at
least two sekizai namespaces in your templates: js
and css
. You can do
so using the render_block
template tag from the sekizai_tags
template
tag libary. We highly recommended putting the {% render_block "css" %}
tag
as the last thing before the closing </head>
HTML tag and the
{% render_block "js" %}
tag as the last thing before the closing </body>
HTML tag.
This command depends on whether you upgrade your installation or do a fresh install. We recommend that you get familiar with the way South works, as it is a very powerful, easy and convenient tool. django CMS uses it extensively.
Run:
python manage.py syncdb --all
python manage.py migrate --fake
The first command will prompt you to create a super user. Choose ‘yes’ and enter appropriate values.
That should be it. Restart your development server using python manage.py runserver
and point a web browser to 127.0.0.1:8000 :you should get
the django CMS “It Worked” screen.
Head over to the admin panel <http://127.0.0.1:8000/admin/> and log in with the user you created during the database setup.
To deploy your django CMS project on a production webserver, please refer to the Django documentation.
That’s it. Now the best part: you can start using the CMS!
Run your server with python manage.py runserver
, then point a web browser to
127.0.0.1:8000/admin/ , and log in using the super
user credentials you defined when you ran syncdb
earlier.
Once in the admin part of your site, you should see something like the following:
Adding a page is as simple as clicking “Pages” in the admin view, then the “add page” button at the top right-hand corner of the screen.
This is where you select which template to use (remember, we created two), as well as pretty obvious things like which language the page is in (used for internationalisation), the page’s title, and the url slug it will use.
Hitting the “Save” button, unsurprisingly, saves the page. It will now display in the list of pages.
Congratulations! You now have a fully functional django CMS installation!
The following is a list of parameters that can be changed for each of your pages:
By default, pages are “invisible”. To let people access them you should mark them as “published”.
So far, our page doesn’t do much. Make sure it’s marked as “published”, then click on the page’s “edit” button.
Ignore most of the interface for now and click the “view on site” button at the top right-hand corner of the screen. As expected, your page is blank for the time being, since our template is a really minimal one.
Let’s get to it now then!
Press your browser’s back button, so as to see the page’s admin interface. If you followed
the tutorial so far, your template (template_1.html
) defines two placeholders.
The admin interfaces shows you theses placeholders as sub menus:
Scroll down the “Available plugins” drop-down list. This displays the plugins you
added to your INSTALLED_APPS
settings. Choose the “text” plugin in the drop-down,
then press the “Add” button.
The right part of the plugin area displays a rich text editor (TinyMCE).
In the editor, type in some text and then press the “Save” button.
Go back to your website using the top right-hand “View on site” button. That’s it!
Congratulations, you now have a fully functional CMS! Feel free to play around with the different plugins provided out of the box and to build great websites!
South is an incredible piece of software that lets you handle database migrations. This document is by no means meant to replace the excellent documentation available online, but rather to give a quick primer on why you should use South and how to get started quickly.
As always using Django and Python is a joy. Installing South is as simple as typing:
pip install South
Then, simply add south
to the list of INSTALLED_APPS
in your
settings.py
file.
For a very short crash course:
manage.py syncdb
command, simply run
manage.py schemamigration --initial <app name>
. This will create a new
migrations package, along with a new migration file (in the form of a python
script).manage.py migrate
. Your tables will be created
in the database and Django will work as usual.manage.py schemamigration --auto <app name>
to create a new migration
file. Next run manage.py migrate
to apply the newly created migration.Obviously, South is a very powerful tool and this simple crash course is only the very tip of the iceberg. Readers are highly encouraged to have a quick glance at the excellent official South documentation.
The django CMS has a lot of settings you can use to customize your installation so that it is exactly as you’d like it to be.
Default: ()
(Not a valid setting!)
A list of templates you can select for a page.
Example:
CMS_TEMPLATES = (
('base.html', gettext('default')),
('2col.html', gettext('2 Column')),
('3col.html', gettext('3 Column')),
('extra.html', gettext('Some extra fancy template')),
)
Note
All templates defined in CMS_TEMPLATES
must contain at least the
js
and css
sekizai namespaces, for more information, see
Static files handling with sekizai.
Warning
django CMS internally relies on a number of templates to function correctly.
These exist beneath cms
within the templates directory. As such, it
is highly recommended you avoid using the same directory name for your own
project templates.
Default: True
Optional Enables the inheritance of templates from parent pages.
If this is enabled, pages have the additional template option to inherit their template from the nearest ancestor. New pages default to this setting if the new page is not a root page.
Default: {}
Optional
Used to configure placeholders. If not given, all plugins are available in all placeholders.
Example:
CMS_PLACEHOLDER_CONF = {
'content': {
'plugins': ['TextPlugin', 'PicturePlugin'],
'text_only_plugins': ['LinkPlugin']
'extra_context': {"width":640},
'name':gettext("Content"),
},
'right-column': {
"plugins": ['TeaserPlugin', 'LinkPlugin'],
"extra_context": {"width":280},
'name':gettext("Right Column"),
'limits': {
'global': 2,
'TeaserPlugin': 1,
'LinkPlugin': 1,
},
},
'base.html content': {
"plugins": ['TextPlugin', 'PicturePlugin', 'TeaserPlugin']
},
}
You can combine template names and placeholder names to granularly define plugins, as shown above with ‘’base.html content’‘.
plugins
A list of plugins that can be added to this placeholder. If not supplied, all plugins can be selected.
text_only_plugins
A list of additional plugins available only in the TextPlugin, these plugins can’t be added directly to this placeholder.
extra_context
Extra context that plugins in this placeholder receive.
name
The name displayed in the Django admin. With the gettext stub, the name can be internationalized.
limits
Limit the number of plugins that can be placed inside this placeholder. Dictionary keys are plugin names and the values are their respective limits. Special case: “global” - Limit the absolute number of plugins in this placeholder regardless of type (takes precedence over the type-specific limits).
Default: []
A list of plugin context processors. Plugin context processors are callables that modify all plugins’ context before rendering. See Custom Plugins for more information.
Default: []
A list of plugin processors. Plugin processors are callables that modify all plugin’s output after rendering. See Custom Plugins for more information.
Default: ()
A list of import paths for cms.app_base.CMSApp
subclasses.
Defaults to an empty list which means CMS applications are auto-discovered in
all INSTALLED_APPS
by trying to import their cms_app
module.
If this setting is set, the auto-discovery is disabled.
Example:
CMS_APPHOOKS = (
'myapp.cms_app.MyApp',
'otherapp.cms_app.MyFancyApp',
'sampleapp.cms_app.SampleApp',
)
Default: True
If set to False
, frontend editing is not available for models using
cms.models.fields.PlaceholderField
.
The Wymeditor from cms.plugins.text
plugin can take the same
configuration as vanilla Wymeditor. Therefore you will need to learn
how to configure that. The best thing to do is to head
over to the Wymeditor examples page
in order to understand how Wymeditor works.
The cms.plugins.text
plugin exposes several variables named
WYM_* that correspond to the wym configuration. The simplest
way to get started with this is to go to cms/plugins/text/settings.py
and copy over the WYM_* variables and you will realize they
match one to one to Wymeditor’s.
Currently the following variables are available:
WYM_TOOLS
WYM_CONTAINERS
WYM_CLASSES
WYM_STYLES
WYM_STYLESHEET
Default: True
By default django CMS hides menu items that are not yet translated into the current language. With this setting set to False they will show up anyway.
Default: Value of LANGUAGES
Defines the languages available in django CMS.
Example:
CMS_LANGUAGES = (
('fr', gettext('French')),
('de', gettext('German')),
('en', gettext('English')),
)
Note
Make sure you only define languages which are also in LANGUAGES
.
Default: True
This will redirect the browser to the same page in another language if the page is not available in the current language.
Default: {}
Language fallback ordering for each language.
Example:
CMS_LANGUAGE_CONF = {
'de': ['en', 'fr'],
'en': ['de'],
}
Default: {}
If you have more than one site and CMS_LANGUAGES
differs between
the sites, you may want to fill this out so that when you switch between sites
in the admin you only get the languages available to that particular site.
Example:
CMS_SITE_LANGUAGES = {
1:['en','de'],
2:['en','fr'],
3:['en'],
}
Default: Value of CMS_LANGUAGES
A list of languages django CMS uses in the frontend. For example, if you decide you want to add a new language to your page but don’t want to show it to the world yet.
Example:
CMS_FRONTEND_LANGUAGES = ("de", "en", "pt-BR")
Default: MEDIA_ROOT
+ CMS_MEDIA_PATH
The path to the media root of the cms media files.
default: MEDIA_URL
+ CMS_MEDIA_PATH
The location of the media files that are located in cms/media/cms/
Default: 'cms_page_media/'
By default, django CMS creates a folder called cms_page_media
in your
static files folder where all uploaded media files are stored. The media files
are stored in subfolders numbered with the id of the page.
You should take care that the directory to which it points is writable by the user under which Django will be running.
Default: True
This adds a new field “url overwrite” to the “advanced settings” tab of your page. With this field you can overwrite the whole relative url of the page.
Default: False
This adds a new “redirect” field to the “advanced settings” tab of the page.
You can set a url here to which visitors will be redirected when the page is accessed.
Note: Don’t use this too much. django.contrib.redirects
is much more
flexible, handy, and is designed exactly for this purpose.
Deprecated since version 2.4: CMS_FLAT_URLS
will be removed in 2.4.
Default: False
If this is enabled the slugs are not nested in the urls.
So a page with a “world” slug will have a “/world” url, even it is a child of the “hello” page. If disabled the page would have the url: “/hello/world/”
Default: False
This adds a new “softroot” field to the “advanced settings” tab of the page. If a page is marked as softroot the menu will only display items until it finds the softroot.
If you have a huge site you can easily partition the menu with this.
Default: False
If this is enabled you get 3 new models in Admin:
In the edit-view of the pages you can now assign users to pages and grant them permissions. In the global permissions you can set the permissions for users globally.
If a user has the right to create new users he can now do so in the “Users - page”. But he will only see the users he created. The users he created can also only inherit the rights he has. So if he only has been granted the right to edit a certain page all users he creates can, in turn, only edit this page. Naturally he can limit the rights of the users he creates even further, allowing them to see only a subset of the pages to which he is allowed access.
Default: all
Decides if pages without any view restrictions are public by default or staff
only. Possible values are all
and staff
.
Default: False
If set to True
, gives you a new “moderation” column in the tree view.
You can select to moderate pages or whole trees. If a page is under moderation you will receive an email if somebody changes a page and you will be asked to approve the changes. Only after you approve the changes will they be updated on the “live” site. If you make changes to a page you moderate yourself, you will need to approve it anyway. This allows you to change a lot of pages for a new version of the site, for example, and go live with all the changes at the same time.
Note
When switching this value to True
on an existing site, you have
to run the cms moderator on
command to make the required database
changes.
Default: False
for both
This adds two new DateTimeField
fields in the
“advanced settings” tab of the page. With this option you can limit the time a
page is published.
Default: False
This adds a new “SEO Fields” fieldset to the page admin. You can set the Page Title, Meta Keywords and Meta Description in there.
To access these fields in the template use:
{% load cms_tags %}
<head>
<title>{% page_attribute page_title %}</title>
<meta name="description" content="{% page_attribute meta_description %}"/>
<meta name="keywords" content="{% page_attribute meta_keywords %}"/>
...
...
</head>
This dictionary carries the various cache duration settings.
'content'
¶Default: 60
Cache expiration (in seconds) for show_placeholder
and page_url
template tags.
Note
This settings was previously called CMS_CONTENT_CACHE_DURATION
Default: cms-
The CMS will prepend the value associated with this key to every cache access (set and get). This is useful when you have several django CMS installations, and you don’t want them to share cache objects.
Example:
CMS_CACHE_PREFIX = 'mysite-live'
Note
Django 1.3 introduced a site-wide cache key prefix. See Django’s own docs on cache key prefixing
Allows you to upload a file. A filetype icon will be assigned based on the file extension.
For installation be sure you have the following in the INSTALLED_APPS
setting in your project’s settings.py
file:
INSTALLED_APPS = (
# ...
'cms.plugins.file',
# ...
)
You should take care that the directory defined by the configuration setting
CMS_PAGE_MEDIA_PATH
(by default cms_page_media/
relative to
MEDIA_ROOT
) is writable by the user under which django will be
running.
You might consider using django-filer with django CMS plugin and its
cmsplugin_filer_file
component instead.
Warning
The builtin file plugin only works with local storages. If you need more advanced solutions, please look at alternative file plugins for the django CMS, such as django-filer.
Allows you to upload and display a Flash SWF file on your page.
For installation be sure you have the following in the
INSTALLED_APPS
setting in your project’s settings.py
file:
INSTALLED_APPS = (
# ...
'cms.plugins.flash',
# ...
)
Displays a map of an address on your page.
Both address and coordinates are supported to center the map; zoom level and route planner can be set when adding/editing plugin in the admin.
New in version 2.3.2: width/height parameter has been added, so it’s no longer required to set plugin container size in CSS or template.
Changed in version 2.3.2: Zoom level is set via a select field which ensure only legal values are used.
Note
Due to the above change, level field is now marked as NOT NULL, and a datamigration has been introduced to modify existing googlemap plugin instance to set the default value if level if is NULL.
For installation be sure you have the following in the INSTALLED_APPS
setting in your project’s settings.py
file:
INSTALLED_APPS = (
# ...
'cms.plugins.googlemap',
# ...
)
Displays a link to an arbitrary URL or to a page. If a page is moved the URL will still be correct.
For installation be sure to have the following in the INSTALLED_APPS
setting in your project’s settings.py
file:
INSTALLED_APPS = (
# ...
'cms.plugins.link',
# ...
)
Note
As of version 2.2, the link plugin no longer verifies the existence of link targets.
Displays a picture in a page.
For installation be sure you have the following in the INSTALLED_APPS
setting in your project’s settings.py
file:
INSTALLED_APPS = (
# ...
'cms.plugins.picture',
# ...
)
There are several solutions for Python and Django out there to automatically resize your pictures, you can find some on Django Packages and compare them there.
In your project template directory create a folder called cms/plugins
and
in it create a file called picture.html
. Here is an example
picture.html
template using easy-thumbnails:
{% load thumbnail %}
{% if link %}<a href="{{ link }}">{% endif %}
{% if placeholder == "content" %}
<img src="{% thumbnail picture.image 300x600 %}"{% if picture.alt %} alt="{{ picture.alt }}"{% endif %} />
{% else %}
{% if placeholder == "teaser" %}
<img src="{% thumbnail picture.image 150x150 %}"{% if picture.alt %} alt="{{ picture.alt }}"{% endif %} />
{% endif %}
{% endif %}
{% if link %}</a>{% endif %}
In this template the picture is scaled differently based on which placeholder it was placed in.
You should take care that the directory defined by the configuration setting
CMS_PAGE_MEDIA_PATH
(by default cms_page_media/
relative to
MEDIA_ROOT
) is writable by the user under which django will be
running.
Note
In order to improve clarity, some Picture fields have been omitted in the example template code.
Note
For more advanced use cases where you would like to upload your media
to a central location, consider using django-filer with
django CMS plugin and its cmsplugin_filer_image
component
instead.
Renders an HTML snippet from an HTML file in your templates directories or a snippet given via direct input.
For installation be sure you have the following in the INSTALLED_APPS
setting in your project’s settings.py
file:
INSTALLED_APPS = (
# ...
'cms.plugins.snippet',
# ...
)
Note
This plugin should mainly be used during development to quickly test HTML snippets.
Warning
This plugin is a potential security hazard, since it allows admins to place custom JavaScript on pages. This may allow administrators with the right to add snippets to elevate their privileges to superusers. This plugin should only be used during the initial development phase for rapid prototyping and should be disabled on production sites.
Displays text. If plugins are text-enabled they can be placed inside the text-flow. At this moment the following core plugins are text-enabled:
cms.plugins.link
cms.plugins.picture
cms.plugins.file
cms.plugins.snippet
The current editor is Wymeditor. If you want to
use TinyMce you need to install django-tinymce. If tinymce
is in your
INSTALLED_APPS
it will be automatically enabled. If you have tinymce
installed but don’t want to use it in the cms put the following in your
settings.py
:
CMS_USE_TINYMCE = False
Note
When using django-tinymce, you also need to configure it. See the django-tinymce docs for more information.
For installation be sure you have the following in your project’s
INSTALLED_APPS
setting:
INSTALLED_APPS = (
# ...
'cms.plugins.text',
# ...
)
Plays Video Files or Youtube / Vimeo Videos. Uses the OSFlashVideoPlayer. When uploading videos use either .flv files or h264 encoded video files.
For installation be sure you have the following in your project’s
INSTALLED_APPS
setting:
INSTALLED_APPS = (
# ...
'cms.plugins.video',
# ...
)
There are some settings you can set in your settings.py to overwrite some default behavior:
VIDEO_AUTOPLAY
((default: False
)VIDEO_AUTOHIDE
(default: False
)VIDEO_FULLSCREEN
(default: True
)VIDEO_LOOP
(default: False
)VIDEO_AUTOPLAY
(default: False
)VIDEO_BG_COLOR
(default: "000000"
)VIDEO_TEXT_COLOR
(default: "FFFFFF"
)VIDEO_SEEKBAR_COLOR
(default: "13ABEC"
)VIDEO_SEEKBARBG_COLOR
(default: "333333"
)VIDEO_LOADINGBAR_COLOR
(default: "828282"
)VIDEO_BUTTON_OUT_COLOR
(default: "333333"
)VIDEO_BUTTON_OVER_COLOR
(default: "000000"
)VIDEO_BUTTON_HIGHLIGHT_COLOR
(default: "FFFFFF"
)You should take care that the directory defined by the configuration setting
CMS_PAGE_MEDIA_PATH
(by default cms_page_media/
relative to
MEDIA_ROOT
) is writable by the user under which django will be
running.
Note
For more advanced use cases where you would like to upload your media
to a central location, consider using django-filer with
django CMS plugin and its cmsplugin_filer_video
component
instead.
Display’s a number of a twitter user’s latest posts.
For installation be sure you have the following in your project’s
INSTALLED_APPS
setting:
INSTALLED_APPS = (
# ...
'cms.plugins.twitter',
# ...
)
Note
Since avatars are not guaranteed to be available over SSL (HTTPS), by default the Twitter plugin does not use avatars on secure sites.
Displays all plugins of another page or another language. Great if you always need the same plugins on a lot of pages.
For installation be sure you have the following in your project’s
INSTALLED_APPS
setting:
INSTALLED_APPS = (
# ...
'cms.plugins.inherit',
# ...
)
Warning
The inherit plugin is currently the only core-plugin which cannot be used in non-cms placeholders.
After upgrading to a new version with an existing database, you encounter something like:
Caught MultipleObjectsReturned while rendering: get() returned more than one CacheKey – it returned 12! Lookup parameters were {‘key’: ‘cms-menu_nodes_en_1_1_user’, ‘language’: ‘en’, ‘site’: 1L}
What has happened is that your database contains some old cache data in the menus_cachekey table. Just delete all those entries.
The multilingual URL middleware adds a language prefix to every URL.
Example:
/de/account/login/
/fr/account/login/
It also adds this prefix automatically to every href
and form
tag.
To install it, include
'cms.middleware.multilingual.MultilingualURLMiddleware'
in your project’s
MIDDLEWARE_CLASSES
setting.
Note
This middleware must be put before cms.middleware.page.CurrentPageMiddleware
Example:
MIDDLEWARE_CLASSES = (
...
'cms.middleware.multilingual.MultilingualURLMiddleware',
'cms.middleware.user.CurrentUserMiddleware',
'cms.middleware.page.CurrentPageMiddleware',
'cms.middleware.toolbar.ToolbarMiddleware'
...
)
The language_chooser
template tag will display a language chooser for the
current page. You can modify the template in menu/language_chooser.html
or
provide your own template if necessary.
Example:
{% load menu_tags %}
{% language_chooser "myapp/language_chooser.html" %}
If the current URL is not handled by the CMS and you have some i18n slugs in the
URL you may use the menus.utils.set_language_changer()
function in the
view that handles the current URL.
In the models of the current object add an optional language parameter to the
get_absolute_url()
method:
from django.utils.translation import get_language
def get_absolute_url(self, language=None):
if not language:
language = get_language()
return reverse("product_view", args=[self.get_slug(language=language)])
In the view pass the get_absolute_url()
method to the
set_language_changer()
function:
from menus.utils import set_language_changer
def get_product(request, slug):
item = get_object_or_404(Product, slug=slug, published=True)
set_language_changer(request, item.get_absolute_url)
# ...
This allows the language chooser to have another URL than the current one.
If the current URL is not handled by the CMS and no
set_language_changer()
function is provided it will take the
exact same URL as the current one and will only change the language prefix.
For class-based generic views set_language_changer()
can be
used as follows:
from menus.utils import set_language_changer
class ProductDetailView(DetailView):
model = Product
def get_context_data(self, **kwargs):
context = super(ProductDetailView, self).get_context_data(**kwargs)
set_language_changer(self.request, self.object.get_absolute_url)
return context
For the language chooser to work the
cms.middleware.multilingual.MultilingualURLMiddleware
must be enabled.
If the URLs of your views don’t actually change besides the language prefix,
you can use the menus.utils.simple_language_changer()
view decorator,
instead of manually using set_language_changer()
:
from menus.utils import simple_language_changer
@simple_language_changer
def get_prodcut(request, slug):
# ...
This template tag returns the URL of the current page in another language.
Example:
{% page_language_url "de" %}
If you put CMS_HIDE_UNTRANSLATED
to False
in your
settings.py
all pages will be displayed in all languages even if they are
not translated yet.
If CMS_HIDE_UNTRANSLATED
is True
in your settings.py
and you are on a page that doesn’t yet have an English translation and you view the
German version then the language chooser will redirect to /
. The same goes
for URLs that are not handled by the CMS and display a language chooser.
Sitemaps are XML files used by Google to index your website by using their Webmaster Tools and telling them the location of your sitemap.
The CMSSitemap
will create a sitemap with all the published pages of
your CMS
- Add
django.contrib.sitemaps
to your project’sINSTALLED_APPS
setting.- Add
from cms.sitemaps import CMSSitemap
to the top of your mainurls.py
.- Add
url(r'^sitemap\.xml$', 'django.contrib.sitemaps.views.sitemap', {'sitemaps': {'cmspages': CMSSitemap}}),
to your urlpatterns.
More information about django.contrib.sitemaps
can be found in the official
Django documentation.
To use any of the following templatetags you first need to load them at the top of your template:
{% load cms_tags menu_tags %}
Changed in version 2.1: The placeholder name became case sensitive.
The placeholder
templatetag defines a placeholder on a page. All
placeholders in a template will be auto-detected and can be filled with
plugins when editing a page that is using said template. When rendering, the
content of these plugins will appear where the placeholder
tag was.
Example:
{% placeholder "content" %}
If you want additional content to be displayed in case the placeholder is
empty, use the or
argument and an additional {% endplaceholder %}
closing tag. Everything between {% placeholder "..." or %}
and {%
endplaceholder %}
is rendered in the event that the placeholder has no plugins or
the plugins do not generate any output.
Example:
{% placeholder "content" or %}There is no content.{% endplaceholder %}
If you want to add extra variables to the context of the placeholder, you
should use Django’s with
tag. For instance, if you want to resize images
from your templates according to a context variable called width
, you can
pass it as follows:
{% with 320 as width %}{% placeholder "content" %}{% endwith %}
If you want the placeholder to inherit the content of a placeholder with the
same name on parent pages, simply pass the inherit
argument:
{% placeholder "content" inherit %}
This will walk up the page tree up until the root page and will show the first placeholder it can find with content.
It’s also possible to combine this with the or
argument to show an
ultimate fallback if the placeholder and none of the placeholders on parent
pages have plugins that generate content:
{% placeholder "content" inherit or %}There is no spoon.{% endplaceholder %}
See also the CMS_PLACEHOLDER_CONF
setting where you can also add extra
context variables and change some other placeholder behavior.
Displays a specific placeholder from a given page. This is useful if you want to have some more or less static content that is shared among many pages, such as a footer.
Arguments:
placeholder_name
page_lookup
(see Page Lookup for more information)language
(optional)site
(optional)Examples:
{% show_placeholder "footer" "footer_container_page" %}
{% show_placeholder "content" request.current_page.parent_id %}
{% show_placeholder "teaser" request.current_page.get_root %}
The page_lookup
argument, passed to several templatetags to retrieve a
page, can be of any of the following types:
str
: interpreted as the reverse_id
field of the desired page, which
can be set in the “Advanced” section when editing a page.int
: interpreted as the primary key (pk
field) of the desired pagedict
: a dictionary containing keyword arguments to find the desired page
(for instance: {'pk': 1}
)Page
: you can also pass a page object directly, in which case there will
be no database lookup.If you know the exact page you are referring to, it is a good idea to use a
reverse_id
(a string used to uniquely name a page) rather than a
hard-coded numeric ID in your template. For example, you might have a help
page that you want to link to or display parts of on all pages. To do this,
you would first open the help page in the admin interface and enter an ID
(such as help
) under the ‘Advanced’ tab of the form. Then you could use
that reverse_id
with the appropriate templatetags:
{% show_placeholder "right-column" "help" %}
<a href="{% page_url "help" %}">Help page</a>
If you are referring to a page relative to the current page, you’ll probably have to use a numeric page ID or a page object. For instance, if you want the content of the parent page to display on the current page, you can use:
{% show_placeholder "content" request.current_page.parent_id %}
Or, suppose you have a placeholder called teaser
on a page that, unless a
content editor has filled it with content specific to the current page, should
inherit the content of its root-level ancestor:
{% placeholder "teaser" or %}
{% show_placeholder "teaser" request.current_page.get_root %}
{% endplaceholder %}
The same as show_placeholder
, but the placeholder contents will not be
cached.
Arguments:
placeholder_name
page_lookup
(see Page Lookup for more information)language
(optional)site
(optional)Example:
{% show_uncached_placeholder "footer" "footer_container_page" %}
Displays the URL of a page in the current language.
Arguments:
page_lookup
(see Page Lookup for more information)Example:
<a href="{% page_url "help" %}">Help page</a>
<a href="{% page_url request.current_page.parent %}">Parent page</a>
This templatetag is used to display an attribute of the current page in the current language.
Arguments:
attribute_name
page_lookup
(optional; see Page Lookup for more
information)Possible values for attribute_name
are: "title"
, "menu_title"
,
"page_title"
, "slug"
, "meta_description"
, "meta_keywords"
(note that you can also supply that argument without quotes, but this is
deprecated because the argument might also be a template variable).
Example:
{% page_attribute "page_title" %}
If you supply the optional page_lookup
argument, you will get the page
attribute from the page found by that argument.
Example:
{% page_attribute "page_title" "my_page_reverse_id" %}
{% page_attribute "page_title" request.current_page.parent_id %}
{% page_attribute "slug" request.current_page.get_root %}
New in version 2.3.2: This template tag supports the as
argument. With this you can assign the result
of the template tag to a new variable that you can use elsewhere in the template.
Example:
{% page_attribute "page_title" as title %}
<title>{{ title }}</title>
It even can be used in combination with the page_lookup
argument.
Example:
{% page_attribute "page_title" "my_page_reverse_id" as title %}
<a href="/mypage/">{{ title }}</a>
Renders the breadcrumb navigation of the current page.
The template for the HTML can be found at cms/breadcrumb.html
:
{% show_breadcrumb %}
Or with a custom template and only display level 2 or higher:
{% show_breadcrumb 2 "myapp/breadcrumb.html" %}
Usually, only pages visible in the navigation are shown in the breadcrumb. To include all pages in the breadcrumb, write:
{% show_breadcrumb 0 "cms/breadcrumb.html" 0 %}
If the current URL is not handled by the CMS or by a navigation extender, the current menu node can not be determined. In this case you may need to provide your own breadcrumb via the template. This is mostly needed for pages like login, logout and third-party apps. This can easily be accomplished by a block you overwrite in your templates.
For example in your base.html:
<ul>
{% block breadcrumb %}
{% show_breadcrumb %}
{% endblock %}
<ul>
And then in your app template:
{% block breadcrumb %}
<li><a href="/">home</a></li>
<li>My current page</li>
{% endblock %}
Returns the url of the current page in an other language:
{% page_language_url de %}
{% page_language_url fr %}
{% page_language_url en %}
If the current url has no cms-page and is handled by a navigation extender and the url changes based on the language, you will need to set a language_changer function with the set_language_changer function in cms.utils.
For more information, see Internationalization.
The language_chooser
template tag will display a language chooser for the
current page. You can modify the template in menu/language_chooser.html
or
provide your own template if necessary.
Example:
{% language_chooser %}
or with custom template:
{% language_chooser "myapp/language_chooser.html" %}
The language_chooser has three different modes in which it will display the
languages you can choose from: “raw” (default), “native”, “current” and “short”.
It can be passed as the last argument to the language_chooser tag
as a string.
In “raw” mode, the language will be displayed like its verbose name in the
settings. In “native” mode the languages are displayed in their actual language
(eg. German will be displayed “Deutsch”, Japanese as “日本語” etc). In “current”
mode the languages are translated into the current language the user is seeing
the site in (eg. if the site is displayed in German, Japanese will be displayed
as “Japanisch”). “Short” mode takes the language code (eg. “en”) to display.
If the current url has no cms-page and is handled by a navigation extender and the url changes based on the language, you will need to set a language_changer function with the set_language_changer function in menus.utils.
For more information, see Internationalization.
The cms_toolbar
templatetag will add the required css and javascript to the
sekizai blocks in the base template. The templatetag has to be placed after the
<body>
tag and before any {% cms_placeholder %}
occurrences within your HTML.
Example:
<body>
{% cms_toolbar %}
{% placeholder "home" %}
...
You can invoke the django CMS command line interface using the cms
Django
command:
python manage.py cms
cms list
¶The list
command is used to display information about your installation.
It has two subcommands:
cms list plugins
lists all plugins that are used in your project.cms list apphooks
lists all apphooks that are used in your project.cms uninstall
¶The uninstall
subcommand can be used to make uninstalling a CMS
Plugin or an apphook easier.
It has two subcommands:
cms uninstall plugins <plugin name> [<plugin name 2> [...]]
uninstalls
one or several plugins by removing them from all pages where they are
used. Note that the plugin name should be the name of the class that is
registered in the django CMS. If you are unsure about the plugin name, use
the cms list to see a list of installed plugins.cms uninstall apphooks <apphook name> [<apphook name 2> [...]]
uninstalls
one or several apphooks by removing them from all pages where they are
used. Note that the apphook name should be the name of the class that is
registered in the django CMS. If you are unsure about the apphook name, use
the cms list to see a list of installed apphooks.Warning
The uninstall command permanently deletes data from your database. You should make a backup of your database before using them!
cms moderator
¶If you turn CMS_MODERATOR
to True
on an existing project, you
should use the cms moderator on
command to make the required changes in the
database, otherwise you will have problems with invisible pages.
Warning
This command alters data in your database. You should make a backup of your database before using it!
cms mptt-repair
¶Occasionally, the MPTT structure in which pages and plugins are held can accumulate small errors. These are typically the result of failed operations or large and complex restructurings of the tree (perhaps even cosmic rays, planetary alignment or other mysterious conditions).
Usually you won’t even notice them, and they won’t affect the operation of the system, but when you run into trouble it’s useful to be able to rebuild the tree - it’s also useful to rebuild it as part of preventative maintenance.
Warning
This command alters data in your database. You should make a backup of your database before using it!
In django-cms you can set two types of permissions:
To enable these features, settings.py
requires:
CMS_PERMISSION = True
View restrictions can be set-up from the View restrictions formset on any cms page. Once a page has at least one view restriction installed, only users with granted access will be able to see that page. Mind that this restriction is for viewing the page as an end-user (front-end view), not viewing the page in the admin interface!
View restrictions are also controlled by the CMS_PUBLIC_FOR
setting. Possible values are all
and staff
.
This setting decides if pages without any view restrictions are:
After setting CMS_PERMISSION = True
you will have three new models in the admin index:
Using Users (page) you can easily add users with permissions over cms pages.
You would be able to create an user with the same set of permissions using the usual Auth.User model, but using Users (page) is more convenient.
A new user created using Users (page) with given page add/edit/delete rights will not be able to make any changes to pages straight away. The user must first be assigned to a set of pages over which he may exercise these rights. This is done using the Page permissions formset on any page or by using Pages global Permissions.
The Page permission formset has multiple checkboxes defining different permissions: can edit, can add, can delete, can change advanced settings, can publish, can move and can change permission. These define what kind of actions the user/group can do on the pages on which the permissions are being granted through the Grant on drop-down.
Can change permission refers to whether the user can change the permissions of his subordinate users. Bob is the subordinate of Alice if one of:
Note: Mind that even though a new user has permissions to change a page, that doesn’t give him permissions to add a plugin within that page.
In order to be able to add/change/delete plugins on any page, you will need to go through the usual Auth.User model and give the new user permissions to each plugin you want him to have access to.
Example: if you want the new user to be able to use the text plugin, you will need to give him the following rights: text | text | Can add text
, text | text | Can change text
, text | text | Can delete text
.
Using the Pages global permissions model you can give a set of permissions to all pages in a set of sites.
From this point onwards, this tutorial assumes you have done the
Django Tutorial and will show you how to integrate the tutorial’s poll app into the
django CMS. Hereafter, if a poll app is mentioned, we are referring to the one you get
after completing the Django Tutorial.
Also, make sure the poll app is in your INSTALLED_APPS
.
We assume your main urls.py
looks something like this:
from django.conf.urls.defaults import *
from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns('',
(r'^admin/', include(admin.site.urls)),
(r'^polls/', include('polls.urls')),
(r'^', include('cms.urls')),
)
A Plugin is a small bit of content that you can place on your pages.
For our polling app we would like to have a small poll plugin which shows a poll and lets the user vote.
In your poll application’s models.py
add the following:
from cms.models import CMSPlugin
class PollPlugin(CMSPlugin):
poll = models.ForeignKey('polls.Poll', related_name='plugins')
def __unicode__(self):
return self.poll.question
Note
django CMS plugins must inherit from cms.models.CMSPlugin
(or a subclass thereof) and not
models.Model
.
Run manage.py syncdb
to create the database tables for this model or see
Using South with django CMS to see how to do it using South.
Now create a file cms_plugins.py
in the same folder your models.py
is
in. After having followed the Django Tutorial and adding this file your polls
app folder should look like this:
polls/
__init__.py
cms_plugins.py
models.py
tests.py
views.py
The plugin class is responsible for providing the django CMS with the necessary information to render your Plugin.
For our poll plugin, write the following plugin class:
from cms.plugin_base import CMSPluginBase
from cms.plugin_pool import plugin_pool
from polls.models import PollPlugin as PollPluginModel
from django.utils.translation import ugettext as _
class PollPlugin(CMSPluginBase):
model = PollPluginModel # Model where data about this plugin is saved
name = _("Poll Plugin") # Name of the plugin
render_template = "polls/plugin.html" # template to render the plugin with
def render(self, context, instance, placeholder):
context.update({'instance':instance})
return context
plugin_pool.register_plugin(PollPlugin) # register the plugin
Note
All plugin classes must inherit from
cms.plugin_base.CMSPluginBase
and must register themselves
with the cms.plugin_pool.plugin_pool
.
You probably noticed the
render_template
attribute in the above plugin class. In order for our plugin to work, that template must
exist and is responsible for rendering the plugin.
The template should look something like this:
<h1>{{ instance.poll.question }}</h1>
<form action="{% url polls.views.vote instance.poll.id %}" method="post">
{% csrf_token %}
{% for choice in instance.poll.choice_set.all %}
<input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}" />
<label for="choice{{ forloop.counter }}">{{ choice.choice }}</label><br />
{% endfor %}
<input type="submit" value="Vote" />
</form>
Note
We don’t show the errors here, because when submitting the form you’re taken off this page to the actual voting page.
Right now, external apps are statically hooked into the main urls.py
. This
is not the preferred approach in the django CMS. Ideally you attach your apps to CMS
pages.
For that purpose you write a CMSApp
. That is
just a small class telling the CMS how to include that app.
CMS Apps live in a file called cms_app.py
, so go ahead and create it to
make your polls app look like this:
polls/
__init__.py
cms_app.py
cms_plugins.py
models.py
tests.py
views.py
In this file, write:
from cms.app_base import CMSApp
from cms.apphook_pool import apphook_pool
from django.utils.translation import ugettext_lazy as _
class PollsApp(CMSApp):
name = _("Poll App") # give your app a name, this is required
urls = ["polls.urls"] # link your app to url configuration(s)
apphook_pool.register(PollsApp) # register your app
Now remove the inclusion of the polls urls in your main urls.py
so it looks
like this:
from django.conf.urls.defaults import *
from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns('',
(r'^admin/', include(admin.site.urls)),
(r'^', include('cms.urls')),
)
Now open your admin in your browser and edit a CMS Page. Open the ‘Advanced Settings’ tab and choose ‘Polls App’ for your ‘Application’.
Unfortunately, for these changes to take effect, you will have to restart your server. So do that and afterwards if you navigate to that CMS Page, you will see your polls application.
CMS Plugins are reusable content publishers that can be inserted into django CMS pages (or indeed into any content that uses django CMS placeholders). They enable the publishing of information automatically, without further intervention.
This means that your published web content, whatever it is, is kept up-to-date at all times.
It’s like magic, but quicker.
Unless you’re lucky enough to discover that your needs can be met by the built-in plugins, or by the many available 3rd-party plugins, you’ll have to write your own custom CMS Plugin. Don’t worry though - writing a CMS Plugin is rather simple.
A plugin is the most convenient way to integrate content from another Django app into a django CMS page.
For example, suppose you’re developing a site for a record company in django CMS. You might like to have a “Latest releases” box on your site’s home page.
Of course, you could every so often edit that page and update the information. However, a sensible record company will manage its catalogue in Django too, which means Django already knows what this week’s new releases are.
This is an excellent opportunity to make use of that information to make your life easier - all you need to do is create a django CMS plugin that you can insert into your home page, and leave it to do the work of publishing information about the latest releases for you.
Plugins are reusable. Perhaps your record company is producing a series of reissues of seminal Swiss punk records; on your site’s page about the series, you could insert the same plugin, configured a little differently, that will publish information about recent new releases in that series.
A django CMS plugin is fundamentally composed of three things.
These correspond to the familiar Model-View-Template scheme:
And so to build your plugin, you’ll make it from:
cms.models.pluginmodel.CMSPlugin
to
store the configuration for your plugin instancescms.plugin_base.CMSPluginBase
that defines
the operating logic of your plugincms.plugin_base.CMSPluginBase
¶cms.plugin_base.CMSPluginBase
is actually a subclass of django.contrib.admin.options.ModelAdmin
.
It is its render()
method that is the plugin’s view function.
The plugin model, the subclass of cms.models.pluginmodel.CMSPlugin
,
is actually optional.
You could have a plugin that doesn’t need to be configured, because it only ever does one thing.
For example, you could have a plugin that only publishes information about the top-selling record of the past seven days. Obviously, this wouldn’t be very flexible - you wouldn’t be able to use the same plugin for the best-selling release of the last month instead.
Usually, you find that it is useful to be able to configure your plugin, and this will require a model.
You may use python manage.py startapp
to set up the basic layout for you
plugin app. Alternatively, just add a file called cms_plugins.py
to an
existing Django application.
In there, you place your plugins. For our example, include the following code:
from cms.plugin_base import CMSPluginBase
from cms.plugin_pool import plugin_pool
from cms.models.pluginmodel import CMSPlugin
from django.utils.translation import ugettext_lazy as _
class HelloPlugin(CMSPluginBase):
model = CMSPlugin
name = _("Hello Plugin")
render_template = "hello_plugin.html"
def render(self, context, instance, placeholder):
return context
plugin_pool.register_plugin(HelloPlugin)
Now we’re almost done. All that’s left is to add the template. Add the
following into the root template directory in a file called
hello_plugin.html
:
<h1>Hello {% if request.user.is_authenticated %}{{ request.user.first_name }} {{ request.user.last_name}}{% else %}Guest{% endif %}</h1>
This plugin will now greet the users on your website either by their name if they’re logged in, or as Guest if they’re not.
Now let’s take a closer look at what we did there. The cms_plugins.py
files
are where you should define your subclasses of
cms.plugin_base.CMSPluginBase
, these classes define the different
plugins.
There are three required attributes on those classes:
model
: The model you wish to use for storing information about this plugin.
If you do not require any special information, for example configuration, to
be stored for your plugins, you can simply use
cms.models.pluginmodel.CMSPlugin
(We’ll look at that model more
closely in a bit).name
: The name of your plugin as displayed in the admin. It is generally
good practice to mark this string as translatable using
django.utils.translation.ugettext_lazy()
, however this is optional.render_template
: The template to render this plugin with.In addition to those three attributes, you must also define a
render()
method on your subclasses. It is specifically this render
method that is the view for your plugin.
The render method takes three arguments:
context
: The context with which the page is rendered.instance
: The instance of your plugin that is rendered.placeholder
: The name of the placeholder that is rendered.This method must return a dictionary or an instance of
django.template.Context
, which will be used as context to render the
plugin template.
In many cases, you want to store configuration for your plugin instances. For example, if you have a plugin that shows the latest blog posts, you might want to be able to choose the amount of entries shown. Another example would be a gallery plugin where you want to choose the pictures to show for the plugin.
To do so, you create a Django model by subclassing
cms.models.pluginmodel.CMSPlugin
in the models.py
of an installed
application.
Let’s improve our HelloPlugin
from above by making its fallback name for
non-authenticated users configurable.
In our models.py
we add the following:
from cms.models.pluginmodel import CMSPlugin
from django.db import models
class Hello(CMSPlugin):
guest_name = models.CharField(max_length=50, default='Guest')
If you followed the Django tutorial, this shouldn’t look too new to you. The
only difference to normal models is that you subclass
cms.models.pluginmodel.CMSPlugin
rather than
django.db.models.base.Model
.
Now we need to change our plugin definition to use this model, so our new
cms_plugins.py
looks like this:
from cms.plugin_base import CMSPluginBase
from cms.plugin_pool import plugin_pool
from django.utils.translation import ugettext_lazy as _
from models import Hello
class HelloPlugin(CMSPluginBase):
model = Hello
name = _("Hello Plugin")
render_template = "hello_plugin.html"
def render(self, context, instance, placeholder):
context['instance'] = instance
return context
plugin_pool.register_plugin(HelloPlugin)
We changed the model
attribute to point to our newly created Hello
model and pass the model instance to the context.
As a last step, we have to update our template to make use of this new configuration:
<h1>Hello {% if request.user.is_authenticated %}{{ request.user.first_name }} {{ request.user.last_name}}{% else %}{{ instance.guest_name }}{% endif %}</h1>
The only thing we changed there is that we use the template variable
{{ instance.guest_name }}
instead of the hardcoded Guest
string in the
else clause.
Warning
cms.models.pluginmodel.CMSPlugin
subclasses cannot be further
subclassed at the moment. In order to make your plugin models reusable,
please use abstract base models.
Warning
You cannot name your model fields the same as any installed plugins
lower-cased model name, due to the implicit one-to-one relation Django uses
for subclassed models. If you use all core plugins, this includes:
file
, flash
, googlemap
, link
, picture
, snippetptr
,
teaser
, twittersearch
, twitterrecententries
and video
.
Additionally, it is recommended that you avoid using page
as a model
field, as it is declared as a property of cms.models.pluginmodel.CMSPlugin
,
and your plugin will not work as intended in the administration without
further work.
If your custom plugin has foreign key or many-to-many relations you are responsible for copying those if necessary whenever the CMS copies the plugin.
To do this you can implement a method called
cms.models.pluginmodel.CMSPlugin.copy_relations()
on your plugin
model which gets the old instance of the plugin as an argument.
Let’s assume this is your plugin:
class ArticlePluginModel(CMSPlugin):
title = models.CharField(max_length=50)
sections = models.ManyToManyField(Section)
def __unicode__(self):
return self.title
Now when the plugin gets copied, you want to make sure the sections stay:
def copy_relations(self, oldinstance):
self.sections = oldinstance.sections.all()
Your full model now:
class ArticlePluginModel(CMSPlugin):
title = models.CharField(max_length=50)
sections = models.ManyToManyField(Section)
def __unicode__(self):
return self.title
def copy_relations(self, oldinstance):
self.sections = oldinstance.sections.all()
Since cms.plugin_base.CMSPluginBase
extends
django.contrib.admin.options.ModelAdmin
, you can customize the form
for your plugins just as you would customize your admin interfaces.
Note
If you want to overwrite the form be sure to extend from
admin/cms/page/plugin_change_form.html
to have a unified look across the
plugins and to have the preview functionality automatically installed.
If your plugin depends on certain media files, javascript or stylesheets, you
can include them from your plugin template using django-sekizai. Your CMS
templates are always enforced to have the css
and js
sekizai namespaces,
therefore those should be used to include the respective files. For more
information about django-sekizai, please refer to the
django-sekizai documentation.
To fully harness the power of django-sekizai, it is helpful to have a consistent style on how to use it. Here is a set of conventions that should be followed (but don’t necessarily need to be):
addtoblock
. Always include one external CSS or JS file per
addtoblock
or one snippet per addtoblock
. This is needed so
django-sekizai properly detects duplicate files.addtoblock
tag and the HTML tags.A good example:
{% load sekizai_tags %}
{% addtoblock "js" %}<script type="text/javascript" src="{{ MEDIA_URL }}myplugin/js/myjsfile.js"></script>{% endaddtoblock %}
{% addtoblock "js" %}<script type="text/javascript" src="{{ MEDIA_URL }}myplugin/js/myotherfile.js"></script>{% endaddtoblock %}
{% addtoblock "css" %}<link rel="stylesheet" type="text/css" href="{{ MEDIA_URL }}myplugin/css/astylesheet.css"></script>{% endaddtoblock %}
{% addtoblock "js" %}
<script type="text/javascript">
$(document).ready(function(){
doSomething();
});
</script>
{% endaddtoblock %}
A bad example:
{% load sekizai_tags %}
{% addtoblock "js" %}<script type="text/javascript" src="{{ MEDIA_URL }}myplugin/js/myjsfile.js"></script>
<script type="text/javascript" src="{{ MEDIA_URL }}myplugin/js/myotherfile.js"></script>{% endaddtoblock %}
{% addtoblock "css" %}
<link rel="stylesheet" type="text/css" href="{{ MEDIA_URL }}myplugin/css/astylesheet.css"></script>
{% endaddtoblock %}
{% addtoblock "js" %}<script type="text/javascript">
$(document).ready(function(){
doSomething();
});
</script>{% endaddtoblock %}
Plugin context processors are callables that modify all plugins’ context before
rendering. They are enabled using the CMS_PLUGIN_CONTEXT_PROCESSORS
setting.
A plugin context processor takes 2 arguments:
instance
: The instance of the plugin modelplaceholder
: The instance of the placeholder this plugin appears in.The return value should be a dictionary containing any variables to be added to the context.
Example:
def add_verbose_name(instance, placeholder):
'''
This plugin context processor adds the plugin model's verbose_name to context.
'''
return {'verbose_name': instance._meta.verbose_name}
Plugin processors are callables that modify all plugins’ output after rendering.
They are enabled using the CMS_PLUGIN_PROCESSORS
setting.
A plugin processor takes 4 arguments:
instance
: The instance of the plugin modelplaceholder
: The instance of the placeholder this plugin appears in.rendered_content
: A string containing the rendered content of the plugin.original_context
: The original context for the template used to render
the plugin.Note
Plugin processors are also applied to plugins embedded in Text
plugins (and any custom plugin allowing nested plugins). Depending on
what your processor does, this might break the output. For example,
if your processor wraps the output in a div
tag, you might end up
having div
tags inside of p
tags, which is invalid. You can
prevent such cases by returning rendered_content
unchanged if
instance._render_meta.text_enabled
is True
, which is the case
when rendering an embedded plugin.
Suppose you want to wrap each plugin in the main placeholder in a colored box but it would be too complicated to edit each individual plugin’s template:
In your settings.py
:
CMS_PLUGIN_PROCESSORS = (
'yourapp.cms_plugin_processors.wrap_in_colored_box',
)
In your yourapp.cms_plugin_processors.py
:
def wrap_in_colored_box(instance, placeholder, rendered_content, original_context):
'''
This plugin processor wraps each plugin's output in a colored box if it is in the "main" placeholder.
'''
# Plugins not in the main placeholder should remain unchanged
# Plugins embedded in Text should remain unchanged in order not to break output
if placeholder.slot != 'main' or (instance._render_meta.text_enabled and instance.parent):
return rendered_content
else:
from django.template import Context, Template
# For simplicity's sake, construct the template from a string:
t = Template('<div style="border: 10px {{ border_color }} solid; background: {{ background_color }};">{{ content|safe }}</div>')
# Prepare that template's context:
c = Context({
'content': rendered_content,
# Some plugin models might allow you to customize the colors,
# for others, use default colors:
'background_color': instance.background_color if hasattr(instance, 'background_color') else 'lightyellow',
'border_color': instance.border_color if hasattr(instance, 'border_color') else 'lightblue',
})
# Finally, render the content through that template, and return the output
return t.render(c)
It is pretty easy to integrate your own Django applications with django CMS. You have 5 ways of integrating your app:
Menus
Statically extend the menu entries
Attach Menus
Attach your menu to a page.
App-Hooks
Attach whole apps with optional menu to a page.
Navigation Modifiers
Modify the whole menu tree
Custom Plugins
Display your models / content in cms pages
With App-Hooks you can attach whole Django applications to pages. For example you have a news app and you want it attached to your news page.
To create an apphook create a cms_app.py
in your application. And in it
write the following:
from cms.app_base import CMSApp
from cms.apphook_pool import apphook_pool
from django.utils.translation import ugettext_lazy as _
class MyApphook(CMSApp):
name = _("My Apphook")
urls = ["myapp.urls"]
apphook_pool.register(MyApphook)
Replace myapp.urls
with the path to your applications urls.py
.
Now edit a page and open the advanced settings tab. Select your new apphook under “Application”. Save the page.
Warning
If you are on a multi-threaded server (mostly all webservers, except the dev-server): Restart the server because the URLs are cached by Django and in a multi-threaded environment we don’t know which caches are cleared yet.
Note
If at some point you want to remove this apphook after deleting the cms_app.py
there is a cms management command called uninstall apphooks
that removes the specified apphook(s) from all pages by name.
eg. manage.py cms uninstall apphooks MyApphook
.
To find all names for uninstallable apphooks there is a command for this as well
manage.py cms list apphooks
.
If you attached the app to a page with the url /hello/world/
and the app has
a urls.py that looks like this:
from django.conf.urls.defaults import *
urlpatterns = patterns('sampleapp.views',
url(r'^$', 'main_view', name='app_main'),
url(r'^sublevel/$', 'sample_view', name='app_sublevel'),
)
The main_view
should now be available at /hello/world/
and the
sample_view
has the url /hello/world/sublevel/
.
Note
All views that are attached like this must return a
RequestContext
instance instead of the
default Context
instance.
An additional feature of apphooks is that if you use the
cms.middleware.multilingual.MultilingualURLMiddleware
all apphook urls
are language namespaced.
What this means:
To reverse the first url from above you would use something like this in your template:
{% url app_main %}
If you want to access the same url but in a different language use a language namespace:
{% url de:app_main %}
{% url en:app_main %}
{% url fr:app_main %}
If you want to add a menu to that page as well that may represent some views in your app add it to your apphook like this:
from myapp.menu import MyAppMenu
class MyApphook(CMSApp):
name = _("My Apphook")
urls = ["myapp.urls"]
menus = [MyAppMenu]
apphook_pool.register(MyApphook)
For an example if your app has a Category
model and you want this
category model to be displayed in the menu when you attach the app to a page.
We assume the following model:
from django.db import models
from django.core.urlresolvers import reverse
import mptt
class Category(models.Model):
parent = models.ForeignKey('self', blank=True, null=True)
name = models.CharField(max_length=20)
def __unicode__(self):
return self.name
def get_absolute_url(self):
return reverse('category_view', args=[self.pk])
try:
mptt.register(Category)
except mptt.AlreadyRegistered:
pass
We would now create a menu out of these categories:
from menus.base import NavigationNode
from menus.menu_pool import menu_pool
from django.utils.translation import ugettext_lazy as _
from cms.menu_bases import CMSAttachMenu
from myapp.models import Category
class CategoryMenu(CMSAttachMenu):
name = _("test menu")
def get_nodes(self, request):
nodes = []
for category in Category.objects.all().order_by("tree_id", "lft"):
node = NavigationNode(
category.name,
category.get_absolute_url(),
category.pk,
category.parent_id
)
nodes.append(node)
return nodes
menu_pool.register_menu(CategoryMenu)
If you add this menu now to your app-hook:
from myapp.menus import CategoryMenu
class MyApphook(CMSApp):
name = _("My Apphook")
urls = ["myapp.urls"]
menus = [MyAppMenu, CategoryMenu]
You get the static entries of MyAppMenu
and the dynamic entries of
CategoryMenu
both attached to the same page.
If you want to display content of your apps on other pages custom plugins are a great way to accomplish that. For example, if you have a news app and you want to display the top 10 news entries on your homepage, a custom plugin is the way to go.
For a detailed explanation on how to write custom plugins please head over to the Custom Plugins section.
Python APIs for creating CMS contents. This is done in cms.api
and not
on the models and managers, because the direct API via models and managers is
slightly counterintuitive for developers. Also the functions defined in this
module do sanity checks on arguments.
Warning
None of the functions in this module does any security or permission checks. They verify their input values to be sane wherever possible, however permission checks should be implemented manually before calling any of these functions.
cms.api.
VISIBILITY_ALL
¶Used for the limit_menu_visibility
keyword argument to
create_page()
. Does not limit menu visibility.
cms.api.
VISIBILITY_USERS
¶Used for the limit_menu_visibility
keyword argument to
create_page()
. Limits menu visibility to authenticated users.
cms.api.
VISIBILITY_STAFF
¶Used for the limit_menu_visibility
keyword argument to
create_page()
. Limits menu visibility to staff users.
cms.api.
create_page
(title, template, language, menu_title=None, slug=None, apphook=None, redirect=None, meta_description=None, meta_keywords=None, created_by='python-api', parent=None, publication_date=None, publication_end_date=None, in_navigation=False, soft_root=False, reverse_id=None, navigation_extenders=None, published=False, site=None, login_required=False, limit_visibility_in_menu=VISIBILITY_ALL, position="last-child")¶Creates a cms.models.pagemodel.Page
instance and returns it. Also
creates a cms.models.titlemodel.Title
instance for the specified
language.
Parameters: |
|
---|
cms.api.
create_title
(language, title, page, menu_title=None, slug=None, apphook=None, redirect=None, meta_description=None, meta_keywords=None, parent=None)¶Creates a cms.models.titlemodel.Title
instance and returns it.
Parameters: |
|
---|
cms.api.
add_plugin
(placeholder, plugin_type, language, position='last-child', **data)¶Adds a plugin to a placeholder and returns it.
Parameters: |
|
---|
cms.api.
create_page_user
(created_by, user, can_add_page=True, can_change_page=True, can_delete_page=True, can_recover_page=True, can_add_pageuser=True, can_change_pageuser=True, can_delete_pageuser=True, can_add_pagepermission=True, can_change_pagepermission=True, can_delete_pagepermission=True, grant_all=False)¶Creates a page user for the user provided and returns that page user.
Parameters: |
|
---|
cms.api.
assign_user_to_page
(page, user, grant_on=ACCESS_PAGE_AND_DESCENDANTS, can_add=False, can_change=False, can_delete=False, can_change_advanced_settings=False, can_publish=False, can_change_permissions=False, can_move_page=False, can_moderate=False, grant_all=False)¶Assigns a user to a page and gives them some permissions. Returns the
cms.models.permissionmodels.PagePermission
object that gets
created.
Parameters: |
|
---|
cms.api.
publish_page
(page, user, approve=False)¶Publishes a page and optionally approves that publication.
Parameters: |
|
---|
cms.api.
approve_page
(page, user)¶Approves a page.
Parameters: |
|
---|
Create a page called 'My Page
using the template 'my_template.html'
and
add a text plugin with the content 'hello world'
. This is done in English:
from cms.api import create_page, add_plugin
page = create_page('My Page', 'my_template.html', 'en')
placeholder = page.placeholders.get(slot='body')
add_plugin(placeholder, 'TextPlugin', 'en', body='hello world')
cms.plugin_base.
CMSPluginBase
¶Inherits django.contrib.admin.options.ModelAdmin
.
admin_preview
¶Defaults to True
, if False
no preview is done in the admin.
change_form_template
¶Custom template to use to render the form to edit this plugin.
form
¶Custom form class to be used to edit this plugin.
model
¶Is the CMSPlugin
model we created earlier. If you don’t need
model because you just want to display some template logic, use
CMSPlugin
from cms.models
as the model instead.
module
¶Will group the plugin in the plugin editor. If module is None
,
plugin is grouped “Generic” group.
name
¶Will be displayed in the plugin editor.
render_plugin
¶If set to False
, this plugin will not be rendered at all.
render_template
¶Will be rendered with the context returned by the render function.
text_enabled
¶Whether this plugin can be used in text plugins or not.
icon_alt
(instance)¶Returns the alt text for the icon used in text plugins, see
icon_src()
.
icon_src
(instance)¶Returns the url to the icon to be used for the given instance when that instance is used inside a text plugin.
render
(context, instance, placeholder)¶This method returns the context to be used to render the template
specified in render_template
.
Parameters: |
|
---|---|
Return type: |
|
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 either the normal Django admin interface or the so called frontend editing.
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
, including frontend editing.
You need to define a PlaceholderField
on the model you would like to
use:
from django.db import models
from cms.models.fields import PlaceholderField
class MyModel(models.Model):
# your fields
my_placeholder = PlaceholderField('placeholder_name')
# your methods
The PlaceholderField
takes a string as its first
argument which will be used to configure which plugins can be used in this
placeholder. The configuration is the same as for placeholders in the CMS.
Warning
For security reasons the related_name for a
PlaceholderField
may not be surpressed using
'+'
to allow the cms to check permissions properly. Attempting to do
so will raise a ValueError
.
If you install this model in the admin application, you have to use
PlaceholderAdmin
instead of
ModelAdmin
so the interface renders
correctly:
from django.contrib import admin
from cms.admin.placeholderadmin import PlaceholderAdmin
from myapp.models import MyModel
admin.site.register(MyModel, PlaceholderAdmin)
Now to render the placeholder in a template you use the
render_placeholder
tag from the
placeholder_tags
template tag library:
{% load placeholder_tags %}
{% render_placeholder mymodel_instance.my_placeholder "640" %}
The render_placeholder
tag takes a
PlaceholderField
instance as its first argument and
optionally accepts a width parameter as its second argument for context sensitive
plugins. 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
:
from django.shortcuts import get_object_or_404, render_to_response
from django.template.context import RequestContext
from myapp.models import MyModel
def my_model_detail(request, id):
object = get_object_or_404(MyModel, id=id)
return render_to_response('my_model_detail.html', {
'object': object,
}, context_instance=RequestContext(request))
There are two ways to add or edit content to a placeholder, the front-end admin view and the back-end view.
Probably the simplest way to add content to a placeholder, simply visit the
page displaying your model (where you put the render_placeholder
tag),
then append ?edit
to the page’s URL. This will make a top banner appear,
and after switching the “Edit mode” button to “on”, the banner will prompt you
for your username and password (the user should be allowed to edit the page,
obviously).
You are now using the so-called front-end edit mode:
Once in Front-end editing mode, your placeholders should display a menu, allowing you to add plugins to them. The following screen shot shows a default selection of plugins in an empty placeholder.
Plugins are rendered at once, so you can get an idea how it will look in fine. However, to view the final look of a plugin simply leave edit mode by clicking the “Edit mode” button in the banner again.
There are some hard restrictions if you want to add custom fieldsets to an
admin page with at least one PlaceholderField
:
PlaceholderField
must be in its own
fieldset
, one
PlaceholderField
per fieldset.'plugin-holder'
and
'plugin-holder-nopage'
For powerful full-text search within the django CMS, we suggest using Haystack together with django-cms-search.
cms.models.fields.
PageField
¶This is a foreign key field to the cms.models.pagemodel.Page
model
that defaults to the cms.forms.fields.PageSelectFormField
form
field when rendered in forms. It has the same API as the
django.db.models.fields.related.ForeignKey
but does not require
the othermodel
argument.
cms.forms.fields.
PageSelectFormField
¶Behaves like a django.forms.models.ModelChoiceField
field for the
cms.models.pagemodel.Page
model, but displays itself as a split
field with a select dropdown for the site and one for the page. It also
indents the page names based on what level they’re on, so that the page
select dropdown is easier to use. This takes the same arguments as
django.forms.models.ModelChoiceField
.
This section doesn’t explain how to do anything, but explains and analyses some key concepts in django CMS.
django CMS has a sophisticated multilingual capability. It is able to serve content in multiple languages, with fallbacks into other languages where translations have not been provided. It also has the facility for the user to set the preferred language and so on.
django CMS determines the user’s language based on (in order of priority):
Once it has identified a user’s language, it will try to accommodate it using the languages set in CMS_LANGUAGES
.
If CMS_LANGUAGE_FALLBACK
is True, and if the user’s preferred
language is not available for that content, it will use the fallbacks
specified for the language in CMS_LANGUAGE_CONF
.
It helps to understand how the system behaves by stepping through some actual examples.
CMS_HIDE_UNTRANSLATED
is False/some/page
/some/page
/some/page
(i.e. no redirection has taken place)/it/some/other/page
that is available in Italian/it/some/other/page
/it/some/other/page
/en/some/other/page
(i.e. it has redirected)/en/some/other/page
are prepended with /en
- even if they are available in Italian/some/page
or any other page without using a language prefix, you’ll get content in English - even though your browser wants ItalianAs soon as you visit any page with a /en
prefix in the path, the system
sets a django_language cookie
(which will expire when the browser is quit)
with content “en”.
From now on, the system thinks that you want English content.
Note that this could have happened:
Note
This is an issue the developers are aware of and are working towards fixing.
Your language cookie should only ever get set or changed if:
If your cookie contains a particualar language (say, “it”):
/it
content where available, and fallback where notWhen visiting a page only available in English:
Like every open-source project, django CMS is always looking for motivated individuals to contribute to its source code. However, to ensure the highest code quality and keep the repository nice and tidy, everybody has to follow a few rules (nothing major, I promise :) )
People interested in developing for the django CMS should join the django-cms-developers mailing list as well as heading over to #django-cms on the freenode IRC network for help and to discuss the development.
You may also be interested in following @djangocmsstatus on twitter to get the GitHub commits as well as the hudson build reports. There is also a @djangocms account for less technical announcements.
Here’s what the contribution process looks like, in a bullet-points fashion, and only for the stuff we host on GitHub:
If you’re interested in developing a new feature for the CMS, it is recommended that you first discuss it on the django-cms-developers mailing list so as not to do any work that will not get merged in anyway.
Since we’re hosted on GitHub, django CMS uses git as a version control system.
The GitHub help is very well written and will get you started on using git and GitHub in a jiffy. It is an invaluable resource for newbies and old timers alike.
We try to conform to PEP8 as much as possible. A few highlights:
This is how you fix a bug or add a feature:
Having a wide and comprehensive library of unit-tests and integration tests is of exceeding importance. Contributing tests is widely regarded as a very prestigious contribution (you’re making everybody’s future work much easier by doing so). Good karma for you. Cookie points. Maybe even a beer if we meet in person :)
Generally tests should be:
In a similar way to code, pull requests will be reviewed before pulling (obviously), and we encourage discussion via code review (everybody learns something this way) or IRC discussions.
To run the tests simply execute python setup.py test
from your shell.
Perhaps considered “boring” by hard-core coders, documentation is sometimes even more important than code! This is what brings fresh blood to a project, and serves as a reference for old timers. On top of this, documentation is the one area where less technical people can help most - you just need to write semi-decent English. People need to understand you. We don’t care about style or correctness.
Documentation should be:
Pulling of documentation is pretty fast and painless. Usually somebody goes over your text and merges it, since there are no “breaks” and that GitHub parses rst files automagically it’s really convenient to work with.
Also, contributing to the documentation will earn you great respect from the core developers. You get good karma just like a test contributor, but you get double cookie points. Seriously. You rock.
We use Python documentation conventions for section marking:
#
with overline, for parts*
with overline, for chapters=
, for sections-
, for subsections^
, for subsubsections"
, for paragraphsFor translators we have a Transifex account where you can translate the .po files and don’t need to install git or mercurial to be able to contribute. All changes there will be automatically sent to the project.
Top translations django-cms core: