CMS System¶
Cubane’s content management system is provided by the
cubane.cms.views.CMS
class. You need to provide your own class that
derives from cubane.cms.views.CMS
. Usually you declare your class in
your main views.py
file for example:
from cubane.cms.views import CMS
class MyCMS(CMS):
pass
By introducing your own class, you can alter the behaviour of the CMS system by
overriding various methods. The CMS class is declared via the Django setting
variable CMS
for your application in the following way:
CMS = 'myapp.views.MyCMS'
The given string value is referring to the actual class that is used by Cubane for representing the CMS system. The path must include the full path to the class including modules and sub-modules.
The following sections will provide details on how to extend and override certain methods of the CMS class in order to extend and change the behaviour of the CMS system.
Template Context Pipeline¶
The CMS system will derive a default template context by deriving a number of variables that are provided when rendering any CMS content.
Then, such template context is further processed by a number of steps until finally the actual page is being rendered.
The CMS class can be extended to intercept and process the template content at various stages in the pipeline, for example to include page-specific or general data that must be available for the template.
The following example demonstrates how the template variable featured
is
made available to every page that is rendered. This could be used for example
to render a list of featured posts on every page.
from cubane.cms.views import CMS
from myapp.models import NewsArticle
class MyCMS(CMS):
def on_template_context(self, request, context, template_context):
featured = NewsArticle.objects.order_by('-posted_on')[:3]
template_context.update({
'featured': featured
})
return template_context
The method cubane.views.CMS.on_template_context()
is being called by the
CMS system for every page that is rendered. So, any additional database
roundtrips or processing work undertaken here occurs for every single page.
The given template context has already been compiled and is ready to be used by
the page template. Therefore, you can use it within your version of
cubane.views.CMS.on_template_context()
in order to obtain critical
information about what is being rendered as the following example demonstrates:
from cubane.cms.views import CMS
from myapp.models import NewsArticle
class MyCMS(CMS):
def on_template_context(self, request, context, template_context):
current_page = template_context.get('current_page')
if current_page and current_page.is_homepage:
featured = NewsArticle.objects.order_by('-posted_on')[:3]
template_context.update({
'featured': featured
})
return template_context
Here, we are only fetching the latest news articles if the current page is the homepage. Cubane’s CMS system provides a number of similar methods to make those common cases easy for us. For example, we could have written the previous example in the following way:
from cubane.cms.views import CMS
from myapp.models import NewsArticle
class MyCMS(CMS):
def on_homepage(self, request, context, template_context):
featured = NewsArticle.objects.order_by('-posted_on')[:3]
template_context.update({
'featured': featured
})
return template_context
The method cubane.views.CMS.on_homepage()
is only being called whenever
the homepage is rendered. Otherwise the method works in the exact same way as
cubane.views.CMS.on_template_context()
.
The following pipeline steps can be overridden:
Method | Description |
---|---|
cubane.views.CMS.on_template_context() |
Called for every request. |
cubane.views.CMS.on_homepage() |
Called only for requests concerning the homepage. |
cubane.views.CMS.on_contact_page() |
Called only for requests concerning the contact page. |
cubane.views.CMS.on_404_page() |
Called only for requests that will trigger a 404 status code. |
Template Context¶
The CMS system derives a default template context for every request that is being processed. Such template context contains information about the current page, the navigation and website-wide settings.
The following template variables are available when rendering CMS content:
active_nav
Contains information about the top level navigation item that is currently the active item. The active navigation item is representing the current page or any parent page therefore.
current_page
Represents the page model instance of the current page that is rendered.
homepage
The page model instance of the page that represents the homepage.
images
A list of all image model instances that are referenced on the current page via one or more content slots.
is_404_page
True
if the current page is rendered as a 404 not found page. Please refer to section Default Page Roles for more information about page roles.
is_contact_page
True
if the current page is the contact page. Please refer to section Default Page Roles for more information about page roles.
is_enquiry_template
True
if the current page is the enquiry page. Please refer to section Default Page Roles for more information about page roles.
is_homepage
True
if the current page is the homepage. Please refer to section Default Page Roles for more information about page roles.
nav
Represents the navigation structure of the page. Please refer to section Navigation for more information.
pages
Represents a list of navigation items for every page that has a unique navigation identifier assigned to it. Please refer to section Navigation by Identifier for more information on navigation identifiers.
page_links
Represents a list of CMS content to which the current page is linking to via its content slots. Please refer to section Links for more information about page links.
page
Refers to the model instance of the current page or – if the current page is represented by a post – the parent page of the current post.
preview
True
if the current page is currently rendered for the purpose of being previewed within the backend system. Please refer to section Preview for more information.
settings
The model instance of the CMS settings as specified viaCMS_SETTINGS_MODEL
. Please refer to section CMS Settings for more information about CMS settings.
slots
Represents a list of slot names of all slots of the current page that are not empty.
If a page hierarchy is used (PAGE_HIERARCHY
), then the following
template variable is made available in addition to the default context:
hierarchical_pages
Represents a list of all page model instances that are direct child pages of the current page. Please refer to section Page Hierarchy for more information about page hierarchies.
If the page has posts assigned to it then the following information is made available in addition to the default context:
paged_posts
List of posts that are assigned to the current page – organised as a list of pages.
paginator
Thepaginator
object that is responsible to paginate the list of all posts that are assigned to the current page.
posts
List of all posts that are assigned to the current page.
post_slug
The slug representing the type of posts that are assigned to the current page.
verbose_name_plural
The plural verbose name of the model that is representing posts that are assigned to the current page.
verbose_name
The singular verbose name of the model that is representing posts that are assigned to the current page.
The template context is first derived for any request that is being processed. Then the template context might be intercepted and further processed by various parts of the CMS system. Please refer to section Template Context Pipeline for more information about pipeline steps.
Hierarchical Pages Queryset¶
The list of hierarchical pages is determined by the method
cubane.cms.views.CMS.get_hierarchical_pages()
. You can override the
method in order to customise the list of hierarchical pages that are returned:
from cubane.cms.views import CMS
class MyCMS(CMS):
def get_hierarchical_pages(self, request, current_page, pages):
pages = pages.order_by('title')
return pages
The example changes the order in which child pages are represented. While you would normally find child pages to be ordered in their distinct sequential order, here the order has been changed to be alphabetically by the page title.
Posts Queryset¶
The list of posts that are assigned to the current page is determined by the
method cubane.cms.views.CMS.get_posts()
. You can override the method in
order to customise the list of posts that are returned:
from django.http import HttpResponse
from cubane.cms.views import CMS
class MyCMS(CMS):
def get_posts(self, request, model, posts):
posts = posts.order_by('title)
return posts
Again, we are only changing the order of posts here, but we could customise the initial query or filter by further arguments.
Preview¶
Any CMS-enabled page can be rendered for preview mode in the backend system. In fact, the preview is used to select particular page slots in order to edit their content.
When rendering page slots via the slot
template tag, then it it
particularly important to always render to slot if the page is presented in
preview mode: For example, a slot may only be rendered under a certain
condition, but in preview mode you would want to always render a slot;
otherwise users will not be able to select the slot to begin with.
{% load cms_tags %}
<!DOCTYPE html>
<html>
<body>
{% if 'content' in slots or preview %}
<div class="content-slot">{% slot 'content' %}</div>
{% endif %}
</body>
</html>
The example demonstrates a condition under which the slot is rendered: The slot is only rendered if the slot has actual content assigned to it. However we also render the slot if we are in preview mode; otherwise no-one would be able to assign content to the slot to start with.
Request/Response Hooks¶
On every request, the CMS system calls the methods
cubane.cms.views.CMS.on_request()
and
cubane.cms.views.CMS.on_response()
.
cubane.cms.views.CMS.on_request()
is called first before any other
pipeline function is called. Just before the response has been compiled, the
method cubane.cms.views.CMS.on_response()
is called.
Both methods can alter the response if a response object is returned by either
of them. If cubane.cms.views.CMS.on_request()
returns a response object,
then any further processing is aborted and the returned response object is
delivered back to the client.
from django.http import HttpResponse
from cubane.cms.views import CMS
class MyCMS(CMS):
def on_request(self, request, context):
return HttpResponse('Intercepting each request replacing it with this response.')
Identifier Hooks¶
For CMS pages that have a unique identifier assigned, a method can be defined
as part of the cubane.cms.views.CMS
class that matches the identifier.
For example, if a page is rendered that had an identifier of map
then the
CMS system would automatically attempt to call the method
on_page_identifier_map
.
from django.conf import settings
from django.http import HttpResponse
from cubane.cms.views import CMS
class MyCMS(CMS):
def on_page_identifier_map(self, request, context, template_context):
template_context.update({
'map_api_key': settings.MAP_API_KEY
})
return template_context
The example above demonstrates how the settings variable MAP_API_KEY
is
provided to the template for the page with the identifier map
.
See also
A unique page identifier is also useful when using the navigation system. Please refer to section Navigation by Identifier for more information about identifiers being used in combination with the navigation system.
Django View Handlers¶
The CMS system can be integrated with ordinary Django view handlers by allowing the system to determine a template context including navigation and other aspects to be derived without any real CMS page being present.
For example, you could implement a member area where the login page does not really exist as part of the CMS system. However, you can still generate all other CMS-related information that is required to render the page, such as the navigation:
from cubane.decorators import template
from cubane.cms.decorators import cubane_cms_context
@template('myapp/login.html')
@cubane_cms_context()
def members_login(request):
...
return {
'form': form
}
The template
decorator can be used to render a template file (in this case
myapp/login.html
based on the template context that is returned by the view
handler function in the form of a dictionary.
The cubane_cms_context
decorator generates a regular template context as
you would expect from the CMS system (see section
Template Context) but then also updates the template
context based on the dictionary that is returned from the django view handler
function.