From fcb30a11d8c289632c271d1c4b9993d7ee4c2b9b Mon Sep 17 00:00:00 2001 From: Joseph Kocherhans Date: Fri, 30 Nov 2007 20:55:26 +0000 Subject: [PATCH] newforms-admin: Fixed #6722. Admin widgets are now marked safe. git-svn-id: http://code.djangoproject.com/svn/django/branches/newforms-admin@6782 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- django/contrib/admin/options.py | 2 +- .../contrib/admin/templatetags/admin_list.py | 6 ++-- django/contrib/admin/tests/__init__.py | 5 +++ django/contrib/admin/tests/widgets.py | 35 +++++++++++++++++++ django/contrib/admin/views/main.py | 1 + django/contrib/admin/widgets.py | 13 +++---- 6 files changed, 51 insertions(+), 11 deletions(-) create mode 100644 django/contrib/admin/tests/__init__.py create mode 100644 django/contrib/admin/tests/widgets.py diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py index 952d4b8298..f84b096158 100644 --- a/django/contrib/admin/options.py +++ b/django/contrib/admin/options.py @@ -101,7 +101,7 @@ class Fieldline(object): yield AdminField(self.form, field, is_first=(i == 0)) def errors(self): - return u'\n'.join([self.form[f].errors.as_ul() for f in self.fields]) + return mark_safe(u'\n'.join([self.form[f].errors.as_ul() for f in self.fields])) class AdminField(object): def __init__(self, form, field, is_first): diff --git a/django/contrib/admin/templatetags/admin_list.py b/django/contrib/admin/templatetags/admin_list.py index c3b993f518..2737a27972 100644 --- a/django/contrib/admin/templatetags/admin_list.py +++ b/django/contrib/admin/templatetags/admin_list.py @@ -114,7 +114,7 @@ def result_headers(cl): yield {"text": header, "sortable": True, "url": cl.get_query_string({ORDER_VAR: i, ORDER_TYPE_VAR: new_order_type}), - "class_attrib": (th_classes and ' class="%s"' % ' '.join(th_classes) or '')} + "class_attrib": mark_safe((th_classes and ' class="%s"' % ' '.join(th_classes) or ''))} def _boolean_icon(field_val): BOOLEAN_MAPPING = {True: 'yes', False: 'no', None: 'unknown'} @@ -148,8 +148,6 @@ def items_for_result(cl, result): # function has an "allow_tags" attribute set to True. if not allow_tags: result_repr = escape(result_repr) - else: - result_repr = mark_safe(result_repr) else: field_val = getattr(result, f.attname) @@ -187,7 +185,7 @@ def items_for_result(cl, result): else: result_repr = escape(field_val) if force_unicode(result_repr) == '': - result_repr = mark_safe(' ') + result_repr = ' ' # If list_display_links not defined, add the link tag to the first field if (first and not cl.list_display_links) or field_name in cl.list_display_links: table_tag = {True:'th', False:'td'}[first] diff --git a/django/contrib/admin/tests/__init__.py b/django/contrib/admin/tests/__init__.py new file mode 100644 index 0000000000..ca064cbbf9 --- /dev/null +++ b/django/contrib/admin/tests/__init__.py @@ -0,0 +1,5 @@ +from django.contrib.admin.tests import widgets + +__test__ = { + 'WIDGET_TESTS': widgets, +} diff --git a/django/contrib/admin/tests/widgets.py b/django/contrib/admin/tests/widgets.py new file mode 100644 index 0000000000..e2c8c68916 --- /dev/null +++ b/django/contrib/admin/tests/widgets.py @@ -0,0 +1,35 @@ +""" +>>> from datetime import datetime +>>> from django.utils.html import escape, conditional_escape +>>> from django.contrib.admin.widgets import FilteredSelectMultiple, AdminSplitDateTime +>>> from django.contrib.admin.widgets import AdminFileWidget, ForeignKeyRawIdWidget +>>> from django.contrib.admin.widgets import RelatedFieldWidgetWrapper +>>> from django.contrib.admin.models import LogEntry + +Calling conditional_escape on the output of widget.render will simulate what +happens in the template. This is easier than setting up a template and context +for each test. + +Make sure that the Admin widgets render properly, that is, without their extra +HTML escaped. + +>>> w = FilteredSelectMultiple('test', False) +>>> print conditional_escape(w.render('test', 'test')) + + + +>>> w = AdminSplitDateTime() +>>> print conditional_escape(w.render('test', datetime(2007, 12, 1, 9, 30))) +

Date:
Time:

+ +>>> w = AdminFileWidget() +>>> print conditional_escape(w.render('test', 'test')) +Currently: test
Change: + +>>> rel = LogEntry._meta.get_field('user').rel +>>> w = ForeignKeyRawIdWidget(rel) +>>> print conditional_escape(w.render('test', 'test', attrs={})) + Lookup + +""" diff --git a/django/contrib/admin/views/main.py b/django/contrib/admin/views/main.py index 44012bc0cd..2a78b7ed75 100644 --- a/django/contrib/admin/views/main.py +++ b/django/contrib/admin/views/main.py @@ -10,6 +10,7 @@ from django.db.models.query import handle_legacy_orderlist, QuerySet from django.http import Http404 from django.utils.encoding import force_unicode, smart_str from django.utils.translation import ugettext +from django.utils.safestring import mark_safe import operator try: diff --git a/django/contrib/admin/widgets.py b/django/contrib/admin/widgets.py index cbef69ce01..26aacf7a03 100644 --- a/django/contrib/admin/widgets.py +++ b/django/contrib/admin/widgets.py @@ -6,6 +6,7 @@ from django import newforms as forms from django.utils.datastructures import MultiValueDict from django.utils.text import capfirst from django.utils.translation import ugettext as _ +from django.utils.safestring import mark_safe from django.conf import settings class FilteredSelectMultiple(forms.SelectMultiple): @@ -28,7 +29,7 @@ class FilteredSelectMultiple(forms.SelectMultiple): # API to determine the ID dynamically. output.append(u'SelectFilter.init("id_%s", "%s", %s, "%s"); });\n' % \ (name, self.verbose_name.replace('"', '\\"'), int(self.is_stacked), settings.ADMIN_MEDIA_PREFIX)) - return u''.join(output) + return mark_safe(u''.join(output)) class AdminDateWidget(forms.TextInput): class Media: @@ -57,8 +58,8 @@ class AdminSplitDateTime(forms.SplitDateTimeWidget): forms.MultiWidget.__init__(self, widgets, attrs) def format_output(self, rendered_widgets): - return u'

%s %s
%s %s

' % \ - (_('Date:'), rendered_widgets[0], _('Time:'), rendered_widgets[1]) + return mark_safe(u'

%s %s
%s %s

' % \ + (_('Date:'), rendered_widgets[0], _('Time:'), rendered_widgets[1])) class AdminFileWidget(forms.FileInput): """ @@ -73,7 +74,7 @@ class AdminFileWidget(forms.FileInput): if value: output.append('Currently: %s
Change: ' % (settings.MEDIA_URL, value, value)) output.append(super(AdminFileWidget, self).render(name, value, attrs)) - return u''.join(output) + return mark_safe(u''.join(output)) class ForeignKeyRawIdWidget(forms.TextInput): """ @@ -99,7 +100,7 @@ class ForeignKeyRawIdWidget(forms.TextInput): output.append(' ' % \ (related_url, url, name)) output.append('Lookup' % settings.ADMIN_MEDIA_PREFIX) - return u''.join(output) + return mark_safe(u''.join(output)) #if self.change: # TODO #output.append(' TODO') @@ -148,7 +149,7 @@ class RelatedFieldWidgetWrapper(object): output.append(u' ' % \ (related_url, name)) output.append(u'Add Another' % settings.ADMIN_MEDIA_PREFIX) - return u''.join(output) + return mark_safe(u''.join(output)) def __deepcopy__(self, memo): # There's no reason to deepcopy admin_site, etc, so just return self.