1. Extending the CMS: Examples

    We assume your main urls.py looks something like this:

    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:

    1. from cms.models import CMSPlugin
    2. class PollPlugin(CMSPlugin):
    3. poll = models.ForeignKey('polls.Poll', related_name='plugins')
    4. def __unicode__(self):
    5. 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 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 and adding this file your polls app folder should look like this:

    1. polls/
    2. __init__.py
    3. cms_plugins.py
    4. models.py
    5. tests.py
    6. views.py

    The plugin class is responsible for providing the django CMS with the necessary information to render your 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 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:

    1. <h1>{{ instance.poll.question }}</h1>
    2. <form action="{% url polls.views.vote instance.poll.id %}" method="post">
    3. {% csrf_token %}
    4. {% for choice in instance.poll.choice_set.all %}
    5. <input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}" />
    6. <label for="choice{{ forloop.counter }}">{{ choice.choice }}</label><br />
    7. {% endfor %}
    8. <input type="submit" value="Vote" />
    9. </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:

    1. polls/
    2. __init__.py
    3. cms_app.py
    4. cms_plugins.py
    5. models.py
    6. tests.py
    7. views.py

    Now remove the inclusion of the polls urls in your main urls.py so it looks like this:

    1. from django.conf.urls.defaults import *
    2. from django.contrib import admin
    3. admin.autodiscover()
    4. (r'^admin/', include(admin.site.urls)),
    5. (r'^', include('cms.urls')),
    6. )

    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.

    Now you might have noticed that the menu tree stops at the CMS Page you created in the last step. So let’s create a menu that shows a node for each poll you have active.

    For this we need a file called menu.py. Create it and ensure your polls app looks like this:

    1. polls/
    2. __init__.py
    3. cms_app.py
    4. cms_plugins.py
    5. menu.py
    6. models.py
    7. tests.py
    8. views.py

    In your menu.py write:

    At this point this menu alone doesn’t do a whole lot. We have to attach it to the Apphook first.

    So open your cms_apps.py and write:

    1. from cms.app_base import CMSApp
    2. from cms.apphook_pool import apphook_pool
    3. from polls.menu import PollsMenu
    4. from django.utils.translation import ugettext_lazy as _
    5. class PollsApp(CMSApp):
    6. name = _("Poll App")
    7. urls = ["polls.urls"]
    8. menus = [PollsMenu] # attach a CMSAttachMenu to this apphook.