Skip to content

Commit

Permalink
Added a {% widget %} tag
Browse files Browse the repository at this point in the history
This allows rendering widgets with the broader context, introducing
compatibility with things like django-sekizai.

This should make @ojii happy.
  • Loading branch information
brutasse committed Mar 13, 2012
1 parent 19a9df3 commit 175b84a
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 0 deletions.
2 changes: 2 additions & 0 deletions docs/index.rst
Expand Up @@ -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**:

Expand Down
26 changes: 26 additions & 0 deletions docs/templatetags.rst
Expand Up @@ -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
</layouts>` 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.
1 change: 1 addition & 0 deletions floppyforms/templates/floppyforms/dummy.html
@@ -0,0 +1 @@
{{ field }}
38 changes: 38 additions & 0 deletions floppyforms/templatetags/floppyforms.py
Expand Up @@ -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()
Expand All @@ -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)
2 changes: 2 additions & 0 deletions floppyforms/tests/templates/media_widget.html
@@ -0,0 +1,2 @@
{% include "floppyforms/input.html" %}
<script type="text/javascript" src="{{ STATIC_URL }}foo.js"></script>
25 changes: 25 additions & 0 deletions 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
Expand Down Expand Up @@ -606,3 +607,27 @@ def test_change_widget(self):
self.assertHTMLEqual(render("""{% form myform using %}
{% formfield form.name %}
{% endform %}""", {'myform': form}, config), """<input type="password" name="name" id="id_name" />""")


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/'}), """
<input type="text" name="test" id="id_test" required>
<script type="text/javascript" src="/static/foo.js"></script>
<input type="text" name="test2" id="id_test2">""")

with self.assertRaises(TemplateSyntaxError):
render("""{% widget %}""")

with self.assertRaises(TemplateSyntaxError):
render("""{% widget stuff 12 %}""")

0 comments on commit 175b84a

Please sign in to comment.