diff options
| author | Tim Graham <timograham@gmail.com> | 2013-01-25 06:53:40 -0500 |
|---|---|---|
| committer | Tim Graham <timograham@gmail.com> | 2013-01-25 06:56:38 -0500 |
| commit | 42fcfcaa529dac1fe3066797d7e4ab7aa6f6cdf3 (patch) | |
| tree | 26266b7080f945895af14beb027f352cc184fa63 /docs | |
| parent | d571894fc09b34b8b43cb8f1790c743a47679851 (diff) | |
[1.5.x] Fixed #19577 - Added HTML escaping to admin examples.
Thanks foo@ for the report and Florian Apolloner for the review.
Backport of eafc036476 from master
Diffstat (limited to 'docs')
| -rw-r--r-- | docs/ref/contrib/admin/index.txt | 33 | ||||
| -rw-r--r-- | docs/ref/utils.txt | 13 |
2 files changed, 40 insertions, 6 deletions
diff --git a/docs/ref/contrib/admin/index.txt b/docs/ref/contrib/admin/index.txt index 27ecdaa9e5..757b387d78 100644 --- a/docs/ref/contrib/admin/index.txt +++ b/docs/ref/contrib/admin/index.txt @@ -451,17 +451,25 @@ subclass:: * 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 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:: + from django.utils.html import format_html + class Person(models.Model): first_name = models.CharField(max_length=50) last_name = models.CharField(max_length=50) color_code = models.CharField(max_length=6) 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 class PersonAdmin(admin.ModelAdmin): @@ -502,12 +510,17 @@ subclass:: For example:: + from django.utils.html import format_html + class Person(models.Model): first_name = models.CharField(max_length=50) color_code = models.CharField(max_length=6) 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.admin_order_field = 'first_name' @@ -833,19 +846,27 @@ subclass:: the admin interface to provide feedback on the status of the objects being edited, for example:: + from django.utils.html import format_html_join + from django.utils.safestring import mark_safe + class PersonAdmin(ModelAdmin): readonly_fields = ('address_report',) def address_report(self, instance): - return ", ".join(instance.get_full_address()) or \ - "<span class='errors'>I can't determine this address.</span>" + # assuming get_full_address() returns a list of strings + # 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 address_report.short_description = "Address" # in this example, we have used HTML tags in the output address_report.allow_tags = True - .. attribute:: ModelAdmin.save_as Set ``save_as`` to enable a "save as" feature on admin change forms. diff --git a/docs/ref/utils.txt b/docs/ref/utils.txt index 9d3e000e03..35d76531a7 100644 --- a/docs/ref/utils.txt +++ b/docs/ref/utils.txt @@ -543,6 +543,19 @@ escaping HTML. through :func:`conditional_escape` which (ultimately) calls :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) Removes anything that looks like an html tag from the string, that is |
