Permalink
Browse files

Improved Page and Title extension documentation (#5845)

* improved Page example
* corrected Title example so it actually works properly
* removed broken example from cms.toolbar.ExtensionToolbar comments
bonus: removed out-of-date note about redo/undo from documentation home page

Fixes #5092
Fixes #5083
  • Loading branch information...
1 parent fac5767 commit 580d06e0ad4ce329a9143b95fddb62010046dd24 @evildmp evildmp committed on GitHub Jan 11, 2017
Showing with 127 additions and 83 deletions.
  1. +0 −37 cms/extensions/toolbar.py
  2. +116 −43 docs/how_to/extending_page_title.rst
  3. +0 −2 docs/index.rst
  4. +5 −1 docs/reference/pages.rst
  5. +6 −0 docs/reference/titles.rst
@@ -9,43 +9,6 @@
class ExtensionToolbar(CMSToolbar):
- """
- ExtensionToolbar provides utility functions to handle much of the boilerplate involved in creating a toolbar for
- PageExtension and TitleExtension.
-
- The basic implementation of an extension toolbar using this class is::
-
- @toolbar_pool.register
- class SampleExtension(ExtensionToolbar):
- model = ExtModel # The PageExtension / TitleExtension you are working with
-
- def populate(self):
- current_page_menu = self._setup_extension_toolbar()
- if current_page_menu:
- position = 0
- page_extension, url = self.get_page_extension_admin()
- if url:
- current_page_menu.add_modal_item('Item label', url=url,
- disabled=not self.toolbar.edit_mode,
- position=position)
-
- For TitleExtension use ``get_title_extension_admin`` and cycle on the resulting title extensions and urls
-
- @toolbar_pool.register
- class SampleExtension(ExtensionToolbar):
- model = ExtModel # The PageExtension / TitleExtension you are working with
-
- def populate(self):
- current_page_menu = self._setup_extension_toolbar()
- if current_page_menu:
- position = 0
- urls = self.get_title_extension_admin()
- for title_extension, url in urls:
- current_page_menu.add_modal_item('Item label', url=url,
- disabled=not self.toolbar.edit_mode,
- position=position)
-
- """
model = None
page = None
@@ -1,29 +1,24 @@
#################################
-Extending the page & title models
+Extending the Page & Title models
#################################
-.. versionadded:: 3.0
-
-You can extend the page and title models with your own fields (e.g. adding
-an icon for every page) by using the extension models:
-``cms.extensions.PageExtension`` and ``cms.extensions.TitleExtension``,
-respectively.
+You can extend the :class:`cms.models.Page` and :class:`cms.models.Title` models with your own fields (e.g. adding an
+icon for every page) by using the extension models: ``cms.extensions.PageExtension`` and
+``cms.extensions.TitleExtension``, respectively.
************************
Title vs Page extensions
************************
The difference between a **page extension** and a **title extension** is related to the difference
-between the ``Page`` and ``Title`` models.
+between the :class:`cms.models.Page` and :class:`cms.models.Title` models.
-Titles support pages by providing a storage mechanism, amongst other things, for language-specific
-properties of ``Pages``. So, if you find that you need to extend the page model in a
-language-specific manner - for example, if you need to create language-specific keywords for each
-language of your pages - then you may need to use a ``TitleExtension``.
+* ``PageExtension``: use to add fields that should have **the same values** for the different language versions of a
+ page - for example, an icon.
+* ``TitleExtension``: use to add fields that should have **language-specific values** for different language versions
+ of a page - for example, keywords.
-On the other hand if the extension you'd like to create is the same for all of the different
-languages of the page, then you may be fine using a ``PageExtension``.
***************************
Implement a basic extension
@@ -35,13 +30,15 @@ Three basic steps are required:
* add the extension *admin*
* add a toolbar menu item for the extension
+
+Page model extension example
+============================
+
The model
-=========
+---------
-To add a field to the page model, create a class that inherits from
-``cms.extensions.PageExtension``. Make sure to import the
-``cms.extensions.PageExtension`` model. Your class should live in one of your
-apps' ``models.py`` (or module).
+To add a field to the Page model, create a class that inherits from ``cms.extensions.PageExtension``. Your class should
+live in one of your applications' ``models.py`` (or module).
.. note::
@@ -55,21 +52,21 @@ Finally, you'll need to register the model using ``extension_pool``.
Here's a simple example which adds an ``icon`` field to the page::
from django.db import models
-
from cms.extensions import PageExtension
from cms.extensions.extension_pool import extension_pool
class IconExtension(PageExtension):
image = models.ImageField(upload_to='icons')
+
extension_pool.register(IconExtension)
Of course, you will need to make and run a migration for this new model.
The admin
-=========
+---------
To make your extension editable, you must first create an admin class that
sub-classes ``cms.extensions.PageExtensionAdmin``. This admin handles page
@@ -99,9 +96,6 @@ Since PageExtensionAdmin inherits from ``ModelAdmin``, you'll be able to use the
normal set of Django ``ModelAdmin`` properties appropriate to your
needs.
-Once you've registered your admin class, a new model will appear in the top-
-level admin list.
-
.. note::
Note that the field that holds the relationship between the extension and a
@@ -110,15 +104,18 @@ level admin list.
The toolbar item
-================
+----------------
You'll also want to make your model editable from the cms toolbar in order to
associate each instance of the extension model with a page.
To add toolbar items for your extension create a file named ``cms_toolbars.py``
in one of your apps, and add the relevant menu entries for the extension on each page.
-Here's a simple version for our example::
+Here's a simple version for our example. This example adds a node to the existing *Page* menu, called *Page icon*. When
+selected, it will open a modal dialog in which the *Page icon* field can be edited.
+
+::
from cms.toolbar_pool import toolbar_pool
from cms.extensions.toolbar import ExtensionToolbar
@@ -134,37 +131,113 @@ Here's a simple version for our example::
def populate(self):
# setup the extension toolbar with permissions and sanity checks
current_page_menu = self._setup_extension_toolbar()
+
# if it's all ok
if current_page_menu:
# retrieves the instance of the current extension (if any) and the toolbar item URL
page_extension, url = self.get_page_extension_admin()
if url:
- # adds a toolbar item
+ # adds a toolbar item in position 0 (at the top of the menu)
current_page_menu.add_modal_item(_('Page Icon'), url=url,
- disabled=not self.toolbar.edit_mode)
+ disabled=not self.toolbar.edit_mode, position=0)
-.. note::
- For a title extension, the ``populate()`` method above would need to loop over the titles for
- the page::
+Title model extension example
+=============================
+
+In this example, we'll create a ``Rating`` extension field, that can be applied to each ``Title``, in other words, to
+each language version of each ``Page``.
+
+.. note::
+
+ Please refer to the more detailed discussion above of the Page model extension example, and in particular to the
+ special **notes**.
+
+
+The model
+---------
+
+::
+
+ from django.db import models
+ from cms.extensions import TitleExtension
+ from cms.extensions.extension_pool import extension_pool
+
+
+ class RatingExtension(TitleExtension):
+ rating = models.IntegerField()
+
+
+ extension_pool.register(RatingExtension)
+
+
+The admin
+---------
+
+::
+
+ from django.contrib import admin
+ from cms.extensions import TitleExtensionAdmin
+ from .models import RatingExtension
+
+
+ class RatingExtensionAdmin(TitleExtensionAdmin):
+ pass
+
+
+ admin.site.register(RatingExtension, RatingExtensionAdmin)
+
+
+The toolbar item
+----------------
+
+In this example, we need to loop over the titles for the page, and populate the menu with those.
+
+::
+
+ from cms.toolbar_pool import toolbar_pool
+ from cms.extensions.toolbar import ExtensionToolbar
+ from django.utils.translation import ugettext_lazy as _
+ from .models import RatingExtension
+ from cms.utils import get_language_list # needed to get the page's languages
+ @toolbar_pool.register
+ class RatingExtensionToolbar(ExtensionToolbar):
+ # defines the model for the current toolbar
+ model = RatingExtension
def populate(self):
# setup the extension toolbar with permissions and sanity checks
current_page_menu = self._setup_extension_toolbar()
+
# if it's all ok
if current_page_menu and self.toolbar.edit_mode:
- # create a sub menu
- position = 0
- sub_menu = self._get_sub_menu(current_page_menu, 'submenu_label', 'Submenu', position)
- # retrieves the instances of the current title extension (if any) and the toolbar item URL
+ # create a sub menu labelled "Ratings" at position 1 in the menu
+ sub_menu = self._get_sub_menu(
+ current_page_menu, 'submenu_label', 'Ratings', position=1
+ )
+
+ # retrieves the instances of the current title extension (if any)
+ # and the toolbar item URL
urls = self.get_title_extension_admin()
- # cycle through the title list
- for title_extension, url in urls:
+
+ # we now also need to get the titleset (i.e. different language titles)
+ # for this page
+ page = self._get_page()
+ titleset = page.title_set.filter(language__in=get_language_list(page.site_id))
+
+ # create a 3-tuple of (title_extension, url, title)
+ nodes = [(title_extension, url, title.title) for (
+ (title_extension, url), title) in zip(urls, titleset)
+ ]
+
+ # cycle through the list of nodes
+ for title_extension, url, title in nodes:
+
# adds toolbar items
- sub_menu.add_modal_item('icon for title %s' % self._get_page().get_title(),
- url=url, disabled=not self.toolbar.edit_mode)
+ sub_menu.add_modal_item(
+ 'Rate %s' % title, url=url, disabled=not self.toolbar.edit_mode
+ )
- Otherwise, the implementation is similar.
****************
@@ -208,10 +281,10 @@ above.
Title extensions
----------------
-In order to access to a title extension within a template, get the ``Title`` object using
-``request.current_page.get_title_obj``, for example:
+In order to retrieve a title extension within a template, get the ``Title`` object using
+``request.current_page.get_title_obj``. Using the example above, we could use::
- {{ request.current_page.get_title_obj.your_title_extension }}
+ {{ request.current_page.get_title_obj.ratingextension.rating }}
With menus
View
@@ -110,8 +110,6 @@ django CMS is a well-tested CMS platform that powers sites both large and
small. Here are a few of the key features:
* robust internationalisation (i18n) support for creating multilingual sites
-* virtually unlimited undo history, allowing editors to revert to a previous
- version
* front-end editing, providing rapid access to the content management interface
* support for a variety of editors with advanced text editing features.
* a flexible plugins system that lets developers put powerful tools at the
@@ -5,4 +5,8 @@ Models
.. class:: cms.models.Page
A ``Page`` is the basic unit of site structure in django CMS. The CMS uses a hierachical page model: each page
- stands in relation to other pages as parent, child or sibling.
+ stands in relation to other pages as parent, child or sibling. This hierarchy is managed by the `django-treebeard
+ <http://django-treebeard.readthedocs.io/en/latest/>`_ library.
+
+ A ``Page`` also has language-specific properties - for example, it will have a title and a slug for each language it
+ exists in. These properties are managed by the :class:`cms.models.Title` model.
@@ -3,3 +3,9 @@ Titles
######
.. class:: cms.models.Title
+
+ Titles support pages by providing a storage mechanism, amongst other things, for language-specific
+ properties of :class:`cms.models.Page`, such as its title, slug, meta description and so on.
+
+ Each ``Title`` has a foreign key to :class:`cms.models.Page`; each :class:`cms.models.Page` may have several
+ ``Titles``.

0 comments on commit 580d06e

Please sign in to comment.