diff --git a/django/utils/html.py b/django/utils/html.py
index 25605be..ec7b28d 100644
a
|
b
|
def format_html(format_string, *args, **kwargs):
|
87 | 87 | |
88 | 88 | def format_html_join(sep, format_string, args_generator): |
89 | 89 | """ |
90 | | A wrapper format_html, for the common case of a group of arguments that need |
91 | | to be formatted using the same format string, and then joined using |
| 90 | A wrapper of format_html, for the common case of a group of arguments that |
| 91 | need to be formatted using the same format string, and then joined using |
92 | 92 | 'sep'. 'sep' is also passed through conditional_escape. |
93 | 93 | |
94 | 94 | 'args_generator' should be an iterator that returns the sequence of 'args' |
diff --git a/docs/ref/contrib/admin/index.txt b/docs/ref/contrib/admin/index.txt
index ee04d77..a862d55 100644
a
|
b
|
subclass::
|
449 | 449 | * If the string given is a method of the model, ``ModelAdmin`` or a |
450 | 450 | callable, Django will HTML-escape the output by default. If you'd |
451 | 451 | rather not escape the output of the method, give the method an |
452 | | ``allow_tags`` attribute whose value is ``True``. |
| 452 | ``allow_tags`` attribute whose value is ``True``. However, to avoid an |
| 453 | XSS vulnerability, you should use :func:`~django.utils.html.format_html` |
| 454 | to escape user-provided inputs. |
453 | 455 | |
454 | 456 | Here's a full example model:: |
455 | 457 | |
| 458 | from django.utils.html import format_html |
| 459 | |
456 | 460 | class Person(models.Model): |
457 | 461 | first_name = models.CharField(max_length=50) |
458 | 462 | last_name = models.CharField(max_length=50) |
459 | 463 | color_code = models.CharField(max_length=6) |
460 | 464 | |
461 | 465 | def colored_name(self): |
462 | | return '<span style="color: #%s;">%s %s</span>' % (self.color_code, self.first_name, self.last_name) |
| 466 | return format_html('<span style="color: #{0};">{1} {2}</span>', |
| 467 | self.color_code, |
| 468 | self.first_name, |
| 469 | self.last_name) |
| 470 | |
463 | 471 | colored_name.allow_tags = True |
464 | 472 | |
465 | 473 | class PersonAdmin(admin.ModelAdmin): |
… |
… |
subclass::
|
500 | 508 | |
501 | 509 | For example:: |
502 | 510 | |
| 511 | from django.utils.html import format_html |
| 512 | |
503 | 513 | class Person(models.Model): |
504 | 514 | first_name = models.CharField(max_length=50) |
505 | 515 | color_code = models.CharField(max_length=6) |
506 | 516 | |
507 | 517 | def colored_first_name(self): |
508 | | return '<span style="color: #%s;">%s</span>' % (self.color_code, self.first_name) |
| 518 | return format_html('<span style="color: #{0};">{1}</span>', |
| 519 | self.color_code, |
| 520 | self.first_name) |
| 521 | |
509 | 522 | colored_first_name.allow_tags = True |
510 | 523 | colored_first_name.admin_order_field = 'first_name' |
511 | 524 | |
… |
… |
subclass::
|
817 | 830 | the admin interface to provide feedback on the status of the objects being |
818 | 831 | edited, for example:: |
819 | 832 | |
| 833 | from django.utils.html import format_html_join |
| 834 | from django.utils.safestring import mark_safe |
| 835 | |
820 | 836 | class PersonAdmin(ModelAdmin): |
821 | 837 | readonly_fields = ('address_report',) |
822 | 838 | |
823 | 839 | def address_report(self, instance): |
824 | | return ", ".join(instance.get_full_address()) or \ |
825 | | "<span class='errors'>I can't determine this address.</span>" |
| 840 | # assuming get_full_address() returns a list of strings |
| 841 | # for each line of the address and you want to separate each |
| 842 | # line by a linebreak |
| 843 | return format_html_join( |
| 844 | mark_safe('<br/>'), |
| 845 | '{0}', |
| 846 | ((line,) for line in instance.get_full_address()), |
| 847 | ) or "<span class='errors'>I can't determine this address.</span>" |
826 | 848 | |
827 | 849 | # short_description functions like a model field's verbose_name |
828 | 850 | address_report.short_description = "Address" |
829 | 851 | # in this example, we have used HTML tags in the output |
830 | 852 | address_report.allow_tags = True |
831 | 853 | |
832 | | |
833 | 854 | .. attribute:: ModelAdmin.save_as |
834 | 855 | |
835 | 856 | 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 20192ed..2dc007f 100644
a
|
b
|
escaping HTML.
|
541 | 541 | through :func:`conditional_escape` which (ultimately) calls |
542 | 542 | :func:`~django.utils.encoding.force_text` on the values. |
543 | 543 | |
| 544 | .. function:: format_html_join(sep, format_string, args_generator) |
| 545 | |
| 546 | A wrapper of :func:`format_html`, for the common case of a group of |
| 547 | arguments that need to be formatted using the same format string, and then |
| 548 | joined using ``sep``. ``sep`` is also passed through |
| 549 | :func:`conditional_escape`. |
| 550 | |
| 551 | ``args_generator`` should be an iterator that returns the sequence of |
| 552 | ``args`` that will be passed to :func:`format_html`. For example:: |
| 553 | |
| 554 | format_html_join('\n', "<li>{0} {1}</li>", ((u.first_name, u.last_name) |
| 555 | for u in users)) |
| 556 | |
| 557 | |
544 | 558 | .. function:: strip_tags(value) |
545 | 559 | |
546 | 560 | Removes anything that looks like an html tag from the string, that is |