Include monkeypatch from nuggets. Fix #11.

This commit is contained in:
James Socol
2012-11-09 14:41:57 -05:00
parent 42321f50b9
commit 4361b9aacd
5 changed files with 128 additions and 0 deletions

View File

@@ -152,6 +152,15 @@ The other method uses Jinja's ``trans`` tag::
directly. Both methods are useful, pick the one that makes you happy.
Forms
-----
Django marks its form HTML "safe" according to its own rules, which Jinja2 does
not recognize.
.. automodule:: jingo.monkey
Testing
-------

View File

@@ -152,6 +152,15 @@ The other method uses Jinja's ``trans`` tag::
directly. Both methods are useful, pick the one that makes you happy.
Forms
-----
Django marks its form HTML "safe" according to its own rules, which Jinja2 does
not recognize.
.. automodule:: jingo.monkey
Testing
-------

85
jingo/monkey.py Normal file
View File

@@ -0,0 +1,85 @@
"""
This monkeypatches Django to support the __html__ protocol used in Jinja
templates. Form, BoundField, ErrorList, and other form objects that
render HTML through their __unicode__ method are extended with __html__
so they can be rendered in Jinja templates without adding |safe.
Call the patch() function to execute the patch. It must be called
before django.forms is imported for the conditional_escape patch to work
properly. The root URLconf is the recommended location for calling patch().
Usage::
import jingo.monkey
jingo.monkey.patch()
This patch was originally developed by Jeff Balogh and this version is taken
from the nuggets project at
https://github.com/mozilla/nuggets/blob/master/safe_django_forms.py
"""
import django.utils.encoding
import django.utils.html
import django.utils.safestring
# This function gets directly imported within Django, so this change needs to
# happen before too many Django imports happen.
def conditional_escape(html):
"""
Similar to escape(), except that it doesn't operate on pre-escaped strings.
"""
if hasattr(html, '__html__'):
return html.__html__()
elif isinstance(html, django.utils.safestring.SafeData):
return html
return django.utils.html.escape(html)
# Django uses SafeData to mark a string that has already been escaped or
# otherwise deemed safe. This __html__ method lets Jinja know about that too.
def __html__(self):
"""
Returns the html representation of a string.
Allows interoperability with other template engines.
"""
return self
# Django uses StrAndUnicode for classes like Form, BoundField, Widget which
# have a __unicode__ method which returns escaped html. We replace
# StrAndUnicode with SafeStrAndUnicode to get the __html__ method.
class SafeStrAndUnicode(django.utils.encoding.StrAndUnicode):
"""A class whose __str__ and __html__ returns __unicode__."""
def __html__(self):
return unicode(self)
def patch():
django.utils.html.conditional_escape = conditional_escape
django.utils.safestring.SafeData.__html__ = __html__
# forms imports have to come after we patch conditional_escape.
from django.forms import forms, formsets, util, widgets
# Replace StrAndUnicode with SafeStrAndUnicode in the inheritance
# for all these classes.
classes = (
forms.BaseForm,
forms.BoundField,
formsets.BaseFormSet,
util.ErrorDict,
util.ErrorList,
widgets.Media,
widgets.RadioInput,
widgets.RadioFieldRenderer,
)
for cls in classes:
bases = list(cls.__bases__)
if django.utils.encoding.StrAndUnicode in bases:
idx = bases.index(django.utils.encoding.StrAndUnicode)
bases[idx] = SafeStrAndUnicode
cls.__bases__ = tuple(bases)

View File

@@ -0,0 +1,24 @@
from django import forms
from jinja2 import escape
from nose.tools import eq_
import jingo
import jingo.monkey
from test_helpers import render
class MyForm(forms.Form):
email = forms.EmailField()
def test_monkey_patch():
form = MyForm()
html = form.as_ul()
context = {'form': form}
t = '{{ form.as_ul() }}'
eq_(escape(html), render(t, context))
jingo.monkey.patch()
eq_(html, render(t, context))

View File

@@ -1,5 +1,6 @@
from django.conf.urls.defaults import patterns
urlpatterns = patterns('',
(r'^url/(\d+)/(\w+)/$', lambda r: None, {}, "url-args"),
(r'^url/(?P<num>\d+)/(?P<word>\w+)/$', lambda r: None, {}, "url-kwargs"),