Source code for dynamicforms.templatetags.dynamicforms

import json as jsonlib

from django import template
from django.utils.safestring import mark_safe
from django.utils.translation import ugettext_lazy as _
from rest_framework.templatetags import rest_framework as drftt
from rest_framework.utils.encoders import JSONEncoder

from ..action import TablePosition
from ..mixins import DisplayMode
from ..renderers import HTMLFormRenderer
from ..struct import Struct

register = template.Library()


[docs]@register.filter(name='dict_item') def dict_item(d, k): """Returns the given key from a dictionary.""" return d[k]
# just copy the template tags that are the same as we're not redeclaring them # TODO: the following DRF filters pending removal? # note that simply copying the filters didn't work: django kept complaining about parameters. So now it's verbatim copy
[docs]@register.filter def items(value): """ Simple filter to return the items of the dict. Useful when the dict may have a key 'items' which is resolved first in Django template dot-notation lookup. See DRF issue #4931 Also see: https://stackoverflow.com/questions/15416662/django-template-loop-over-dictionary-items-with-items-as-key """ return drftt.items(value)
@register.filter def add_nested_class(value): return drftt.add_nested_class(value) @register.filter def format_value(value): # TODO: this one pending removal on tasks #62 in #63 completion return drftt.format_value(value) @register.filter def as_string(value): # TODO: this one pending removal on tasks #62 in #63 completion return drftt.as_string(value) @register.filter def as_list_of_strings(value): # TODO: this one pending removal on tasks #62 in #63 completion return drftt.as_list_of_strings(value) # // just copy tags
[docs]@register.simple_tag def render_form(serializer, form_template=None): """ Renders form from serializer. If form_template is given, then renderer will use that one, otherwise it will use what is defined in self.base_template (e.g.: »form.html«) from template_pack (e.g.: »dynamicforms/bootstrap/field/«) .. code-block:: django {% set_var template_pack=DYNAMICFORMS.template|add:'field' %} {% render_form serializer template_pack=template_pack %} :param serializer: Serializer object :param form_template: form template file name to use. overrides all other template name declarations :return: rendered template """ style = {} if form_template: style['form_template'] = form_template style['serializer'] = serializer renderer = HTMLFormRenderer() return renderer.render(serializer.data, None, {'style': style})
[docs]@register.simple_tag def render_field(field, style): """ Renders separate field. Style is a dict, that contains template_pack or form_template and rendered. It is defined when rendering form, so it is best to use that one. To do that dynamicforms should be loaded first. See example below. .. code-block:: django {% load dynamicforms %} {% for field in form %} {% if not field.read_only %} {% render_field field style=style %} {% endif %} {% endfor %} :param field: Serializer Field instance :param style: render parameters :return: rendered field template """ renderer = style.get('renderer', HTMLFormRenderer()) return renderer.render_field(field, style)
[docs]@register.simple_tag def render_field_to_table(serializer, field_name, value, row_data): """ Renders separate field to table view. :param serializer: Serializer :param field_name: Field name :param value: Field value :param row_data: data for entire row :return: rendered field for table view """ return serializer.fields[field_name].render_to_table(value, row_data)
[docs]@register.simple_tag def table_columns_count(serializer): """ Returns number of columns including control columns :param serializer: Serializer :return: Number of all columns """ actions = serializer.actions.renderable_actions(serializer) return (len([f for f in serializer.fields.values() if f.display_table == DisplayMode.FULL]) + (1 if any(action.position == "rowend" for action in actions) else 0) + (1 if any(action.position == "rowstart" for action in actions) else 0))
[docs]@register.simple_tag(takes_context=True) def render_table_commands(context, serializer, position, field_name=None, button_position=None): """ Renders commands that are defined in serializers controls attribute. :param context: Context :param serializer: Serializer :param position: Position of command (See action.py->Action for more details) :param field_name: If position is left or right to the field, then this parameter must contain field name :param button_position: form button position one of (form, dialog, user-provided) :return: rendered command buttons. If table_header parameter is given and commands for position are defined, returns only rendered table header """ ret = '' if position == 'onfieldchange': ret = serializer.actions.render_field_onchange(serializer) ret += serializer.actions.render_form_init(serializer) elif position == 'onfieldinit': ret += serializer.actions.render_field_init(serializer, field_name) elif position == 'form-buttons': ret += serializer.actions.render_form_buttons(serializer, button_position) else: table_header = None if position.startswith('thead_'): position = position[6:] table_header = _('Actions') positions = dict( onrowclick=(TablePosition.ROW_CLICK, TablePosition.ROW_RIGHTCLICK), header=(TablePosition.HEADER,), rowstart=(TablePosition.ROW_START,), rowend=(TablePosition.ROW_END,), fieldleft=(TablePosition.FIELD_START,), fieldright=(TablePosition.FIELD_END,), ) ret_tmp = serializer.actions.render_renderable_actions(positions[position], field_name, serializer) if ret_tmp and positions[position][0] in (TablePosition.ROW_START, TablePosition.ROW_END): ret += ('<th>%s</th>' % table_header) if table_header else ('<td>%s</td>' % ret_tmp) elif ret_tmp: ret += ret_tmp ret = '{% load static i18n %}' + ret return mark_safe(context.template.engine.from_string(ret).render(context))
[docs]@register.simple_tag(takes_context=True) def field_to_serializer_and_data(context, serializer): """ Adjusts context such that the nested serializer field becomes THE serializer :param serializer: field to be converted into context :return: nothing """ if hasattr(serializer, 'child'): # this is a ListSerializer context.update(dict(serializer=serializer.child, data=serializer.value, **serializer.child.template_context)) else: serializer._field._data = serializer.value # The serializer has default values here context.update(dict(serializer=serializer, data=serializer.value, **serializer.template_context)) return ''
[docs]@register.simple_tag(takes_context=True) def get_data_template(context, context_data=None): """ Returns template that should be used for rendering current serializer data :param context: template context (automatically provided by django) :return: template file name """ if context_data: context = context_data serializer = context['serializer'] return serializer.data_template
[docs]@register.simple_tag(takes_context=True) def set_var(context, **kwds): """ Sets the given variables to provided values. Kind of like the 'with' block, only it isn't a block tag :param context: template context (automatically provided by django) :param kwds: named parameters with their respective values :return: this tag doesn't render """ for k, v in kwds.items(): context[k] = v return ''
[docs]@register.simple_tag(takes_context=True) def set_var_conditional(context, condition=None, condition_var=None, compare=None, else_value=None, **kwds): """ Sets the given variables to provided values. Kind of like the 'with' block, only it isn't a block tag :param context: template context (automatically provided by django) :param kwds: named parameters with their respective values :param condition_var: pair with compare to obtain True or False whether to use original assignment or else_value :param compare: pair with condition_var to obtain True or False whether to use original assignment or else_value :param condition: alternative to condition_var & compare: original assignment if truthy or else_value if falsy :param else_value: value to be assigned to the variable(s) when condition is falsy :return: this tag doesn't render """ if condition_var is not None: condition = condition_var == compare for k, v in kwds.items(): context[k] = v if condition else else_value return ''
@register.simple_tag(takes_context=False) def iter_options_bound(field): return field.iter_options_bound(field.value)
[docs]@register.filter def json(value): """ JSON serialises given variable. Use when you want to insert a variable directly into JavaScript :param value: variable to serialise :return: JSON serialised string """ class Encoder(JSONEncoder): def default(self, obj): if isinstance(obj, Struct): return obj.__to_dict__() return super().default(obj) return mark_safe(jsonlib.dumps(value, cls=Encoder))
@register.simple_tag(takes_context=True) def dict_item_default(context, var, d, k, default): context[var] = d.get(k, default) return ''