Fixed #19577 - Added HTML escaping to admin examples.

Thanks foo@ for the report and Florian Apolloner for the review.
This commit is contained in:
Tim Graham 2013-01-25 06:53:40 -05:00
parent 1f6b2e7a65
commit eafc036476
3 changed files with 42 additions and 8 deletions

View File

@ -87,8 +87,8 @@ def format_html(format_string, *args, **kwargs):
def format_html_join(sep, format_string, args_generator): def format_html_join(sep, format_string, args_generator):
""" """
A wrapper format_html, for the common case of a group of arguments that need A wrapper of format_html, for the common case of a group of arguments that
to be formatted using the same format string, and then joined using need to be formatted using the same format string, and then joined using
'sep'. 'sep' is also passed through conditional_escape. 'sep'. 'sep' is also passed through conditional_escape.
'args_generator' should be an iterator that returns the sequence of 'args' 'args_generator' should be an iterator that returns the sequence of 'args'

View File

@ -449,17 +449,25 @@ subclass::
* If the string given is a method of the model, ``ModelAdmin`` or a * If the string given is a method of the model, ``ModelAdmin`` or a
callable, Django will HTML-escape the output by default. If you'd callable, Django will HTML-escape the output by default. If you'd
rather not escape the output of the method, give the method an rather not escape the output of the method, give the method an
``allow_tags`` attribute whose value is ``True``. ``allow_tags`` attribute whose value is ``True``. However, to avoid an
XSS vulnerability, you should use :func:`~django.utils.html.format_html`
to escape user-provided inputs.
Here's a full example model:: Here's a full example model::
from django.utils.html import format_html
class Person(models.Model): class Person(models.Model):
first_name = models.CharField(max_length=50) first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50) last_name = models.CharField(max_length=50)
color_code = models.CharField(max_length=6) color_code = models.CharField(max_length=6)
def colored_name(self): def colored_name(self):
return '<span style="color: #%s;">%s %s</span>' % (self.color_code, self.first_name, self.last_name) return format_html('<span style="color: #{0};">{1} {2}</span>',
self.color_code,
self.first_name,
self.last_name)
colored_name.allow_tags = True colored_name.allow_tags = True
class PersonAdmin(admin.ModelAdmin): class PersonAdmin(admin.ModelAdmin):
@ -500,12 +508,17 @@ subclass::
For example:: For example::
from django.utils.html import format_html
class Person(models.Model): class Person(models.Model):
first_name = models.CharField(max_length=50) first_name = models.CharField(max_length=50)
color_code = models.CharField(max_length=6) color_code = models.CharField(max_length=6)
def colored_first_name(self): def colored_first_name(self):
return '<span style="color: #%s;">%s</span>' % (self.color_code, self.first_name) return format_html('<span style="color: #{0};">{1}</span>',
self.color_code,
self.first_name)
colored_first_name.allow_tags = True colored_first_name.allow_tags = True
colored_first_name.admin_order_field = 'first_name' colored_first_name.admin_order_field = 'first_name'
@ -817,19 +830,27 @@ subclass::
the admin interface to provide feedback on the status of the objects being the admin interface to provide feedback on the status of the objects being
edited, for example:: edited, for example::
from django.utils.html import format_html_join
from django.utils.safestring import mark_safe
class PersonAdmin(ModelAdmin): class PersonAdmin(ModelAdmin):
readonly_fields = ('address_report',) readonly_fields = ('address_report',)
def address_report(self, instance): def address_report(self, instance):
return ", ".join(instance.get_full_address()) or \ # assuming get_full_address() returns a list of strings
"<span class='errors'>I can't determine this address.</span>" # for each line of the address and you want to separate each
# line by a linebreak
return format_html_join(
mark_safe('<br/>'),
'{0}',
((line,) for line in instance.get_full_address()),
) or "<span class='errors'>I can't determine this address.</span>"
# short_description functions like a model field's verbose_name # short_description functions like a model field's verbose_name
address_report.short_description = "Address" address_report.short_description = "Address"
# in this example, we have used HTML tags in the output # in this example, we have used HTML tags in the output
address_report.allow_tags = True address_report.allow_tags = True
.. attribute:: ModelAdmin.save_as .. attribute:: ModelAdmin.save_as
Set ``save_as`` to enable a "save as" feature on admin change forms. Set ``save_as`` to enable a "save as" feature on admin change forms.

View File

@ -541,6 +541,19 @@ escaping HTML.
through :func:`conditional_escape` which (ultimately) calls through :func:`conditional_escape` which (ultimately) calls
:func:`~django.utils.encoding.force_text` on the values. :func:`~django.utils.encoding.force_text` on the values.
.. function:: format_html_join(sep, format_string, args_generator)
A wrapper of :func:`format_html`, for the common case of a group of
arguments that need to be formatted using the same format string, and then
joined using ``sep``. ``sep`` is also passed through
:func:`conditional_escape`.
``args_generator`` should be an iterator that returns the sequence of
``args`` that will be passed to :func:`format_html`. For example::
format_html_join('\n', "<li>{0} {1}</li>", ((u.first_name, u.last_name)
for u in users))
.. function:: strip_tags(value) .. function:: strip_tags(value)
Removes anything that looks like an html tag from the string, that is Removes anything that looks like an html tag from the string, that is