"""
Plugin for including template snippets through the CMS
"""
from collections import defaultdict
from content_editor.admin import ContentEditorInline
from django.db import models
from django.db.models import signals
from django.template.base import Template
from django.template.loader import render_to_string
from django.utils.translation import gettext_lazy as _
from feincms3.mixins import ChoicesCharField
from feincms3.renderer import render_in_context
__all__ = ("Snippet", "SnippetInline", "render_snippet")
[docs]
def render_snippet(plugin, context=None, **kwargs):
"""
Renders the selected template using ``render_to_string``
"""
return render_to_string(plugin.template_name, {"plugin": plugin})
[docs]
class Snippet(models.Model):
"""
Template snippet plugin
"""
template_name = ChoicesCharField(_("template"), max_length=100)
class Meta:
abstract = True
verbose_name = _("predefined snippet")
verbose_name_plural = _("predefined snippets")
def __str__(self):
return self.get_template_name_display()
[docs]
@staticmethod
def fill_template_name_choices(sender, **kwargs):
"""
Fills in the choices for ``template_name`` from the ``TEMPLATES`` class
variable. This method is a receiver of Django's ``class_prepared``
signal.
"""
if issubclass(sender, Snippet) and not sender._meta.abstract:
sender._meta.get_field("template_name").choices = [
choice[:2] for choice in sender.TEMPLATES
]
[docs]
@classmethod
def register_with(cls, renderer, **kwargs):
"""
This helper registers the snippet plugin with a
``TemplatePluginRenderer`` while adding support for template-specific
context functions. The templates specified using the ``TEMPLATES``
class variable may contain a callable which receives the plugin
instance and the template context and returns a context dictionary.
"""
from feincms3.renderer import default_context
templates = defaultdict(
lambda: Template(""),
((row[0], row[0]) for row in cls.TEMPLATES),
)
context_fns = defaultdict(
lambda: default_context,
[(row[0], row[2]) for row in cls.TEMPLATES if len(row) > 2],
)
def _render_snippet(plugin, context):
return render_in_context(
context,
templates[plugin.template_name],
context_fns[plugin.template_name](plugin, context),
)
renderer.register(cls, _render_snippet, **kwargs)
signals.class_prepared.connect(Snippet.fill_template_name_choices)
[docs]
class SnippetInline(ContentEditorInline):
"""
Snippet inline does nothing special, it simply exists for consistency
with the other feincms3 plugins
"""
button = '<span class="material-icons">smart_toy</span>'