Ticket #17135: 17135.3.patch
File 17135.3.patch, 30.0 KB (added by , 13 years ago) |
---|
-
docs/internals/deprecation.txt
251 251 :mod:`django.core.management`. This also means that the old (pre-1.4) 252 252 style of :file:`manage.py` file will no longer work. 253 253 254 * Setting the ``is_safe`` and ``needs_autoescape`` flags as attributes of 255 template filter functions will no longer be supported. 256 254 257 2.0 255 258 --- 256 259 -
docs/howto/custom-template-tags.txt
206 206 1. Your filter does not introduce any HTML-unsafe characters (``<``, ``>``, 207 207 ``'``, ``"`` or ``&``) into the result that were not already present. In 208 208 this case, you can let Django take care of all the auto-escaping 209 handling for you. All you need to do is put the ``is_safe`` attribute on210 your filter function and set it to ``True``, like so:209 handling for you. All you need to do is set the ``is_safe`` flag to ``True`` 210 when you register your filter function, like so: 211 211 212 212 .. code-block:: python 213 213 214 @register.filter 214 @register.filter(is_safe=True) 215 215 def myfilter(value): 216 216 return value 217 myfilter.is_safe = True218 217 219 218 This attribute tells Django that if a "safe" string is passed into your 220 219 filter, the result will still be "safe" and if a non-safe string is … … 236 235 237 236 .. code-block:: python 238 237 239 @register.filter 238 @register.filter(is_safe=True) 240 239 def add_xx(value): 241 240 return '%sxx' % value 242 add_xx.is_safe = True243 241 244 242 When this filter is used in a template where auto-escaping is enabled, 245 243 Django will escape the output whenever the input is not already marked 246 244 as "safe". 247 245 248 By default, ``is_safe`` defaults to ``False``, and you can omit it from249 any filterswhere it isn't required.246 By default, ``is_safe`` is ``False``, and you can omit it from any filters 247 where it isn't required. 250 248 251 249 Be careful when deciding if your filter really does leave safe strings 252 250 as safe. If you're *removing* characters, you might inadvertently leave … … 279 277 can operate in templates where auto-escaping is either on or off in 280 278 order to make things easier for your template authors. 281 279 282 In order for your filter to know the current auto-escaping state, set 283 the ``needs_autoescape`` attribute to ``True`` on your function. (If you284 don't specify this attribute, it defaults to ``False``). This attribute285 tells Django that your filter function wants to be passed an extra286 keyword argument, called ``autoescape``, that is ``True`` if287 auto-escaping is ineffect and ``False`` otherwise.280 In order for your filter to know the current auto-escaping state, set the 281 ``needs_autoescape`` flag to ``True`` when you register your filter function. 282 (If you don't specify this flag, it defaults to ``False``). This flag tells 283 Django that your filter function wants to be passed an extra keyword 284 argument, called ``autoescape``, that is ``True`` if auto-escaping is in 285 effect and ``False`` otherwise. 288 286 289 287 For example, let's write a filter that emphasizes the first character of 290 288 a string: … … 294 292 from django.utils.html import conditional_escape 295 293 from django.utils.safestring import mark_safe 296 294 295 @register.filter(needs_autoescape=True) 297 296 def initial_letter_filter(text, autoescape=None): 298 297 first, other = text[0], text[1:] 299 298 if autoescape: … … 302 301 esc = lambda x: x 303 302 result = '<strong>%s</strong>%s' % (esc(first), esc(other)) 304 303 return mark_safe(result) 305 initial_letter_filter.needs_autoescape = True306 304 307 The ``needs_autoescape`` attribute on the filter function and the 308 ``autoescape`` keyword argument mean that our function will know whether 309 automatic escaping is in effect when the filter is called. We use 310 ``autoescape`` to decide whether the input data needs to be passed 311 through ``django.utils.html.conditional_escape`` or not. (In the latter 312 case, we just use the identity function as the "escape" function.) The 313 ``conditional_escape()`` function is like ``escape()`` except it only 314 escapes input that is **not** a ``SafeData`` instance. If a ``SafeData`` 315 instance is passed to ``conditional_escape()``, the data is returned 316 unchanged. 305 The ``needs_autoescape`` flag and the ``autoescape`` keyword argument mean 306 that our function will know whether automatic escaping is in effect when the 307 filter is called. We use ``autoescape`` to decide whether the input data 308 needs to be passed through ``django.utils.html.conditional_escape`` or not. 309 (In the latter case, we just use the identity function as the "escape" 310 function.) The ``conditional_escape()`` function is like ``escape()`` except 311 it only escapes input that is **not** a ``SafeData`` instance. If a 312 ``SafeData`` instance is passed to ``conditional_escape()``, the data is 313 returned unchanged. 317 314 318 315 Finally, in the above example, we remember to mark the result as safe 319 316 so that our HTML is inserted directly into the template without further … … 324 321 handle the auto-escaping issues and return a safe string, the 325 322 ``is_safe`` attribute won't change anything either way. 326 323 324 .. versionchanged:: 1.4 325 326 ``is_safe`` and ``needs_autoescape`` used to be attributes of the filter 327 function: 328 329 .. code-block:: python 330 331 @register.filter 332 def myfilter(value): 333 return value 334 myfilter.is_safe = True 335 336 .. code-block:: python 337 338 @register.filter 339 def initial_letter_filter(text, autoescape=None): 340 # ... 341 return mark_safe(result) 342 initial_letter_filter.needs_autoescape = True 343 344 This syntax is deprecated. 345 327 346 Writing custom template tags 328 347 ---------------------------- 329 348 -
tests/regressiontests/templates/templatetags/custom.py
6 6 7 7 register = template.Library() 8 8 9 @register.filter 10 @stringfilter 9 11 def trim(value, num): 10 12 return value[:num] 11 trim = stringfilter(trim)12 13 13 register.filter(trim)14 15 14 @register.simple_tag 16 15 def no_params(): 17 16 """Expected no_params __doc__""" -
django/templatetags/l10n.py
5 5 6 6 register = Library() 7 7 8 @register.filter 8 @register.filter(is_safe=False) 9 9 def localize(value): 10 10 """ 11 11 Forces a value to be rendered as a localized value, 12 12 regardless of the value of ``settings.USE_L10N``. 13 13 """ 14 14 return force_unicode(formats.localize(value, use_l10n=True)) 15 localize.is_safe = False16 15 17 @register.filter 16 @register.filter(is_safe=False) 18 17 def unlocalize(value): 19 18 """ 20 19 Forces a value to be rendered as a non-localized value, 21 20 regardless of the value of ``settings.USE_L10N``. 22 21 """ 23 22 return force_unicode(value) 24 unlocalize.is_safe = False25 23 26 24 class LocalizeNode(Node): 27 25 def __init__(self, nodelist, use_l10n): -
django/contrib/humanize/templatetags/humanize.py
11 11 12 12 register = template.Library() 13 13 14 @register.filter 14 @register.filter(is_safe=True) 15 15 def ordinal(value): 16 16 """ 17 17 Converts an integer to its ordinal as a string. 1 is '1st', 2 is '2nd', … … 25 25 if value % 100 in (11, 12, 13): # special case 26 26 return u"%d%s" % (value, suffixes[0]) 27 27 return u"%d%s" % (value, suffixes[value % 10]) 28 ordinal.is_safe = True29 28 30 @register.filter 29 @register.filter(is_safe=True) 31 30 def intcomma(value, use_l10n=True): 32 31 """ 33 32 Converts an integer to a string containing commas every three digits. … … 47 46 return new 48 47 else: 49 48 return intcomma(new, use_l10n) 50 intcomma.is_safe = True51 49 52 50 # A tuple of standard large number to their converters 53 51 intword_converters = ( … … 97 95 )), 98 96 ) 99 97 100 @register.filter 98 @register.filter(is_safe=False) 101 99 def intword(value): 102 100 """ 103 101 Converts a large integer to a friendly text representation. Works best … … 129 127 new_value = value / float(large_number) 130 128 return _check_for_i18n(new_value, *converters(new_value)) 131 129 return value 132 intword.is_safe = False133 130 134 @register.filter 131 @register.filter(is_safe=True) 135 132 def apnumber(value): 136 133 """ 137 134 For numbers 1-9, returns the number spelled out. Otherwise, returns the … … 144 141 if not 0 < value < 10: 145 142 return value 146 143 return (_('one'), _('two'), _('three'), _('four'), _('five'), _('six'), _('seven'), _('eight'), _('nine'))[value-1] 147 apnumber.is_safe = True148 144 149 145 @register.filter 150 146 def naturalday(value, arg=None): -
django/contrib/markup/templatetags/markup.py
18 18 19 19 register = template.Library() 20 20 21 @register.filter 21 @register.filter(is_safe=True) 22 22 def textile(value): 23 23 try: 24 24 import textile … … 28 28 return force_unicode(value) 29 29 else: 30 30 return mark_safe(force_unicode(textile.textile(smart_str(value), encoding='utf-8', output='utf-8'))) 31 textile.is_safe = True32 31 33 @register.filter 32 @register.filter(is_safe=True) 34 33 def markdown(value, arg=''): 35 34 """ 36 35 Runs Markdown over a given value, optionally using various … … 73 72 return mark_safe(markdown.markdown(force_unicode(value), extensions, safe_mode=safe_mode)) 74 73 else: 75 74 return mark_safe(force_unicode(markdown.markdown(smart_str(value)))) 76 markdown.is_safe = True77 75 78 @register.filter 76 @register.filter(is_safe=True) 79 77 def restructuredtext(value): 80 78 try: 81 79 from docutils.core import publish_parts … … 87 85 docutils_settings = getattr(settings, "RESTRUCTUREDTEXT_FILTER_SETTINGS", {}) 88 86 parts = publish_parts(source=smart_str(value), writer_name="html4css1", settings_overrides=docutils_settings) 89 87 return mark_safe(force_unicode(parts["fragment"])) 90 restructuredtext.is_safe = True91 -
django/template/base.py
1057 1057 self.tags[getattr(func, "_decorated_function", func).__name__] = func 1058 1058 return func 1059 1059 1060 def filter(self, name=None, filter_func=None ):1060 def filter(self, name=None, filter_func=None, **flags): 1061 1061 if name is None and filter_func is None: 1062 1062 # @register.filter() 1063 return self.filter_function 1064 elif filter_func is None: 1063 def dec(func): 1064 return self.filter_function(func, **flags) 1065 return dec 1066 1067 elif name is not None and filter_func is None: 1065 1068 if callable(name): 1066 1069 # @register.filter 1067 return self.filter_function(name )1070 return self.filter_function(name, **flags) 1068 1071 else: 1069 1072 # @register.filter('somename') or @register.filter(name='somename') 1070 1073 def dec(func): 1071 return self.filter(name, func )1074 return self.filter(name, func, **flags) 1072 1075 return dec 1076 1073 1077 elif name is not None and filter_func is not None: 1074 1078 # register.filter('somename', somefunc) 1075 1079 self.filters[name] = filter_func 1080 for attr in ('is_safe', 'needs_autoescape'): 1081 if attr in flags: 1082 value = flags[attr] 1083 setattr(filter_func, attr, value) 1084 if hasattr(filter_func, "_decorated_function"): 1085 setattr(filter_func._decorated_function, attr, value) 1076 1086 return filter_func 1077 1087 else: 1078 1088 raise InvalidTemplateLibrary("Unsupported arguments to " 1079 1089 "Library.filter: (%r, %r)", (name, filter_func)) 1080 1090 1081 def filter_function(self, func ):1082 self.filters[getattr(func, "_decorated_function", func).__name__] = func1083 return func1091 def filter_function(self, func, **flags): 1092 name = getattr(func, "_decorated_function", func).__name__ 1093 return self.filter(name, func, **flags) 1084 1094 1085 1095 def simple_tag(self, func=None, takes_context=None, name=None): 1086 1096 def dec(func): -
django/template/defaultfilters.py
37 37 if args: 38 38 args = list(args) 39 39 args[0] = force_unicode(args[0]) 40 if isinstance(args[0], SafeData) and getattr(func, 'is_safe', False): 40 if (isinstance(args[0], SafeData) and 41 getattr(_dec._decorated_function, 'is_safe', False)): 41 42 return mark_safe(func(*args, **kwargs)) 42 43 return func(*args, **kwargs) 43 44 … … 46 47 _dec._decorated_function = getattr(func, '_decorated_function', func) 47 48 for attr in ('is_safe', 'needs_autoescape'): 48 49 if hasattr(func, attr): 50 import warnings 51 warnings.warn("Setting the %s attribute of a template filter " 52 "function is deprecated; use @register.filter(%s=%s) " 53 "instead" % (attr, attr, getattr(func, attr)), 54 PendingDeprecationWarning) 49 55 setattr(_dec, attr, getattr(func, attr)) 50 56 return wraps(func)(_dec) 51 57 … … 53 59 # STRINGS # 54 60 ################### 55 61 56 @register.filter 62 @register.filter(is_safe=True) 57 63 @stringfilter 58 64 def addslashes(value): 59 65 """ … … 62 68 filter instead. 63 69 """ 64 70 return value.replace('\\', '\\\\').replace('"', '\\"').replace("'", "\\'") 65 addslashes.is_safe = True66 71 67 @register.filter 72 @register.filter(is_safe=True) 68 73 @stringfilter 69 74 def capfirst(value): 70 75 """Capitalizes the first character of the value.""" 71 76 return value and value[0].upper() + value[1:] 72 capfirst.is_safe = True73 77 74 78 @register.filter("escapejs") 75 79 @stringfilter … … 77 81 """Hex encodes characters for use in JavaScript strings.""" 78 82 return escapejs(value) 79 83 80 @register.filter("fix_ampersands" )84 @register.filter("fix_ampersands", is_safe=True) 81 85 @stringfilter 82 86 def fix_ampersands_filter(value): 83 87 """Replaces ampersands with ``&`` entities.""" 84 88 return fix_ampersands(value) 85 fix_ampersands_filter.is_safe = True86 89 87 90 # Values for testing floatformat input against infinity and NaN representations, 88 91 # which differ across platforms and Python versions. Some (i.e. old Windows … … 96 99 nan = (1e200 * 1e200) // (1e200 * 1e200) 97 100 special_floats = [str(pos_inf), str(neg_inf), str(nan)] 98 101 99 @register.filter 102 @register.filter(is_safe=True) 100 103 def floatformat(text, arg=-1): 101 104 """ 102 105 Displays a float to a specified number of decimal places. … … 172 175 return mark_safe(formats.number_format(number, abs(p))) 173 176 except InvalidOperation: 174 177 return input_val 175 floatformat.is_safe = True176 178 177 @register.filter 179 @register.filter(is_safe=True) 178 180 @stringfilter 179 181 def iriencode(value): 180 182 """Escapes an IRI value for use in a URL.""" 181 183 return force_unicode(iri_to_uri(value)) 182 iriencode.is_safe = True183 184 184 @register.filter 185 @register.filter(is_safe=True, needs_autoescape=True) 185 186 @stringfilter 186 187 def linenumbers(value, autoescape=None): 187 188 """Displays text with line numbers.""" … … 196 197 for i, line in enumerate(lines): 197 198 lines[i] = (u"%0" + width + u"d. %s") % (i + 1, escape(line)) 198 199 return mark_safe(u'\n'.join(lines)) 199 linenumbers.is_safe = True200 linenumbers.needs_autoescape = True201 200 202 @register.filter 201 @register.filter(is_safe=True) 203 202 @stringfilter 204 203 def lower(value): 205 204 """Converts a string into all lowercase.""" 206 205 return value.lower() 207 lower.is_safe = True208 206 209 @register.filter 207 @register.filter(is_safe=False) 210 208 @stringfilter 211 209 def make_list(value): 212 210 """ … … 216 214 For a string, it's a list of characters. 217 215 """ 218 216 return list(value) 219 make_list.is_safe = False220 217 221 @register.filter 218 @register.filter(is_safe=True) 222 219 @stringfilter 223 220 def slugify(value): 224 221 """ … … 228 225 value = unicodedata.normalize('NFKD', value).encode('ascii', 'ignore') 229 226 value = unicode(re.sub('[^\w\s-]', '', value).strip().lower()) 230 227 return mark_safe(re.sub('[-\s]+', '-', value)) 231 slugify.is_safe = True232 228 233 @register.filter 229 @register.filter(is_safe=True) 234 230 def stringformat(value, arg): 235 231 """ 236 232 Formats the variable according to the arg, a string formatting specifier. … … 245 241 return (u"%" + unicode(arg)) % value 246 242 except (ValueError, TypeError): 247 243 return u"" 248 stringformat.is_safe = True249 244 250 @register.filter 245 @register.filter(is_safe=True) 251 246 @stringfilter 252 247 def title(value): 253 248 """Converts a string into titlecase.""" 254 249 t = re.sub("([a-z])'([A-Z])", lambda m: m.group(0).lower(), value.title()) 255 250 return re.sub("\d([A-Z])", lambda m: m.group(0).lower(), t) 256 title.is_safe = True257 251 258 @register.filter 252 @register.filter(is_safe=True) 259 253 @stringfilter 260 254 def truncatechars(value, arg): 261 255 """ … … 268 262 except ValueError: # Invalid literal for int(). 269 263 return value # Fail silently. 270 264 return Truncator(value).chars(length) 271 truncatechars.is_safe = True272 265 273 @register.filter 266 @register.filter(is_safe=True) 274 267 @stringfilter 275 268 def truncatewords(value, arg): 276 269 """ … … 285 278 except ValueError: # Invalid literal for int(). 286 279 return value # Fail silently. 287 280 return Truncator(value).words(length, truncate=' ...') 288 truncatewords.is_safe = True289 281 290 @register.filter 282 @register.filter(is_safe=True) 291 283 @stringfilter 292 284 def truncatewords_html(value, arg): 293 285 """ … … 302 294 except ValueError: # invalid literal for int() 303 295 return value # Fail silently. 304 296 return Truncator(value).words(length, html=True, truncate=' ...') 305 truncatewords_html.is_safe = True306 297 307 @register.filter 298 @register.filter(is_safe=False) 308 299 @stringfilter 309 300 def upper(value): 310 301 """Converts a string into all uppercase.""" 311 302 return value.upper() 312 upper.is_safe = False313 303 314 @register.filter 304 @register.filter(is_safe=False) 315 305 @stringfilter 316 306 def urlencode(value, safe=None): 317 307 """ … … 326 316 if safe is not None: 327 317 kwargs['safe'] = safe 328 318 return urlquote(value, **kwargs) 329 urlencode.is_safe = False330 319 331 @register.filter 320 @register.filter(is_safe=True, needs_autoescape=True) 332 321 @stringfilter 333 322 def urlize(value, autoescape=None): 334 323 """Converts URLs in plain text into clickable links.""" 335 324 return mark_safe(urlize_impl(value, nofollow=True, autoescape=autoescape)) 336 urlize.is_safe = True337 urlize.needs_autoescape = True338 325 339 @register.filter 326 @register.filter(is_safe=True, needs_autoescape=True) 340 327 @stringfilter 341 328 def urlizetrunc(value, limit, autoescape=None): 342 329 """ … … 347 334 """ 348 335 return mark_safe(urlize_impl(value, trim_url_limit=int(limit), nofollow=True, 349 336 autoescape=autoescape)) 350 urlizetrunc.is_safe = True351 urlizetrunc.needs_autoescape = True352 337 353 @register.filter 338 @register.filter(is_safe=False) 354 339 @stringfilter 355 340 def wordcount(value): 356 341 """Returns the number of words.""" 357 342 return len(value.split()) 358 wordcount.is_safe = False359 343 360 @register.filter 344 @register.filter(is_safe=True) 361 345 @stringfilter 362 346 def wordwrap(value, arg): 363 347 """ … … 366 350 Argument: number of characters to wrap the text at. 367 351 """ 368 352 return wrap(value, int(arg)) 369 wordwrap.is_safe = True370 353 371 @register.filter 354 @register.filter(is_safe=True) 372 355 @stringfilter 373 356 def ljust(value, arg): 374 357 """ … … 377 360 Argument: field size. 378 361 """ 379 362 return value.ljust(int(arg)) 380 ljust.is_safe = True381 363 382 @register.filter 364 @register.filter(is_safe=True) 383 365 @stringfilter 384 366 def rjust(value, arg): 385 367 """ … … 388 370 Argument: field size. 389 371 """ 390 372 return value.rjust(int(arg)) 391 rjust.is_safe = True392 373 393 @register.filter 374 @register.filter(is_safe=True) 394 375 @stringfilter 395 376 def center(value, arg): 396 377 """Centers the value in a field of a given width.""" 397 378 return value.center(int(arg)) 398 center.is_safe = True399 379 400 380 @register.filter 401 381 @stringfilter … … 413 393 # HTML STRINGS # 414 394 ################### 415 395 416 @register.filter("escape" )396 @register.filter("escape", is_safe=True) 417 397 @stringfilter 418 398 def escape_filter(value): 419 399 """ 420 400 Marks the value as a string that should not be auto-escaped. 421 401 """ 422 402 return mark_for_escaping(value) 423 escape_filter.is_safe = True424 403 425 @register.filter 404 @register.filter(is_safe=True) 426 405 @stringfilter 427 406 def force_escape(value): 428 407 """ … … 431 410 possible escaping). 432 411 """ 433 412 return mark_safe(escape(value)) 434 force_escape.is_safe = True435 413 436 @register.filter("linebreaks" )414 @register.filter("linebreaks", is_safe=True, needs_autoescape=True) 437 415 @stringfilter 438 416 def linebreaks_filter(value, autoescape=None): 439 417 """ … … 443 421 """ 444 422 autoescape = autoescape and not isinstance(value, SafeData) 445 423 return mark_safe(linebreaks(value, autoescape)) 446 linebreaks_filter.is_safe = True447 linebreaks_filter.needs_autoescape = True448 424 449 @register.filter 425 @register.filter(is_safe=True, needs_autoescape=True) 450 426 @stringfilter 451 427 def linebreaksbr(value, autoescape=None): 452 428 """ … … 458 434 if autoescape: 459 435 value = escape(value) 460 436 return mark_safe(value.replace('\n', '<br />')) 461 linebreaksbr.is_safe = True462 linebreaksbr.needs_autoescape = True463 437 464 @register.filter 438 @register.filter(is_safe=True) 465 439 @stringfilter 466 440 def safe(value): 467 441 """ 468 442 Marks the value as a string that should not be auto-escaped. 469 443 """ 470 444 return mark_safe(value) 471 safe.is_safe = True472 445 473 @register.filter 446 @register.filter(is_safe=True) 474 447 def safeseq(value): 475 448 """ 476 449 A "safe" filter for sequences. Marks each element in the sequence, … … 478 451 with the results. 479 452 """ 480 453 return [mark_safe(force_unicode(obj)) for obj in value] 481 safeseq.is_safe = True482 454 483 @register.filter 455 @register.filter(is_safe=True) 484 456 @stringfilter 485 457 def removetags(value, tags): 486 458 """Removes a space separated list of [X]HTML tags from the output.""" … … 491 463 value = starttag_re.sub(u'', value) 492 464 value = endtag_re.sub(u'', value) 493 465 return value 494 removetags.is_safe = True495 466 496 @register.filter 467 @register.filter(is_safe=True) 497 468 @stringfilter 498 469 def striptags(value): 499 470 """Strips all [X]HTML tags.""" 500 471 return strip_tags(value) 501 striptags.is_safe = True502 472 503 473 ################### 504 474 # LISTS # 505 475 ################### 506 476 507 @register.filter 477 @register.filter(is_safe=False) 508 478 def dictsort(value, arg): 509 479 """ 510 480 Takes a list of dicts, returns that list sorted by the property given in 511 481 the argument. 512 482 """ 513 483 return sorted(value, key=Variable(arg).resolve) 514 dictsort.is_safe = False515 484 516 @register.filter 485 @register.filter(is_safe=False) 517 486 def dictsortreversed(value, arg): 518 487 """ 519 488 Takes a list of dicts, returns that list sorted in reverse order by the 520 489 property given in the argument. 521 490 """ 522 491 return sorted(value, key=Variable(arg).resolve, reverse=True) 523 dictsortreversed.is_safe = False524 492 525 @register.filter 493 @register.filter(is_safe=False) 526 494 def first(value): 527 495 """Returns the first item in a list.""" 528 496 try: 529 497 return value[0] 530 498 except IndexError: 531 499 return u'' 532 first.is_safe = False533 500 534 @register.filter 501 @register.filter(is_safe=True, needs_autoescape=True) 535 502 def join(value, arg, autoescape=None): 536 503 """ 537 504 Joins a list with a string, like Python's ``str.join(list)``. … … 544 511 except AttributeError: # fail silently but nicely 545 512 return value 546 513 return mark_safe(data) 547 join.is_safe = True548 join.needs_autoescape = True549 514 550 @register.filter 515 @register.filter(is_safe=True) 551 516 def last(value): 552 517 "Returns the last item in a list" 553 518 try: 554 519 return value[-1] 555 520 except IndexError: 556 521 return u'' 557 last.is_safe = True558 522 559 @register.filter 523 @register.filter(is_safe=True) 560 524 def length(value): 561 525 """Returns the length of the value - useful for lists.""" 562 526 try: 563 527 return len(value) 564 528 except (ValueError, TypeError): 565 529 return '' 566 length.is_safe = True567 530 568 @register.filter 531 @register.filter(is_safe=False) 569 532 def length_is(value, arg): 570 533 """Returns a boolean of whether the value's length is the argument.""" 571 534 try: 572 535 return len(value) == int(arg) 573 536 except (ValueError, TypeError): 574 537 return '' 575 length_is.is_safe = False576 538 577 @register.filter 539 @register.filter(is_safe=True) 578 540 def random(value): 579 541 """Returns a random item from the list.""" 580 542 return random_module.choice(value) 581 random.is_safe = True582 543 583 @register.filter("slice" )544 @register.filter("slice", is_safe=True) 584 545 def slice_filter(value, arg): 585 546 """ 586 547 Returns a slice of the list. … … 600 561 601 562 except (ValueError, TypeError): 602 563 return value # Fail silently. 603 slice_filter.is_safe = True604 564 605 @register.filter 565 @register.filter(is_safe=True, needs_autoescape=True) 606 566 def unordered_list(value, autoescape=None): 607 567 """ 608 568 Recursively takes a self-nested list and returns an HTML unordered list -- … … 688 648 return '\n'.join(output) 689 649 value, converted = convert_old_style_list(value) 690 650 return mark_safe(_helper(value)) 691 unordered_list.is_safe = True692 unordered_list.needs_autoescape = True693 651 694 652 ################### 695 653 # INTEGERS # 696 654 ################### 697 655 698 @register.filter 656 @register.filter(is_safe=False) 699 657 def add(value, arg): 700 658 """Adds the arg to the value.""" 701 659 try: … … 705 663 return value + arg 706 664 except Exception: 707 665 return '' 708 add.is_safe = False709 666 710 @register.filter 667 @register.filter(is_safe=False) 711 668 def get_digit(value, arg): 712 669 """ 713 670 Given a whole number, returns the requested digit of it, where 1 is the … … 726 683 return int(str(value)[-arg]) 727 684 except IndexError: 728 685 return 0 729 get_digit.is_safe = False730 686 731 687 ################### 732 688 # DATES # 733 689 ################### 734 690 735 @register.filter 691 @register.filter(is_safe=False) 736 692 def date(value, arg=None): 737 693 """Formats a date according to the given format.""" 738 694 if not value: … … 746 702 return format(value, arg) 747 703 except AttributeError: 748 704 return '' 749 date.is_safe = False750 705 751 @register.filter 706 @register.filter(is_safe=False) 752 707 def time(value, arg=None): 753 708 """Formats a time according to the given format.""" 754 709 if value in (None, u''): … … 762 717 return time_format(value, arg) 763 718 except AttributeError: 764 719 return '' 765 time.is_safe = False766 720 767 @register.filter("timesince" )721 @register.filter("timesince", is_safe=False) 768 722 def timesince_filter(value, arg=None): 769 723 """Formats a date as the time since that date (i.e. "4 days, 6 hours").""" 770 724 if not value: … … 775 729 return timesince(value) 776 730 except (ValueError, TypeError): 777 731 return u'' 778 timesince_filter.is_safe = False779 732 780 @register.filter("timeuntil" )733 @register.filter("timeuntil", is_safe=False) 781 734 def timeuntil_filter(value, arg=None): 782 735 """Formats a date as the time until that date (i.e. "4 days, 6 hours").""" 783 736 if not value: … … 786 739 return timeuntil(value, arg) 787 740 except (ValueError, TypeError): 788 741 return u'' 789 timeuntil_filter.is_safe = False790 742 791 743 ################### 792 744 # LOGIC # 793 745 ################### 794 746 795 @register.filter 747 @register.filter(is_safe=False) 796 748 def default(value, arg): 797 749 """If value is unavailable, use given default.""" 798 750 return value or arg 799 default.is_safe = False800 751 801 @register.filter 752 @register.filter(is_safe=False) 802 753 def default_if_none(value, arg): 803 754 """If value is None, use given default.""" 804 755 if value is None: 805 756 return arg 806 757 return value 807 default_if_none.is_safe = False808 758 809 @register.filter 759 @register.filter(is_safe=False) 810 760 def divisibleby(value, arg): 811 761 """Returns True if the value is devisible by the argument.""" 812 762 return int(value) % int(arg) == 0 813 divisibleby.is_safe = False814 763 815 @register.filter 764 @register.filter(is_safe=False) 816 765 def yesno(value, arg=None): 817 766 """ 818 767 Given a string mapping values for true, false and (optionally) None, … … 843 792 if value: 844 793 return yes 845 794 return no 846 yesno.is_safe = False847 795 848 796 ################### 849 797 # MISC # 850 798 ################### 851 799 852 @register.filter 800 @register.filter(is_safe=True) 853 801 def filesizeformat(bytes): 854 802 """ 855 803 Formats the value like a 'human-readable' file size (i.e. 13 KB, 4.1 MB, … … 873 821 if bytes < 1024 * 1024 * 1024 * 1024 * 1024: 874 822 return ugettext("%s TB") % filesize_number_format(bytes / (1024 * 1024 * 1024 * 1024)) 875 823 return ugettext("%s PB") % filesize_number_format(bytes / (1024 * 1024 * 1024 * 1024 * 1024)) 876 filesizeformat.is_safe = True877 824 878 @register.filter 825 @register.filter(is_safe=False) 879 826 def pluralize(value, arg=u's'): 880 827 """ 881 828 Returns a plural suffix if the value is not 1. By default, 's' is used as … … 918 865 except TypeError: # len() of unsized object. 919 866 pass 920 867 return singular_suffix 921 pluralize.is_safe = False922 868 923 @register.filter("phone2numeric" )869 @register.filter("phone2numeric", is_safe=True) 924 870 def phone2numeric_filter(value): 925 871 """Takes a phone number and converts it in to its numerical equivalent.""" 926 872 return phone2numeric(value) 927 phone2numeric_filter.is_safe = True928 873 929 @register.filter 874 @register.filter(is_safe=True) 930 875 def pprint(value): 931 876 """A wrapper around pprint.pprint -- for debugging, really.""" 932 877 try: 933 878 return pformat(value) 934 879 except Exception, e: 935 880 return u"Error in formatting: %s" % force_unicode(e, errors="replace") 936 pprint.is_safe = True