From 175b84aadc451667aaa65ca5ed3b96ab3bc12b69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Reni=C3=A9?= Date: Mon, 12 Mar 2012 20:24:36 -0500 Subject: [PATCH] Added a {% widget %} tag This allows rendering widgets with the broader context, introducing compatibility with things like django-sekizai. This should make @ojii happy. --- docs/index.rst | 2 + docs/templatetags.rst | 26 +++++++++++++ floppyforms/templates/floppyforms/dummy.html | 1 + floppyforms/templatetags/floppyforms.py | 38 +++++++++++++++++++ floppyforms/tests/templates/media_widget.html | 2 + floppyforms/tests/templatetags.py | 25 ++++++++++++ 6 files changed, 94 insertions(+) create mode 100644 floppyforms/templates/floppyforms/dummy.html create mode 100644 floppyforms/tests/templates/media_widget.html diff --git a/docs/index.rst b/docs/index.rst index b9a75ad..42375ee 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -66,6 +66,8 @@ Changelog * Added ``form``, ``formrow``, ``formfield`` and ``formconfig`` template tags. * Added template based form layout system. + * Added ability to render widgets with the broader page context, for + instance for django-sekizai compatibility. * **v0.4**: diff --git a/docs/templatetags.rst b/docs/templatetags.rst index fd4b5cc..328f3a7 100644 --- a/docs/templatetags.rst +++ b/docs/templatetags.rst @@ -157,3 +157,29 @@ The ``formrow`` tag is usually only used in form layouts. See the documentation on :doc:`row templates and how they are customized ` for more details. + +widget +------ + +.. versionadded:: 1.0 + +The ``widget`` tag lets you render a widget with the outer template context +available. By default widgets are rendered using a completely isolated +context. In some cases you might want to access the outer context, for +instance for using floppyforms widgets with `django-sekizai`_:: + + {% for field in form %} + {% if not field.is_hidden %} + {{ field.label_tag }} + {% widget field %} + {{ field.errors }} + {% else %} + {% widget field %} + {% endif %} + {% endfor %} + +.. _django-sekizai: http://django-sekizai.readthedocs.org/en/latest/ + +You can safely use the ``widget`` tag with non-floppyforms widgets, they will +be properly rendered. However, since they're not template-based, they won't be +able to access any template context. diff --git a/floppyforms/templates/floppyforms/dummy.html b/floppyforms/templates/floppyforms/dummy.html new file mode 100644 index 0000000..98f6063 --- /dev/null +++ b/floppyforms/templates/floppyforms/dummy.html @@ -0,0 +1 @@ +{{ field }} diff --git a/floppyforms/templatetags/floppyforms.py b/floppyforms/templatetags/floppyforms.py index c7352af..f74b95d 100644 --- a/floppyforms/templatetags/floppyforms.py +++ b/floppyforms/templatetags/floppyforms.py @@ -691,6 +691,43 @@ def parse_variables(cls, tagname, parser, bits, options): return variables +class WidgetNode(Node): + """A template tag for rendering a widget with the outer context available. + + This is useful for for instance for using floppyforms with + django-sekizai.""" + + def __init__(self, field): + self.field = Variable(field) + + def render(self, context): + field = self.field.resolve(context) + + if callable(getattr(field.field.widget, 'get_context', None)): + name = field.html_name + attrs = {'id': field.auto_id} + value = field.value() + widget_ctx = field.field.widget.get_context(name, value, attrs) + template = field.field.widget.template_name + else: + widget_ctx = {'field': field} + template = 'floppyforms/dummy.html' + + template = get_template(template) + context.update(widget_ctx) + rendered = template.render(context) + context.pop() + return rendered + + @classmethod + def parse(cls, parser, tokens): + bits = tokens.split_contents() + if len(bits) != 2: + raise TemplateSyntaxError("{% widget %} takes one and only one argument") + field = bits.pop(1) + return cls(field) + + @register.filter def hidden_field_errors(form): hidden_field_errors = ErrorList() @@ -712,3 +749,4 @@ def id(bound_field): register.tag('form', FormNode.parse) register.tag('formrow', FormRowNode.parse) register.tag('formfield', FormFieldNode.parse) +register.tag('widget', WidgetNode.parse) diff --git a/floppyforms/tests/templates/media_widget.html b/floppyforms/tests/templates/media_widget.html new file mode 100644 index 0000000..647a8e3 --- /dev/null +++ b/floppyforms/tests/templates/media_widget.html @@ -0,0 +1,2 @@ +{% include "floppyforms/input.html" %} + diff --git a/floppyforms/tests/templatetags.py b/floppyforms/tests/templatetags.py index 99a90fa..442ba22 100644 --- a/floppyforms/tests/templatetags.py +++ b/floppyforms/tests/templatetags.py @@ -1,4 +1,5 @@ from __future__ import with_statement +from django.forms import TextInput from django.template import Context, Template, TemplateSyntaxError import floppyforms as forms @@ -606,3 +607,27 @@ def test_change_widget(self): self.assertHTMLEqual(render("""{% form myform using %} {% formfield form.name %} {% endform %}""", {'myform': form}, config), """""") + + +class WidgetTagTest(FloppyFormsTestCase): + def test_widget_tag(self): + class MediaWidget(forms.TextInput): + template_name = 'media_widget.html' + + class TestForm(forms.Form): + test = forms.CharField(widget=MediaWidget) + test2 = forms.CharField(widget=TextInput) + + self.assertHTMLEqual(render(""" + {% for field in form %} + {% widget field %} + {% endfor %}""", {'form': TestForm(), 'STATIC_URL': '/static/'}), """ + + + """) + + with self.assertRaises(TemplateSyntaxError): + render("""{% widget %}""") + + with self.assertRaises(TemplateSyntaxError): + render("""{% widget stuff 12 %}""")