From 9cbfc7199b1a4a8d909dde8b18e2f2040358cefc Mon Sep 17 00:00:00 2001 From: Diederik van der Boor Date: Tue, 10 Jan 2017 17:18:04 +0100 Subject: [PATCH] Add polymorphic_formset_tags library --- polymorphic/templatetags/__init__.py | 63 ++++++++++++++- .../templatetags/polymorphic_formset_tags.py | 79 +++++++++++++++++++ 2 files changed, 141 insertions(+), 1 deletion(-) create mode 100644 polymorphic/templatetags/polymorphic_formset_tags.py diff --git a/polymorphic/templatetags/__init__.py b/polymorphic/templatetags/__init__.py index f08e9fb..1c7e071 100644 --- a/polymorphic/templatetags/__init__.py +++ b/polymorphic/templatetags/__init__.py @@ -1,5 +1,65 @@ """ -Template tags to use in the admin. +Template tags for polymorphic + + +The ``polymorphic_formset_tags`` Library +---------------------------------------- + +.. versionadded:: 1.1 + +To render formsets in the frontend, the ``polymorphic_tags`` provides extra +filters to implement HTML rendering of polymorphic formsets. + +The following filters are provided; + +* ``{{ formset|as_script_options }}`` render the ``data-options`` for a JavaScript formset library. +* ``{{ formset|include_empty_form }}`` provide the placeholder form for an add button. +* ``{{ form|as_form_type }}`` return the model name that the form instance uses. +* ``{{ model|as_model_name }}`` performs the same, for a model class or instance. + +.. code-block:: html+django + + {% load i18n polymorphic_formset_tags %} + +
+ {% block add_button %} + {% if formset.show_add_button|default_if_none:'1' %} + {% if formset.empty_forms %} + {# django-polymorphic formset (e.g. PolymorphicInlineFormSetView) #} +
+ {% for model in formset.child_forms %} + {% glyphicon 'plus' %} {{ model|as_verbose_name }} + {% endfor %} +
+ {% else %} + {% trans "Add" %} + {% endif %} + {% endif %} + {% endblock %} + + {{ formset.management_form }} + + {% for form in formset|include_empty_form %} + {% block formset_form_wrapper %} +
+ {{ form.non_field_errors }} + + {# Add the 'pk' field that is not mentioned in crispy #} + {% for field in form.hidden_fields %} + {{ field }} + {% endfor %} + + {% block formset_form %} + {% crispy form %} + {% endblock %} +
+ {% endblock %} + {% endfor %} +
+ + +The ``polymorphic_admin_tags`` Library +-------------------------------------- The ``{% breadcrumb_scope ... %}`` tag makes sure the ``{{ opts }}`` and ``{{ app_label }}`` values are temporary based on the provided ``{{ base_opts }}``. @@ -13,4 +73,5 @@ This allows fixing the breadcrumb in admin templates: {% block breadcrumbs %} {% breadcrumb_scope base_opts %}{{ block.super }}{% endbreadcrumb_scope %} {% endblock %} + """ diff --git a/polymorphic/templatetags/polymorphic_formset_tags.py b/polymorphic/templatetags/polymorphic_formset_tags.py new file mode 100644 index 0000000..575299c --- /dev/null +++ b/polymorphic/templatetags/polymorphic_formset_tags.py @@ -0,0 +1,79 @@ +import json + +from django.template import Library +from django.utils.encoding import force_text +from django.utils.text import capfirst +from django.utils.translation import ugettext + +from polymorphic.formsets import BasePolymorphicModelFormSet + + +register = Library() + + +@register.filter() +def include_empty_form(formset): + """ + Make sure the "empty form" is included when displaying a formset (typically table with input rows) + """ + for form in formset: + yield form + + if hasattr(formset, 'empty_forms'): + # BasePolymorphicModelFormSet + for form in formset.empty_forms: + yield form + else: + # Standard Django formset + yield formset.empty_form + + +@register.filter +def as_script_options(formset): + """ + A JavaScript data structure for the JavaScript code + + This generates the ``data-options`` attribute for ``jquery.django-inlines.js`` + The formset may define the following extra attributes: + + - ``verbose_name`` + - ``add_text`` + - ``show_add_button`` + """ + verbose_name = getattr(formset, 'verbose_name', formset.model._meta.verbose_name) + options = { + 'prefix': formset.prefix, + 'pkFieldName': formset.model._meta.pk.name, + 'addText': getattr(formset, 'add_text', None) or ugettext('Add another %(verbose_name)s') % { + 'verbose_name': capfirst(verbose_name), + }, + 'showAddButton': getattr(formset, 'show_add_button', True), + 'deleteText': ugettext('Verwijder'), + } + + if isinstance(formset, BasePolymorphicModelFormSet): + # Allow to add different types + options['childTypes'] = [ + { + 'name': force_text(model._meta.verbose_name), + 'type': model._meta.model_name, + } for model in formset.child_forms.keys() + ] + + return json.dumps(options) + + +@register.filter +def as_form_type(form): + """ + Usage: ``{{ form|as_form_type }}`` + """ + return form._meta.model._meta.model_name + + +@register.filter +def as_model_name(model): + """ + Usage: ``{{ model|as_model_name }}`` + """ + return model._meta.model_name