1 """Default variable filters.""" |
1 """Default variable filters.""" |
2 |
2 |
3 import re |
3 import re |
4 |
4 from decimal import Decimal, InvalidOperation, ROUND_HALF_UP |
5 try: |
|
6 from decimal import Decimal, InvalidOperation, ROUND_HALF_UP |
|
7 except ImportError: |
|
8 from django.utils._decimal import Decimal, InvalidOperation, ROUND_HALF_UP |
|
9 |
|
10 import random as random_module |
5 import random as random_module |
11 try: |
6 try: |
12 from functools import wraps |
7 from functools import wraps |
13 except ImportError: |
8 except ImportError: |
14 from django.utils.functional import wraps # Python 2.3, 2.4 fallback. |
9 from django.utils.functional import wraps # Python 2.4 fallback. |
15 |
10 |
16 from django.template import Variable, Library |
11 from django.template import Variable, Library |
17 from django.conf import settings |
12 from django.conf import settings |
|
13 from django.utils import formats |
18 from django.utils.translation import ugettext, ungettext |
14 from django.utils.translation import ugettext, ungettext |
19 from django.utils.encoding import force_unicode, iri_to_uri |
15 from django.utils.encoding import force_unicode, iri_to_uri |
20 from django.utils.safestring import mark_safe, SafeData |
16 from django.utils.safestring import mark_safe, SafeData |
21 |
17 |
22 register = Library() |
18 register = Library() |
66 return value and value[0].upper() + value[1:] |
62 return value and value[0].upper() + value[1:] |
67 capfirst.is_safe=True |
63 capfirst.is_safe=True |
68 capfirst = stringfilter(capfirst) |
64 capfirst = stringfilter(capfirst) |
69 |
65 |
70 _base_js_escapes = ( |
66 _base_js_escapes = ( |
71 ('\\', r'\x5C'), |
67 ('\\', r'\u005C'), |
72 ('\'', r'\x27'), |
68 ('\'', r'\u0027'), |
73 ('"', r'\x22'), |
69 ('"', r'\u0022'), |
74 ('>', r'\x3E'), |
70 ('>', r'\u003E'), |
75 ('<', r'\x3C'), |
71 ('<', r'\u003C'), |
76 ('&', r'\x26'), |
72 ('&', r'\u0026'), |
77 ('=', r'\x3D'), |
73 ('=', r'\u003D'), |
78 ('-', r'\x2D'), |
74 ('-', r'\u002D'), |
79 (';', r'\x3B'), |
75 (';', r'\u003B'), |
80 (u'\u2028', r'\u2028'), |
76 (u'\u2028', r'\u2028'), |
81 (u'\u2029', r'\u2029') |
77 (u'\u2029', r'\u2029') |
82 ) |
78 ) |
83 |
79 |
84 # Escape every ASCII character with a value less than 32. |
80 # Escape every ASCII character with a value less than 32. |
85 _js_escapes = (_base_js_escapes + |
81 _js_escapes = (_base_js_escapes + |
86 tuple([('%c' % z, '\\x%02X' % z) for z in range(32)])) |
82 tuple([('%c' % z, '\\u%04X' % z) for z in range(32)])) |
87 |
83 |
88 def escapejs(value): |
84 def escapejs(value): |
89 """Hex encodes characters for use in JavaScript strings.""" |
85 """Hex encodes characters for use in JavaScript strings.""" |
90 for bad, good in _js_escapes: |
86 for bad, good in _js_escapes: |
91 value = value.replace(bad, good) |
87 value = value.replace(bad, good) |
160 except ValueError: |
156 except ValueError: |
161 return input_val |
157 return input_val |
162 |
158 |
163 try: |
159 try: |
164 m = int(d) - d |
160 m = int(d) - d |
165 except (OverflowError, InvalidOperation): |
161 except (ValueError, OverflowError, InvalidOperation): |
166 return input_val |
162 return input_val |
167 |
163 |
168 if not m and p < 0: |
164 if not m and p < 0: |
169 return mark_safe(u'%d' % (int(d))) |
165 return mark_safe(formats.number_format(u'%d' % (int(d)), 0)) |
170 |
166 |
171 if p == 0: |
167 if p == 0: |
172 exp = Decimal(1) |
168 exp = Decimal(1) |
173 else: |
169 else: |
174 exp = Decimal('1.0') / (Decimal(10) ** abs(p)) |
170 exp = Decimal('1.0') / (Decimal(10) ** abs(p)) |
175 try: |
171 try: |
176 return mark_safe(u'%s' % str(d.quantize(exp, ROUND_HALF_UP))) |
172 return mark_safe(formats.number_format(u'%s' % str(d.quantize(exp, ROUND_HALF_UP)), abs(p))) |
177 except InvalidOperation: |
173 except InvalidOperation: |
178 return input_val |
174 return input_val |
179 floatformat.is_safe = True |
175 floatformat.is_safe = True |
180 |
176 |
181 def iriencode(value): |
177 def iriencode(value): |
247 return u"" |
243 return u"" |
248 stringformat.is_safe = True |
244 stringformat.is_safe = True |
249 |
245 |
250 def title(value): |
246 def title(value): |
251 """Converts a string into titlecase.""" |
247 """Converts a string into titlecase.""" |
252 return re.sub("([a-z])'([A-Z])", lambda m: m.group(0).lower(), value.title()) |
248 t = re.sub("([a-z])'([A-Z])", lambda m: m.group(0).lower(), value.title()) |
|
249 return re.sub("\d([A-Z])", lambda m: m.group(0).lower(), t) |
253 title.is_safe = True |
250 title.is_safe = True |
254 title = stringfilter(title) |
251 title = stringfilter(title) |
255 |
252 |
256 def truncatewords(value, arg): |
253 def truncatewords(value, arg): |
257 """ |
254 """ |
647 # INTEGERS # |
644 # INTEGERS # |
648 ################### |
645 ################### |
649 |
646 |
650 def add(value, arg): |
647 def add(value, arg): |
651 """Adds the arg to the value.""" |
648 """Adds the arg to the value.""" |
652 return int(value) + int(arg) |
649 try: |
|
650 return int(value) + int(arg) |
|
651 except (ValueError, TypeError): |
|
652 try: |
|
653 return value + arg |
|
654 except: |
|
655 return value |
653 add.is_safe = False |
656 add.is_safe = False |
654 |
657 |
655 def get_digit(value, arg): |
658 def get_digit(value, arg): |
656 """ |
659 """ |
657 Given a whole number, returns the requested digit of it, where 1 is the |
660 Given a whole number, returns the requested digit of it, where 1 is the |
682 if not value: |
685 if not value: |
683 return u'' |
686 return u'' |
684 if arg is None: |
687 if arg is None: |
685 arg = settings.DATE_FORMAT |
688 arg = settings.DATE_FORMAT |
686 try: |
689 try: |
687 return format(value, arg) |
690 return formats.date_format(value, arg) |
688 except AttributeError: |
691 except AttributeError: |
689 return '' |
692 try: |
|
693 return format(value, arg) |
|
694 except AttributeError: |
|
695 return '' |
690 date.is_safe = False |
696 date.is_safe = False |
691 |
697 |
692 def time(value, arg=None): |
698 def time(value, arg=None): |
693 """Formats a time according to the given format.""" |
699 """Formats a time according to the given format.""" |
694 from django.utils.dateformat import time_format |
700 from django.utils import dateformat |
695 if value in (None, u''): |
701 if value in (None, u''): |
696 return u'' |
702 return u'' |
697 if arg is None: |
703 if arg is None: |
698 arg = settings.TIME_FORMAT |
704 arg = settings.TIME_FORMAT |
699 try: |
705 try: |
700 return time_format(value, arg) |
706 return formats.time_format(value, arg) |
701 except AttributeError: |
707 except AttributeError: |
702 return '' |
708 try: |
|
709 return dateformat.time_format(value, arg) |
|
710 except AttributeError: |
|
711 return '' |
703 time.is_safe = False |
712 time.is_safe = False |
704 |
713 |
705 def timesince(value, arg=None): |
714 def timesince(value, arg=None): |
706 """Formats a date as the time since that date (i.e. "4 days, 6 hours").""" |
715 """Formats a date as the time since that date (i.e. "4 days, 6 hours").""" |
707 from django.utils.timesince import timesince |
716 from django.utils.timesince import timesince |
789 Formats the value like a 'human-readable' file size (i.e. 13 KB, 4.1 MB, |
798 Formats the value like a 'human-readable' file size (i.e. 13 KB, 4.1 MB, |
790 102 bytes, etc). |
799 102 bytes, etc). |
791 """ |
800 """ |
792 try: |
801 try: |
793 bytes = float(bytes) |
802 bytes = float(bytes) |
794 except TypeError: |
803 except (TypeError,ValueError,UnicodeDecodeError): |
795 return u"0 bytes" |
804 return u"0 bytes" |
796 |
805 |
797 if bytes < 1024: |
806 if bytes < 1024: |
798 return ungettext("%(size)d byte", "%(size)d bytes", bytes) % {'size': bytes} |
807 return ungettext("%(size)d byte", "%(size)d bytes", bytes) % {'size': bytes} |
799 if bytes < 1024 * 1024: |
808 if bytes < 1024 * 1024: |