Customizing the frontend rendering¶
As displayed in the Example plugin code page, a plugin is made of two classes:
- A model class in
models.py
. - A plugin class in
content_plugins.py
.
The plugin class renders the model instance using:
- A custom
render()
method. - The
render_template
attribute,get_render_template()
method and optionallyget_context()
method.
Simply stated, a plugin provides the “view” of a “model”.
Simple rendering¶
To quickly create plugins with little to no effort, only the render_template
needs to be specified.
The template code receives the model object via the instance
variable.
To switch the template depending on the model, the get_render_template()
method
can be overwritten instead. For example:
@plugin_pool.register
class MyPlugin(ContentPlugin):
# ...
def get_render_template(self, request, instance, **kwargs):
return instance.template_name or self.render_template
To add more context data, overwrite the get_context
method.
The twitterfeed plugins use this for example to pass settings to the template:
@plugin_pool.register
class MyPlugin(ContentPlugin):
# ...
def get_context(self, request, instance, **kwargs):
context = super(MyPlugin, self).get_context(request, instance, **kwargs)
context.update({
'AVATAR_SIZE': int(appsettings.FLUENT_TWITTERFEED_AVATAR_SIZE),
'REFRESH_INTERVAL': int(appsettings.FLUENT_TWITTERFEED_REFRESH_INTERVAL),
'TEXT_TEMPLATE': appsettings.FLUENT_TWITTERFEED_TEXT_TEMPLATE,
})
return context
For most scenario’s, this provides simple flexibility with a DRY approach.
Custom rendering¶
Instead of only providing extra context data,
the whole render()
method can be overwritten as well.
It should return a string with the desired output. For example, this is the render function of the text plugin:
def render(self, request, instance, **kwargs):
return mark_safe('<div class="text">' + instance.text + '</div>\n')
The standard render()
method basically does the following:
def render(self, request, instance, **kwargs):
template = self.get_render_template(request, instance, **kwargs)
context = self.get_context(request, instance, **kwargs)
return self.render_to_string(request, template, context)
- It takes the template from
get_render_template()
. - It uses the the context provided by
get_context()
. - It uses
render_to_string()
method which adds theSTATIC_URL
andMEDIA_URL
variables in the template.
The output will be escaped by default, so use Django’s format_html()
or mark_safe()
when content should not be escaped.
Hence, it’s preferred to use a template unless that makes things more complex.
Internally, the render_to_string()
method
wraps the rendering context in a PluginContext()
.
which is similar to the RequestContext
that Django provides.
Form processing¶
An entire form with GET/POST can be handled with a plugin.
This happens again by overwriting render()
method.
For example, a “Call me back” plugin can be created using a
custom render()
function:
@plugin_pool.register
class CallMeBackPlugin(ContentPlugin):
model = CallMeBackItem
category = _("Contact page")
render_template = "contentplugins/callmeback/callmeback.html"
cache_output = False # Important! See "Output caching" below.
def render(self, request, instance, **kwargs):
context = self.get_context(request, instance, **kwargs)
context['completed'] = False
if request.method == 'POST':
form = CallMeBackForm(request.POST, request.FILES)
if form.is_valid():
instance = form.save()
return self.redirect(reverse('thank-you-page'))
else:
form = CallMeBackForm()
context['form'] = form
return self.render_to_string(request, self.render_template, context)
Note
The cache_output
attribute is False
to disable the default output caching. The POST screen would return the cached output instead.
To allow plugins to perform directs,
add fluent_contents.middleware.HttpRedirectRequestMiddleware
to MIDDLEWARE_CLASSES
.
Frontend media¶
Plugins can specify additional JS/CSS files which should be included. For example:
@plugin_pool.register
class MyPlugin(ContentPlugin):
# ...
class FrontendMedia:
css = {
'all': ('myplugin/all.css',)
}
js = (
'myplugin/main.js',
)
Equally, there is a frontend_media
property,
and get_frontend_media
method.
Output caching¶
By default, plugin output is cached and only refreshes when the administrator saves the page. This greatly improves the performance of the web site, as very little database queries are needed, and most pages look the same for every visitor anyways.
- When the plugin output is dynamic set the
cache_output
toFalse
. - When the plugin output differs per
SITE_ID
only, setcache_output_per_site
toTrue
. - When the plugin output differs per language,
set
cache_output_per_language
toTrue
. - When the output should be refreshed more often,
change the
cache_timeout
. - As last resort, the caching can be disabled entirely project-wide using the FLUENT_CONTENTS_CACHE_OUTPUT setting. This should be used temporary for development, or special circumstances only.
Most plugins deliver exactly the same content for every request, hence the setting is tuned for speed by default. Further more, this lets plugin authors make a conscious decision about caching, and to avoid unexpected results in production.
When a plugin does a lot of processing at render time
(e.g. requesting a web service, parsing text, sanitizing HTML, or do XSL transformations of content),
consider storing the intermediate rendering results in the database using the save()
method of the model.
The code plugin uses this for example to store the highlighted code syntax.
The render()
method can just read the value.
Development tips¶
In DEBUG
mode, changes to the render_template
are detected, so this doesn’t affect the caching. Some changes however, will not be detected (e.g. include files).
A quick way to clear memcache, is by using nc/ncat/netcat:
echo flush_all | nc localhost 11211
When needed, include FLUENT_CONTENTS_CACHE_OUTPUT = False
in the settings file.