Package: django-boundfield-renderer
django-boundfield-rendererA rendering engine for Django forms using templatetagsPreambleThere are already many libraries to render Django forms in templates, including the default Form methods as_p(), as_ul(), as_table(). Unfortunately, none of them (that I have encountered at least) apply strictly the concept of separation of form and function, or business logic from presentation, etc. Django has made a step into the right direction by using templates for the widgets, but the entirety of a field rendering is still partially done in python code. For example, if the developer wishes to put the label after the checkbox, he still has to write python, instead of redefining a template.This library defines one or more registry, that associate a rendering function (called renderer) for each form field class. That rendering function is made available through the templatetagrenderer.InstallationAdd'boundfield_renderer'to your INSTALLED_APPS setting so Django can find the templatetagrenderer.Basic steps to render a Django FormCreate a registry and register the renderers for the field classesFor example, in the filepath/to/my_registry.pyfromdjangoimportformsfromdjango.template.loaderimportget_templatefromboundfield_rendererimportRendererRegistry# Create the registryregistry=RendererRegistry()# Define a renderer function for a field class, for example the CharField# This can be as simple as the render method of a templatetemplate_render=get_template('mytemplates/char_field.html').render# Register the renderer for the field class in the registry# Either by setting it directly on the registryregistry[forms.CharField]=template_render# Or by using the register method as a decorator on a field class definition@registry.register(get_template('mytemplates/my_field.html').render)classMyField(forms.Field):passThe filemytemplates/char_field.htmlcould be as simple as this:<labelfor="{{ id }}">{{label}}<inputtype="text"id="{{ id }}"name="{{ name }}"value="{{ value }}"></label><p>{{ help_text }}</p><ul>{% for error in errors %}<li>{{ error }}</li>{% endfor %}</ul>Write a template that renders the form using therenderertemplate tagFor example, in the filemytemplates/my_form.html{% load boundfield_renderer %}<html><body><form>{% for boundfield in form %}
			{% renderer boundfield 'path.to.my_registry.registry' %}
			{% endfor %}<inputtype="submit"value="Send"></form></body></html>Renderer functionA renderer function does not have to be a template render method, it can be any method that returns a string. (Must it be marked safe?) It is passed a single parameter that is a dict (called context) with the following key/values:form: The form the field belongs toboundfield: The bound field itselfhtml_name: The HTML name attribute for the fieldvalue: The current value of the fieldlabel: The label of the fieldid: The id for the label of the fieldhelp_text: The help_text of the fielderrors: The list of Validation errors for the fielddisabled: True if the field is disabledis_hidden: True if the field is hiddenrequired: True if the field is requiredResolution of rendererTo find a renderer for a field class, we follow the MRO order of the field class until we find a renderer registered for that subclass. For example:fromdjango.core.exceptionsimportValidationError# Override CharField to add some extra clean, BUT DO NOT register a new rendererclassMyCharField(forms.CharField):defclean(self,value):ifvalue=='Spanish Inquisition':raiseValidationError('I was not expecting the Spanish Inquisition!')else:returnsuper().clean(value)# Override MyCharField AND register a new renderer@registry.register(get_template('mytemplates/my_other_char_field.html').render)classMyOtherCharField(MyCharField):passIn the first case, the renderer used will be the one we registered for the CharField earlier (templatemytemplates/char_field.html). In the second, the renderer used will be the one we registered for MyOtherCharField (templatemytemplates/my_other_char_field.html)If no renderer is found, a ValueError is raised.renderertemplatetagThe renderer templatetag takes a boundfield as the first parameter. It can also take as a second optional parameter a registry object or the full dotted path to a registry object.If no registry is specified, it will use the default registry as defined in the settings as DEFAULT_BOUNDFIELD_RENDERER_REGISTRY.For our example this would be:DEFAULT_BOUNDFIELD_RENDERER_REGISTRY='path.to.my_registry.registry'Finally, the renderer tag can take optional keyword parameters that will be added to the context.If we reuse our previous example form templatemytemplates/my_form.html, we could change the context for a particular field "starwberry" to add a context variable "css_classes" with a value of "forever":{% load boundfield_renderer %}<html><body><form>{% for boundfield in form %}
			{% if boundfield.name == 'strawberry' %}
			{% renderer boundfield 'path.to.my_registry.registry' css_classes='forever' %}
			{% else %}
			{% renderer boundfield 'path.to.my_registry.registry' %}
			{% endif %}
			{% endfor %}<inputtype="submit"value="Send"></form></body></html>Note on renderer registrationThe code that registers the renderer for a form field class must be executed by Django before therenderertemplatetag is called.Practically, this can be achieved by registering the renderers in the same file where the registry is defined, or in the files where the form field class are defined (for example using theregisterdecorator)