Changeset 6641
- Timestamp:
- 11/03/07 21:05:56 (1 year ago)
- Files:
-
- django/trunk/django/template/defaultfilters.py (modified) (36 diffs)
- django/trunk/django/template/defaulttags.py (modified) (45 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
django/trunk/django/template/defaultfilters.py
r6399 r6641 1 "Default variable filters" 1 """Default variable filters.""" 2 3 import re 4 import random as random_module 2 5 3 6 from django.template import Variable, Library 4 7 from django.conf import settings 5 8 from django.utils.translation import ugettext, ungettext 6 from django.utils.encoding import force_unicode, smart_str, iri_to_uri 7 import re 8 import random as random_module 9 from django.utils.encoding import force_unicode, iri_to_uri 9 10 10 11 register = Library() … … 37 38 38 39 def addslashes(value): 39 " Adds slashes - useful for passing strings to JavaScript, for example."40 """Adds slashes - useful for passing strings to JavaScript, for example.""" 40 41 return value.replace('\\', '\\\\').replace('"', '\\"').replace("'", "\\'") 41 42 addslashes = stringfilter(addslashes) 42 43 43 44 def capfirst(value): 44 " Capitalizes the first character of the value"45 """Capitalizes the first character of the value.""" 45 46 return value and value[0].upper() + value[1:] 46 47 capfirst = stringfilter(capfirst) 47 48 48 49 def fix_ampersands(value): 49 " Replaces ampersands with ``&`` entities"50 """Replaces ampersands with ``&`` entities.""" 50 51 from django.utils.html import fix_ampersands 51 52 return fix_ampersands(value) … … 87 88 88 89 def iriencode(value): 89 " Escapes an IRI value for use in a URL"90 """Escapes an IRI value for use in a URL.""" 90 91 return force_unicode(iri_to_uri(value)) 91 92 iriencode = stringfilter(iriencode) 92 93 93 94 def linenumbers(value): 94 " Displays text with line numbers"95 """Displays text with line numbers.""" 95 96 from django.utils.html import escape 96 97 lines = value.split(u'\n') 97 # Find the maximum width of the line count, for use with zero padding string format command 98 # Find the maximum width of the line count, for use with zero padding 99 # string format command. 98 100 width = unicode(len(unicode(len(lines)))) 99 101 for i, line in enumerate(lines): … … 103 105 104 106 def lower(value): 105 " Converts a string into all lowercase"107 """Converts a string into all lowercase.""" 106 108 return value.lower() 107 109 lower = stringfilter(lower) … … 109 111 def make_list(value): 110 112 """ 111 Returns the value turned into a list. For an integer, it's a list of 112 digits. For a string, it's a list of characters. 113 Returns the value turned into a list. 114 115 For an integer, it's a list of digits. 116 For a string, it's a list of characters. 113 117 """ 114 118 return list(value) … … 117 121 def slugify(value): 118 122 """ 119 Normalizes string, converts to lowercase, removes non-alpha char s and120 converts spaces to hyphens.123 Normalizes string, converts to lowercase, removes non-alpha characters, 124 and converts spaces to hyphens. 121 125 """ 122 126 import unicodedata … … 128 132 def stringformat(value, arg): 129 133 """ 130 Formats the variable according to the argument, a string formatting specifier. 134 Formats the variable according to the arg, a string formatting specifier. 135 131 136 This specifier uses Python string formating syntax, with the exception that 132 137 the leading "%" is dropped. … … 141 146 142 147 def title(value): 143 " Converts a string into titlecase"148 """Converts a string into titlecase.""" 144 149 return re.sub("([a-z])'([A-Z])", lambda m: m.group(0).lower(), value.title()) 145 150 title = stringfilter(title) … … 147 152 def truncatewords(value, arg): 148 153 """ 149 Truncates a string after a certain number of words 150 151 Argument: Number of words to truncate after 154 Truncates a string after a certain number of words. 155 156 Argument: Number of words to truncate after. 152 157 """ 153 158 from django.utils.text import truncate_words 154 159 try: 155 160 length = int(arg) 156 except ValueError: # invalid literal for int()161 except ValueError: # Invalid literal for int(). 157 162 return value # Fail silently. 158 163 return truncate_words(value, length) … … 161 166 def truncatewords_html(value, arg): 162 167 """ 163 Truncates HTML after a certain number of words 164 165 Argument: Number of words to truncate after 168 Truncates HTML after a certain number of words. 169 170 Argument: Number of words to truncate after. 166 171 """ 167 172 from django.utils.text import truncate_html_words … … 174 179 175 180 def upper(value): 176 " Converts a string into all uppercase"181 """Converts a string into all uppercase.""" 177 182 return value.upper() 178 183 upper = stringfilter(upper) 179 184 180 185 def urlencode(value): 181 " Escapes a value for use in a URL"186 """Escapes a value for use in a URL.""" 182 187 from django.utils.http import urlquote 183 188 return urlquote(value) … … 185 190 186 191 def urlize(value): 187 " Converts URLs in plain text into clickable links"192 """Converts URLs in plain text into clickable links.""" 188 193 from django.utils.html import urlize 189 194 return urlize(value, nofollow=True) … … 192 197 def urlizetrunc(value, limit): 193 198 """ 194 Converts URLs into clickable links, truncating URLs to the given character limit,195 and adding 'rel=nofollow' attribute to discourage spamming.199 Converts URLs into clickable links, truncating URLs to the given character 200 limit, and adding 'rel=nofollow' attribute to discourage spamming. 196 201 197 202 Argument: Length to truncate URLs to. … … 202 207 203 208 def wordcount(value): 204 " Returns the number of words"209 """Returns the number of words.""" 205 210 return len(value.split()) 206 211 wordcount = stringfilter(wordcount) … … 208 213 def wordwrap(value, arg): 209 214 """ 210 Wraps words at specified line length 215 Wraps words at specified line length. 211 216 212 217 Argument: number of characters to wrap the text at. … … 218 223 def ljust(value, arg): 219 224 """ 220 Left-aligns the value in a field of a given width 221 222 Argument: field size 225 Left-aligns the value in a field of a given width. 226 227 Argument: field size. 223 228 """ 224 229 return value.ljust(int(arg)) … … 227 232 def rjust(value, arg): 228 233 """ 229 Right-aligns the value in a field of a given width 230 231 Argument: field size 234 Right-aligns the value in a field of a given width. 235 236 Argument: field size. 232 237 """ 233 238 return value.rjust(int(arg)) … … 235 240 236 241 def center(value, arg): 237 " Centers the value in a field of a given width"242 """Centers the value in a field of a given width.""" 238 243 return value.center(int(arg)) 239 244 center = stringfilter(center) 240 245 241 246 def cut(value, arg): 242 " Removes all values of arg from the given string"247 """Removes all values of arg from the given string.""" 243 248 return value.replace(arg, u'') 244 249 cut = stringfilter(cut) … … 273 278 274 279 def removetags(value, tags): 275 " Removes a space separated list of [X]HTML tags from the output"280 """Removes a space separated list of [X]HTML tags from the output.""" 276 281 tags = [re.escape(tag) for tag in tags.split()] 277 282 tags_re = u'(%s)' % u'|'.join(tags) … … 284 289 285 290 def striptags(value): 286 " Strips all [X]HTML tags"291 """Strips all [X]HTML tags.""" 287 292 from django.utils.html import strip_tags 288 293 return strip_tags(value) … … 315 320 316 321 def first(value): 317 " Returns the first item in a list"322 """Returns the first item in a list.""" 318 323 try: 319 324 return value[0] … … 322 327 323 328 def join(value, arg): 324 " Joins a list with a string, like Python's ``str.join(list)``"329 """Joins a list with a string, like Python's ``str.join(list)``.""" 325 330 try: 326 331 return arg.join(map(force_unicode, value)) … … 329 334 330 335 def length(value): 331 " Returns the length of the value - useful for lists"336 """Returns the length of the value - useful for lists.""" 332 337 return len(value) 333 338 334 339 def length_is(value, arg): 335 " Returns a boolean of whether the value's length is the argument"340 """Returns a boolean of whether the value's length is the argument.""" 336 341 return len(value) == int(arg) 337 342 338 343 def random(value): 339 " Returns a random item from the list"344 """Returns a random item from the list.""" 340 345 return random_module.choice(value) 341 346 … … 417 422 sublist_item = None 418 423 if isinstance(title, (list, tuple)): 419 sublist_item = title 424 sublist_item = title 420 425 title = '' 421 426 elif i < list_length - 1: … … 425 430 sublist_item = next_item 426 431 # We've processed the next item now too. 427 i += 1 432 i += 1 428 433 if sublist_item: 429 434 sublist = _helper(sublist_item, tabs+1) … … 434 439 i += 1 435 440 return '\n'.join(output) 436 value, converted = convert_old_style_list(value) 441 value, converted = convert_old_style_list(value) 437 442 return _helper(value) 438 443 … … 442 447 443 448 def add(value, arg): 444 " Adds the arg to the value"449 """Adds the arg to the value.""" 445 450 return int(value) + int(arg) 446 451 … … 469 474 470 475 def date(value, arg=None): 471 " Formats a date according to the given format"476 """Formats a date according to the given format.""" 472 477 from django.utils.dateformat import format 473 478 if not value: … … 478 483 479 484 def time(value, arg=None): 480 " Formats a time according to the given format"485 """Formats a time according to the given format.""" 481 486 from django.utils.dateformat import time_format 482 487 if value in (None, u''): … … 487 492 488 493 def timesince(value, arg=None): 489 'Formats a date as the time since that date (i.e. "4 days, 6 hours")'494 """Formats a date as the time since that date (i.e. "4 days, 6 hours").""" 490 495 from django.utils.timesince import timesince 491 496 if not value: … … 496 501 497 502 def timeuntil(value, arg=None): 498 'Formats a date as the time until that date (i.e. "4 days, 6 hours")'503 """Formats a date as the time until that date (i.e. "4 days, 6 hours").""" 499 504 from django.utils.timesince import timesince 500 505 from datetime import datetime … … 510 515 511 516 def default(value, arg): 512 " If value is unavailable, use given default"517 """If value is unavailable, use given default.""" 513 518 return value or arg 514 519 515 520 def default_if_none(value, arg): 516 " If value is None, use given default"521 """If value is None, use given default.""" 517 522 if value is None: 518 523 return arg … … 520 525 521 526 def divisibleby(value, arg): 522 " Returns true if the value is devisible by the argument"527 """Returns True if the value is devisible by the argument.""" 523 528 return int(value) % int(arg) == 0 524 529 … … 545 550 try: 546 551 yes, no, maybe = bits 547 except ValueError: # unpack list of wrong size (no "maybe" value provided) 552 except ValueError: 553 # Unpack list of wrong size (no "maybe" value provided). 548 554 yes, no, maybe = bits[0], bits[1], bits[1] 549 555 if value is None: … … 559 565 def filesizeformat(bytes): 560 566 """ 561 Format the value like a 'human-readable' file size (i.e. 13 KB, 4.1 MB, 102562 bytes, etc).567 Formats the value like a 'human-readable' file size (i.e. 13 KB, 4.1 MB, 568 102 bytes, etc). 563 569 """ 564 570 try: … … 592 598 if int(value) != 1: 593 599 return plural_suffix 594 except ValueError: # invalid string that's not a number600 except ValueError: # Invalid string that's not a number. 595 601 pass 596 except TypeError: # value isn't a string or a number; maybe it's a list?602 except TypeError: # Value isn't a string or a number; maybe it's a list? 597 603 try: 598 604 if len(value) != 1: 599 605 return plural_suffix 600 except TypeError: # len() of unsized object 606 except TypeError: # len() of unsized object. 601 607 pass 602 608 return singular_suffix 603 609 604 610 def phone2numeric(value): 605 " Takes a phone number and converts it in to its numerical equivalent"611 """Takes a phone number and converts it in to its numerical equivalent.""" 606 612 from django.utils.text import phone2numeric 607 613 return phone2numeric(value) 608 614 609 615 def pprint(value): 610 " A wrapper around pprint.pprint -- for debugging, really"616 """A wrapper around pprint.pprint -- for debugging, really.""" 611 617 from pprint import pformat 612 618 try: django/trunk/django/template/defaulttags.py
r6636 r6641 1 "Default tags used by the template system, available to all templates." 2 1 """Default tags used by the template system, available to all templates.""" 2 3 import sys 4 import re 3 5 from itertools import cycle as itertools_cycle 6 try: 7 reversed 8 except NameError: 9 from django.utils.itercompat import reversed # Python 2.3 fallback 4 10 5 11 from django.template import Node, NodeList, Template, Context, Variable … … 9 15 from django.utils.encoding import smart_str, smart_unicode 10 16 from django.utils.itercompat import groupby 11 import sys12 import re13 14 try:15 reversed16 except NameError:17 from django.utils.itercompat import reversed # Python 2.3 fallback18 17 19 18 register = Library() … … 49 48 def render(self, context): 50 49 output = self.nodelist.render(context) 51 # apply filters50 # Apply filters. 52 51 context.update({'var': output}) 53 52 filtered = self.filter_expr.resolve(context) … … 81 80 reversed = '' 82 81 return "<For Node: for %s in %s, tail_len: %d%s>" % \ 83 (', '.join( self.loopvars ), self.sequence, len(self.nodelist_loop), reversed) 82 (', '.join(self.loopvars), self.sequence, len(self.nodelist_loop), 83 reversed) 84 84 85 85 def __iter__(self): … … 115 115 for i, item in enumerate(values): 116 116 context['forloop'] = { 117 # shortcuts for current loop iteration number117 # Shortcuts for current loop iteration number. 118 118 'counter0': i, 119 119 'counter': i+1, 120 # reverse counter iteration numbers120 # Reverse counter iteration numbers. 121 121 'revcounter': len_values - i, 122 122 'revcounter0': len_values - i - 1, 123 # boolean values designating first and last times through loop123 # Boolean values designating first and last times through loop. 124 124 'first': (i == 0), 125 125 'last': (i == len_values - 1), … … 127 127 } 128 128 if unpack: 129 # If there are multiple loop variables, unpack the item into them. 129 # If there are multiple loop variables, unpack the item into 130 # them. 130 131 context.update(dict(zip(self.loopvars, item))) 131 132 else: … … 154 155 try: 155 156 if self._varlist: 156 # Consider multiple parameters. 157 # This automatically behaves like aOR evaluation of the multiple variables.157 # Consider multiple parameters. This automatically behaves 158 # like an OR evaluation of the multiple variables. 158 159 compare_to = [var.resolve(context) for var in self._varlist] 159 160 else: … … 249 250 def render(self, context): 250 251 obj_list = self.target.resolve(context, True) 251 if obj_list == None: # target_var wasn't found in context; fail silently 252 if obj_list == None: 253 # target variable wasn't found in context; fail silently. 252 254 context[self.var_name] = [] 253 255 return '' 254 # List of dictionaries in the format 256 # List of dictionaries in the format: 255 257 # {'grouper': 'key', 'list': [list of contents]}. 256 context[self.var_name] = [{'grouper':key, 'list':list(val)} for key, val in 257 groupby(obj_list, lambda v, f=self.expression.resolve: f(v, True))] 258 context[self.var_name] = [ 259 {'grouper': key, 'list': list(val)} 260 for key, val in 261 groupby(obj_list, lambda v, f=self.expression.resolve: f(v, True)) 262 ] 258 263 return '' 259 264 … … 339 344 from django.core.urlresolvers import reverse, NoReverseMatch 340 345 args = [arg.resolve(context) for arg in self.args] 341 kwargs = dict([(smart_str(k,'ascii'), v.resolve(context)) for k, v in self.kwargs.items()]) 346 kwargs = dict([(smart_str(k,'ascii'), v.resolve(context)) 347 for k, v in self.kwargs.items()]) 342 348 try: 343 349 return reverse(self.view_name, args=args, kwargs=kwargs) … … 345 351 try: 346 352 project_name = settings.SETTINGS_MODULE.split('.')[0] 347 return reverse(project_name + '.' + self.view_name, args=args, kwargs=kwargs) 353 return reverse(project_name + '.' + self.view_name, 354 args=args, kwargs=kwargs) 348 355 except NoReverseMatch: 349 356 return '' … … 389 396 def comment(parser, token): 390 397 """ 391 Ignore everything between ``{% comment %}`` and ``{% endcomment %}``398 Ignores everything between ``{% comment %}`` and ``{% endcomment %}``. 392 399 """ 393 400 parser.skip_past('endcomment') … … 398 405 def cycle(parser, token): 399 406 """ 400 Cycle among the given strings each time this tag is encountered407 Cycles among the given strings each time this tag is encountered. 401 408 402 409 Within a loop, cycles among the given strings each time through … … 417 424 418 425 You can use any number of values, seperated by spaces. Commas can also 419 be used to separate values; if a comma is used, the cycle values are 426 be used to separate values; if a comma is used, the cycle values are 420 427 interpreted as literal strings. 421 428 """ 422 429 423 # Note: This returns the exact same node on each {% cycle name %} call; that424 # is, the node object returned from {% cycle a b c as name %} and the one425 # returned from {% cycle name %} are the exact same object. This shouldn't426 # cause problems (heh), but if it does, now you know.430 # Note: This returns the exact same node on each {% cycle name %} call; 431 # that is, the node object returned from {% cycle a b c as name %} and the 432 # one returned from {% cycle name %} are the exact same object. This 433 # shouldn't cause problems (heh), but if it does, now you know. 427 434 # 428 435 # Ugly hack warning: this stuffs the named template dict into parser so … … 442 449 443 450 if len(args) == 2: 444 # {% cycle foo %} case 451 # {% cycle foo %} case. 445 452 name = args[1] 446 453 if not hasattr(parser, '_namedCycleNodes'): 447 raise TemplateSyntaxError("No named cycles in template: '%s' is not defined" % name) 454 raise TemplateSyntaxError("No named cycles in template." 455 " '%s' is not defined" % name) 448 456 if not name in parser._namedCycleNodes: 449 457 raise TemplateSyntaxError("Named cycle '%s' does not exist" % name) … … 463 471 def debug(parser, token): 464 472 """ 465 Output a whole load of debugging information, including the current context and imported modules. 473 Outputs a whole load of debugging information, including the current 474 context and imported modules. 466 475 467 476 Sample usage:: … … 477 486 def do_filter(parser, token): 478 487 """ 479 Filter the contents of the blog through variable filters.488 Filters the contents of the blog through variable filters. 480 489 481 490 Filters can also be piped through each other, and they can have … … 526 535 bits = token.split_contents()[1:] 527 536 if len(bits) < 1: 528 raise TemplateSyntaxError, "'firstof' statement requires at least one argument" 537 raise TemplateSyntaxError("'firstof' statement requires at least one" 538 " argument") 529 539 return FirstOfNode(bits) 530 540 firstof = register.tag(firstof) … … 533 543 def do_for(parser, token): 534 544 """ 535 Loop over each item in an array.545 Loops over each item in an array. 536 546 537 547 For example, to display a list of athletes given ``athlete_list``:: … … 545 555 You can loop over a list in reverse by using 546 556 ``{% for obj in list reversed %}``. 547 557 548 558 You can also unpack multiple values from a two-dimensional array:: 549 559 550 560 {% for key,value in dict.items %} 551 561 {{ key }}: {{ value }} … … 572 582 bits = token.contents.split() 573 583 if len(bits) < 4: 574 raise TemplateSyntaxError, "'for' statements should have at least four words: %s" % token.contents 584 raise TemplateSyntaxError("'for' statements should have at least four" 585 " words: %s" % token.contents) 575 586 576 587 reversed = bits[-1] == 'reversed' 577 588 in_index = reversed and -3 or -2 578 589 if bits[in_index] != 'in': 579 raise TemplateSyntaxError, "'for' statements should use the format 'for x in y': %s" % token.contents 590 raise TemplateSyntaxError("'for' statements should use the format" 591 " 'for x in y': %s" % token.contents) 580 592 581 593 loopvars = re.sub(r' *, *', ',', ' '.join(bits[1:in_index])).split(',') 582 594 for var in loopvars: 583 595 if not var or ' ' in var: 584 raise TemplateSyntaxError, "'for' tag received an invalid argument: %s" % token.contents 596 raise TemplateSyntaxError("'for' tag received an invalid argument:" 597 " %s" % token.contents) 585 598 586 599 sequence = parser.compile_filter(bits[in_index+1]) … … 607 620 def ifequal(parser, token): 608 621 """ 609 Output the contents of the block if the two arguments equal each other.622 Outputs the contents of the block if the two arguments equal each other. 610 623 611 624 Examples:: … … 626 639 #@register.tag 627 640 def ifnotequal(parser, token): 628 """Output the contents of the block if the two arguments are not equal. See ifequal.""" 641 """ 642 Outputs the contents of the block if the two arguments are not equal. 643 See ifequal. 644 """ 629 645 return do_ifequal(parser, token, True) 630 646 ifnotequal = register.tag(ifnotequal) … … 635 651 The ``{% if %}`` tag evaluates a variable, and if that variable is "true" 636 652 (i.e. exists, is not empty, and is not a false boolean value) the contents 637 of the block are output: 638 639 :: 653 of the block are output:: 640 654 641 655 {% if athlete_list %} … … 648 662 be displayed by the ``{{ athlete_list|count }}`` variable. 649 663 650 As you can see, the ``if`` tag can take an option ``{% else %}`` clause that651 will be displayed if the test fails.664 As you can see, the ``if`` tag can take an option ``{% else %}`` clause 665 that will be displayed if the test fails. 652 666 653 667 ``if`` tags may use ``or``, ``and`` or ``not`` to test a number of … … 674 688 {% endif %} 675 689 676 ``if`` tags do not allow ``and`` and ``or`` clauses with the same 677 tag, because the order of logic would be ambigous. For example,678 this isinvalid::690 ``if`` tags do not allow ``and`` and ``or`` clauses with the same tag, 691 because the order of logic would be ambigous. For example, this is 692 invalid:: 679 693 680 694 {% if athlete_list and coach_list or cheerleader_list %} … … 692 706 del bits[0] 693 707 if not bits: 694 raise TemplateSyntaxError , "'if' statement requires at least one argument"695 # bits now looks something like this: ['a', 'or', 'not', 'b', 'or', 'c.d']708 raise TemplateSyntaxError("'if' statement requires at least one argument") 709 # Bits now looks something like this: ['a', 'or', 'not', 'b', 'or', 'c.d'] 696 710 bitstr = ' '.join(bits) 697 711 boolpairs = bitstr.split(' and ') … … 728 742 def ifchanged(parser, token): 729 743 """ 730 Check if a value has changed from the last iteration of a loop.744 Checks if a value has changed from the last iteration of a loop. 731 745 732 746 The 'ifchanged' block tag is used within a loop. It has two possible uses. 733 747 734 748 1. Checks its own rendered contents against its previous state and only 735 displays the content if it has changed. For example, this displays a list of736 days, only displaying the month if it changes::749 displays the content if it has changed. For example, this displays a 750 list of days, only displaying the month if it changes:: 737 751 738 752 <h1>Archive for {{ year }}</h1> … … 743 757 {% endfor %} 744 758 745 2. If given a variable, check whether that variable has changed. For example, the746 following shows the date every time it changes, but only shows the hour if both747 the hour and the date have changed::759 2. If given a variable, check whether that variable has changed. 760 For example, the following shows the date every time it changes, but 761 only shows the hour if both the hour and the date have changed:: 748 762 749 763 {% for date in days %} … … 763 777 def ssi(parser, token): 764 778 """ 765 Output the contents of a given file into the page.779 Outputs the contents of a given file into the page. 766 780 767 781 Like a simple "include" tag, the ``ssi`` tag includes the contents … … 779 793 parsed = False 780 794 if len(bits) not in (2, 3): 781 raise TemplateSyntaxError, "'ssi' tag takes one argument: the path to the file to be included" 795 raise TemplateSyntaxError("'ssi' tag takes one argument: the path to" 796 " the file to be included") 782 797 if len(bits) == 3: 783 798 if bits[2] == 'parsed': 784 799 parsed = True 785 800 else: 786 raise TemplateSyntaxError, "Second (optional) argument to %s tag must be 'parsed'" % bits[0] 801 raise TemplateSyntaxError("Second (optional) argument to %s tag" 802 " must be 'parsed'" % bits[0]) 787 803 return SsiNode(bits[1], parsed) 788 804 ssi = register.tag(ssi) … … 791 807 def load(parser, token): 792 808 """ 793 Load a custom template tag set. 794 795 For example, to load the template tags in ``django/templatetags/news/photos.py``:: 809 Loads a custom template tag set. 810 811 For example, to load the template tags in 812 ``django/templatetags/news/photos.py``:: 796 813 797 814 {% load news.photos %} … … 804 821 parser.add_library(lib) 805 822 except InvalidTemplateLibrary, e: 806 raise TemplateSyntaxError, "'%s' is not a valid tag library: %s" % (taglib, e) 823 raise TemplateSyntaxError("'%s' is not a valid tag library: %s" % 824 (taglib, e)) 807 825 return LoadNode() 808 826 load = register.tag(load) … … 811 829 def now(parser, token): 812 830 """ 813 Display the date, formatted according to the given string.831 Displays the date, formatted according to the given string. 814 832 815 833 Uses the same format as PHP's ``date()`` function; see http://php.net/date … … 830 848 def regroup(parser, token): 831 849 """ 832 Regroup a list of alike objects by a common attribute.850 Regroups a list of alike objects by a common attribute. 833 851 834 852 This complex tag is best illustrated by use of an example: say that … … 868 886 Note that `{% regroup %}`` does not work when the list to be grouped is not 869 887 sorted by the key you are grouping by! This means that if your list of 870 people was not sorted by gender, you'd need to make sure it is sorted before871 using it, i.e.::888 people was not sorted by gender, you'd need to make sure it is sorted 889 before using it, i.e.:: 872 890 873 891 {% regroup people|dictsort:"gender" by gender as grouped %} … … 879 897 target = parser.compile_filter(firstbits[1]) 880 898 if firstbits[2] != 'by': 881 raise TemplateSyntaxError , "second argument to 'regroup' tag must be 'by'"899 raise TemplateSyntaxError("second argument to 'regroup' tag must be 'by'") 882 900 lastbits_reversed = firstbits[3][::-1].split(None, 2) 883 901 if lastbits_reversed[1][::-1] != 'as': 884 raise TemplateSyntaxError, "next-to-last argument to 'regroup' tag must be 'as'" 902 raise TemplateSyntaxError("next-to-last argument to 'regroup' tag must" 903 " be 'as'") 885 904 886 905 expression = parser.compile_filter(lastbits_reversed[2][::-1]) … … 892 911 def spaceless(parser, token): 893 912 """ 894 Removes whitespace between HTML tags. This includes tab 895 characters and newlines. 913 Removes whitespace between HTML tags, including tab and newline characters. 896 914 897 915 Example usage:: … … 907 925 <p><a href="foo/">Foo</a></p> 908 926 909 Only space between *tags* is normalized -- not space between tags and text. In910 this example, the space around ``Hello`` won't be stripped::927 Only space between *tags* is normalized -- not space between tags and text. 928 In this example, the space around ``Hello`` won't be stripped:: 911 929 912 930 {% spaceless %} … … 924 942 def templatetag(parser, token): 925 943 """ 926 Output one of the bits used to compose template tags.944 Outputs one of the bits used to compose template tags. 927 945 928 946 Since the template system has no concept of "escaping", to display one of … … 949 967 tag = bits[1] 950 968 if tag not in TemplateTagNode.mapping: 951 raise TemplateSyntaxError, "Invalid templatetag argument: '%s'. Must be one of: %s" % \ 952 (tag, TemplateTagNode.mapping.keys()) 969 raise TemplateSyntaxError("Invalid templatetag argument: '%s'." 970 " Must be one of: %s" % 971 (tag, TemplateTagNode.mapping.keys())) 953 972 return TemplateTagNode(tag) 954 973 templatetag = register.tag(templatetag) … … 958 977 Returns an absolute URL matching given view with its parameters. 959 978 960 This is a way to define links that aren't tied to a particular URL configuration:: 979 This is a way to define links that aren't tied to a particular URL 980 configuration:: 961 981 962 982 {% url path.to.some_view arg1,arg2,name1=value1 %} … … 986 1006 bits = token.contents.split(' ', 2) 987 1007 if len(bits) < 2: 988 raise TemplateSyntaxError, "'%s' takes at least one argument (path to a view)" % bits[0] 1008 raise TemplateSyntaxError("'%s' takes at least one argument" 1009 " (path to a view)" % bits[0]) 989 1010 args = [] 990 1011 kwargs = {} … … 1011 1032 1012 1033 Above, if ``this_value`` is 175 and ``max_value`` is 200, the the image in 1013 the above example will be 88 pixels wide (because 175/200 = .875; .875 *1014 100 = 87.5 which is rounded up to 88).1034 the above example will be 88 pixels wide (because 175/200 = .875; 1035 .875 * 100 = 87.5 which is rounded up to 88). 1015 1036 """ 1016 1037 bits = token.contents.split() … … 1029 1050 def do_with(parser, token): 1030 1051 """ 1031 Add a value to the context (inside of this block) for caching and easy1052 Adds a value to the context (inside of this block) for caching and easy 1032 1053 access. 1033 1054 … … 1040 1061 bits = list(token.split_contents()) 1041 1062 if len(bits) != 4 or bits[2] != "as": 1042 raise TemplateSyntaxError, "%r expected format is 'value as name'" % bits[0] 1063 raise TemplateSyntaxError("%r expected format is 'value as name'" % 1064 bits[0]) 1043 1065 var = parser.compile_filter(bits[1]) 1044 1066 name = bits[3]
