~kkubasik/django/aggregation-branch

« back to all changes in this revision

Viewing changes to django/core/template/defaultfilters.py

  • Committer: adrian
  • Date: 2006-05-02 01:31:56 UTC
  • Revision ID: vcs-imports@canonical.com-20060502013156-2941fcd40d080649
MERGED MAGIC-REMOVAL BRANCH TO TRUNK. This change is highly backwards-incompatible. Please read http://code.djangoproject.com/wiki/RemovingTheMagic for upgrade instructions.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
"Default variable filters"
2
 
 
3
 
from django.core.template import resolve_variable, Library
4
 
from django.conf.settings import DATE_FORMAT, TIME_FORMAT
5
 
from django.utils.translation import gettext
6
 
import re
7
 
import random as random_module
8
 
 
9
 
register = Library()
10
 
 
11
 
###################
12
 
# STRINGS         #
13
 
###################
14
 
 
15
 
 
16
 
def addslashes(value):
17
 
    "Adds slashes - useful for passing strings to JavaScript, for example."
18
 
    return value.replace('"', '\\"').replace("'", "\\'")
19
 
 
20
 
def capfirst(value):
21
 
    "Capitalizes the first character of the value"
22
 
    value = str(value)
23
 
    return value and value[0].upper() + value[1:]
24
 
 
25
 
def fix_ampersands(value):
26
 
    "Replaces ampersands with ``&`` entities"
27
 
    from django.utils.html import fix_ampersands
28
 
    return fix_ampersands(value)
29
 
 
30
 
def floatformat(text):
31
 
    """
32
 
    Displays a floating point number as 34.2 (with one decimal place) -- but
33
 
    only if there's a point to be displayed
34
 
    """
35
 
    try:
36
 
        f = float(text)
37
 
    except ValueError:
38
 
        return ''
39
 
    m = f - int(f)
40
 
    if m:
41
 
        return '%.1f' % f
42
 
    else:
43
 
        return '%d' % int(f)
44
 
 
45
 
def linenumbers(value):
46
 
    "Displays text with line numbers"
47
 
    from django.utils.html import escape
48
 
    lines = value.split('\n')
49
 
    # Find the maximum width of the line count, for use with zero padding string format command
50
 
    width = str(len(str(len(lines))))
51
 
    for i, line in enumerate(lines):
52
 
        lines[i] = ("%0" + width  + "d. %s") % (i + 1, escape(line))
53
 
    return '\n'.join(lines)
54
 
 
55
 
def lower(value):
56
 
    "Converts a string into all lowercase"
57
 
    return value.lower()
58
 
 
59
 
def make_list(value):
60
 
    """
61
 
    Returns the value turned into a list. For an integer, it's a list of
62
 
    digits. For a string, it's a list of characters.
63
 
    """
64
 
    return list(str(value))
65
 
 
66
 
def slugify(value):
67
 
    "Converts to lowercase, removes non-alpha chars and converts spaces to hyphens"
68
 
    value = re.sub('[^\w\s-]', '', value).strip().lower()
69
 
    return re.sub('\s+', '-', value)
70
 
 
71
 
def stringformat(value, arg):
72
 
    """
73
 
    Formats the variable according to the argument, a string formatting specifier.
74
 
    This specifier uses Python string formating syntax, with the exception that
75
 
    the leading "%" is dropped.
76
 
 
77
 
    See http://docs.python.org/lib/typesseq-strings.html for documentation
78
 
    of Python string formatting
79
 
    """
80
 
    try:
81
 
        return ("%" + arg) % value
82
 
    except (ValueError, TypeError):
83
 
        return ""
84
 
 
85
 
def title(value):
86
 
    "Converts a string into titlecase"
87
 
    return re.sub("([a-z])'([A-Z])", lambda m: m.group(0).lower(), value.title())
88
 
 
89
 
def truncatewords(value, arg):
90
 
    """
91
 
    Truncates a string after a certain number of words
92
 
 
93
 
    Argument: Number of words to truncate after
94
 
    """
95
 
    from django.utils.text import truncate_words
96
 
    try:
97
 
        length = int(arg)
98
 
    except ValueError: # invalid literal for int()
99
 
        return value # Fail silently.
100
 
    if not isinstance(value, basestring):
101
 
        value = str(value)
102
 
    return truncate_words(value, length)
103
 
 
104
 
def upper(value):
105
 
    "Converts a string into all uppercase"
106
 
    return value.upper()
107
 
 
108
 
def urlencode(value):
109
 
    "Escapes a value for use in a URL"
110
 
    import urllib
111
 
    return urllib.quote(value)
112
 
 
113
 
def urlize(value):
114
 
    "Converts URLs in plain text into clickable links"
115
 
    from django.utils.html import urlize
116
 
    return urlize(value, nofollow=True)
117
 
 
118
 
def urlizetrunc(value, limit):
119
 
    """
120
 
    Converts URLs into clickable links, truncating URLs to the given character limit,
121
 
    and adding 'rel=nofollow' attribute to discourage spamming.
122
 
 
123
 
    Argument: Length to truncate URLs to.
124
 
    """
125
 
    from django.utils.html import urlize
126
 
    return urlize(value, trim_url_limit=int(limit), nofollow=True)
127
 
 
128
 
def wordcount(value):
129
 
    "Returns the number of words"
130
 
    return len(value.split())
131
 
 
132
 
def wordwrap(value, arg):
133
 
    """
134
 
    Wraps words at specified line length
135
 
 
136
 
    Argument: number of characters at which to wrap the text
137
 
    """
138
 
    from django.utils.text import wrap
139
 
    return wrap(str(value), int(arg))
140
 
 
141
 
def ljust(value, arg):
142
 
    """
143
 
    Left-aligns the value in a field of a given width
144
 
 
145
 
    Argument: field size
146
 
    """
147
 
    return str(value).ljust(int(arg))
148
 
 
149
 
def rjust(value, arg):
150
 
    """
151
 
    Right-aligns the value in a field of a given width
152
 
 
153
 
    Argument: field size
154
 
    """
155
 
    return str(value).rjust(int(arg))
156
 
 
157
 
def center(value, arg):
158
 
    "Centers the value in a field of a given width"
159
 
    return str(value).center(int(arg))
160
 
 
161
 
def cut(value, arg):
162
 
    "Removes all values of arg from the given string"
163
 
    return value.replace(arg, '')
164
 
 
165
 
###################
166
 
# HTML STRINGS    #
167
 
###################
168
 
 
169
 
def escape(value):
170
 
    "Escapes a string's HTML"
171
 
    from django.utils.html import escape
172
 
    return escape(value)
173
 
 
174
 
def linebreaks(value):
175
 
    "Converts newlines into <p> and <br />s"
176
 
    from django.utils.html import linebreaks
177
 
    return linebreaks(value)
178
 
 
179
 
def linebreaksbr(value):
180
 
    "Converts newlines into <br />s"
181
 
    return value.replace('\n', '<br />')
182
 
 
183
 
def removetags(value, tags):
184
 
    "Removes a space separated list of [X]HTML tags from the output"
185
 
    tags = [re.escape(tag) for tag in tags.split()]
186
 
    tags_re = '(%s)' % '|'.join(tags)
187
 
    starttag_re = re.compile(r'<%s(/?>|(\s+[^>]*>))' % tags_re)
188
 
    endtag_re = re.compile('</%s>' % tags_re)
189
 
    value = starttag_re.sub('', value)
190
 
    value = endtag_re.sub('', value)
191
 
    return value
192
 
 
193
 
def striptags(value):
194
 
    "Strips all [X]HTML tags"
195
 
    from django.utils.html import strip_tags
196
 
    if not isinstance(value, basestring):
197
 
        value = str(value)
198
 
    return strip_tags(value)
199
 
 
200
 
###################
201
 
# LISTS           #
202
 
###################
203
 
 
204
 
def dictsort(value, arg):
205
 
    """
206
 
    Takes a list of dicts, returns that list sorted by the property given in
207
 
    the argument.
208
 
    """
209
 
    decorated = [(resolve_variable('var.' + arg, {'var' : item}), item) for item in value]
210
 
    decorated.sort()
211
 
    return [item[1] for item in decorated]
212
 
 
213
 
def dictsortreversed(value, arg):
214
 
    """
215
 
    Takes a list of dicts, returns that list sorted in reverse order by the
216
 
    property given in the argument.
217
 
    """
218
 
    decorated = [(resolve_variable('var.' + arg, {'var' : item}), item) for item in value]
219
 
    decorated.sort()
220
 
    decorated.reverse()
221
 
    return [item[1] for item in decorated]
222
 
 
223
 
def first(value):
224
 
    "Returns the first item in a list"
225
 
    try:
226
 
        return value[0]
227
 
    except IndexError:
228
 
        return ''
229
 
 
230
 
def join(value, arg):
231
 
    "Joins a list with a string, like Python's ``str.join(list)``"
232
 
    try:
233
 
        return arg.join(map(str, value))
234
 
    except AttributeError: # fail silently but nicely
235
 
        return value
236
 
 
237
 
def length(value):
238
 
    "Returns the length of the value - useful for lists"
239
 
    return len(value)
240
 
 
241
 
def length_is(value, arg):
242
 
    "Returns a boolean of whether the value's length is the argument"
243
 
    return len(value) == int(arg)
244
 
 
245
 
def random(value):
246
 
    "Returns a random item from the list"
247
 
    return random_module.choice(value)
248
 
 
249
 
def slice_(value, arg):
250
 
    """
251
 
    Returns a slice of the list.
252
 
 
253
 
    Uses the same syntax as Python's list slicing; see
254
 
    http://diveintopython.org/native_data_types/lists.html#odbchelper.list.slice
255
 
    for an introduction.
256
 
    """
257
 
    try:
258
 
        bits = []
259
 
        for x in arg.split(':'):
260
 
            if len(x) == 0:
261
 
                bits.append(None)
262
 
            else:
263
 
                bits.append(int(x))
264
 
        return value[slice(*bits)]
265
 
 
266
 
    except (ValueError, TypeError):
267
 
        return value # Fail silently.
268
 
 
269
 
def unordered_list(value):
270
 
    """
271
 
    Recursively takes a self-nested list and returns an HTML unordered list --
272
 
    WITHOUT opening and closing <ul> tags.
273
 
 
274
 
    The list is assumed to be in the proper format. For example, if ``var`` contains
275
 
    ``['States', [['Kansas', [['Lawrence', []], ['Topeka', []]]], ['Illinois', []]]]``,
276
 
    then ``{{ var|unordered_list }}`` would return::
277
 
 
278
 
        <li>States
279
 
        <ul>
280
 
                <li>Kansas
281
 
                <ul>
282
 
                        <li>Lawrence</li>
283
 
                        <li>Topeka</li>
284
 
                </ul>
285
 
                </li>
286
 
                <li>Illinois</li>
287
 
        </ul>
288
 
        </li>
289
 
    """
290
 
    def _helper(value, tabs):
291
 
        indent = '\t' * tabs
292
 
        if value[1]:
293
 
            return '%s<li>%s\n%s<ul>\n%s\n%s</ul>\n%s</li>' % (indent, value[0], indent,
294
 
                '\n'.join([_helper(v, tabs+1) for v in value[1]]), indent, indent)
295
 
        else:
296
 
            return '%s<li>%s</li>' % (indent, value[0])
297
 
    return _helper(value, 1)
298
 
 
299
 
###################
300
 
# INTEGERS        #
301
 
###################
302
 
 
303
 
def add(value, arg):
304
 
    "Adds the arg to the value"
305
 
    return int(value) + int(arg)
306
 
 
307
 
def get_digit(value, arg):
308
 
    """
309
 
    Given a whole number, returns the requested digit of it, where 1 is the
310
 
    right-most digit, 2 is the second-right-most digit, etc. Returns the
311
 
    original value for invalid input (if input or argument is not an integer,
312
 
    or if argument is less than 1). Otherwise, output is always an integer.
313
 
    """
314
 
    try:
315
 
        arg = int(arg)
316
 
        value = int(value)
317
 
    except ValueError:
318
 
        return value # Fail silently for an invalid argument
319
 
    if arg < 1:
320
 
        return value
321
 
    try:
322
 
        return int(str(value)[-arg])
323
 
    except IndexError:
324
 
        return 0
325
 
 
326
 
###################
327
 
# DATES           #
328
 
###################
329
 
 
330
 
def date(value, arg=DATE_FORMAT):
331
 
    "Formats a date according to the given format"
332
 
    from django.utils.dateformat import format
333
 
    return format(value, arg)
334
 
 
335
 
def time(value, arg=TIME_FORMAT):
336
 
    "Formats a time according to the given format"
337
 
    from django.utils.dateformat import time_format
338
 
    return time_format(value, arg)
339
 
 
340
 
def timesince(value):
341
 
    'Formats a date as the time since that date (i.e. "4 days, 6 hours")'
342
 
    from django.utils.timesince import timesince
343
 
    return timesince(value)
344
 
 
345
 
###################
346
 
# LOGIC           #
347
 
###################
348
 
 
349
 
def default(value, arg):
350
 
    "If value is unavailable, use given default"
351
 
    return value or arg
352
 
 
353
 
def default_if_none(value, arg):
354
 
    "If value is None, use given default"
355
 
    if value is None:
356
 
        return arg
357
 
    return value
358
 
 
359
 
def divisibleby(value, arg):
360
 
    "Returns true if the value is devisible by the argument"
361
 
    return int(value) % int(arg) == 0
362
 
 
363
 
def yesno(value, arg=None):
364
 
    """
365
 
    Given a string mapping values for true, false and (optionally) None,
366
 
    returns one of those strings accoding to the value:
367
 
 
368
 
    ==========  ======================  ==================================
369
 
    Value       Argument                Outputs
370
 
    ==========  ======================  ==================================
371
 
    ``True``    ``"yeah,no,maybe"``     ``yeah``
372
 
    ``False``   ``"yeah,no,maybe"``     ``no``
373
 
    ``None``    ``"yeah,no,maybe"``     ``maybe``
374
 
    ``None``    ``"yeah,no"``           ``"no"`` (converts None to False
375
 
                                        if no mapping for None is given.
376
 
    ==========  ======================  ==================================
377
 
    """
378
 
    if arg is None:
379
 
        arg = gettext('yes,no,maybe')
380
 
    bits = arg.split(',')
381
 
    if len(bits) < 2:
382
 
        return value # Invalid arg.
383
 
    try:
384
 
        yes, no, maybe = bits
385
 
    except ValueError: # unpack list of wrong size (no "maybe" value provided)
386
 
        yes, no, maybe = bits[0], bits[1], bits[1]
387
 
    if value is None:
388
 
        return maybe
389
 
    if value:
390
 
        return yes
391
 
    return no
392
 
 
393
 
###################
394
 
# MISC            #
395
 
###################
396
 
 
397
 
def filesizeformat(bytes):
398
 
    """
399
 
    Format the value like a 'human-readable' file size (i.e. 13 KB, 4.1 MB, 102
400
 
    bytes, etc).
401
 
    """
402
 
    bytes = float(bytes)
403
 
    if bytes < 1024:
404
 
        return "%d byte%s" % (bytes, bytes != 1 and 's' or '')
405
 
    if bytes < 1024 * 1024:
406
 
        return "%.1f KB" % (bytes / 1024)
407
 
    if bytes < 1024 * 1024 * 1024:
408
 
        return "%.1f MB" % (bytes / (1024 * 1024))
409
 
    return "%.1f GB" % (bytes / (1024 * 1024 * 1024))
410
 
 
411
 
def pluralize(value):
412
 
    "Returns 's' if the value is not 1, for '1 vote' vs. '2 votes'"
413
 
    try:
414
 
        if int(value) != 1:
415
 
            return 's'
416
 
    except ValueError: # invalid string that's not a number
417
 
        pass
418
 
    except TypeError: # value isn't a string or a number; maybe it's a list?
419
 
        try:
420
 
            if len(value) != 1:
421
 
                return 's'
422
 
        except TypeError: # len() of unsized object
423
 
            pass
424
 
    return ''
425
 
 
426
 
def phone2numeric(value):
427
 
    "Takes a phone number and converts it in to its numerical equivalent"
428
 
    from django.utils.text import phone2numeric
429
 
    return phone2numeric(value)
430
 
 
431
 
def pprint(value):
432
 
    "A wrapper around pprint.pprint -- for debugging, really"
433
 
    from pprint import pformat
434
 
    return pformat(value)
435
 
 
436
 
# Syntax: register.filter(name of filter, callback)
437
 
register.filter(add)
438
 
register.filter(addslashes)
439
 
register.filter(capfirst)
440
 
register.filter(center)
441
 
register.filter(cut)
442
 
register.filter(date)
443
 
register.filter(default)
444
 
register.filter(default_if_none)
445
 
register.filter(dictsort)
446
 
register.filter(dictsortreversed)
447
 
register.filter(divisibleby)
448
 
register.filter(escape)
449
 
register.filter(filesizeformat)
450
 
register.filter(first)
451
 
register.filter(fix_ampersands)
452
 
register.filter(floatformat)
453
 
register.filter(get_digit)
454
 
register.filter(join)
455
 
register.filter(length)
456
 
register.filter(length_is)
457
 
register.filter(linebreaks)
458
 
register.filter(linebreaksbr)
459
 
register.filter(linenumbers)
460
 
register.filter(ljust)
461
 
register.filter(lower)
462
 
register.filter(make_list)
463
 
register.filter(phone2numeric)
464
 
register.filter(pluralize)
465
 
register.filter(pprint)
466
 
register.filter(removetags)
467
 
register.filter(random)
468
 
register.filter(rjust)
469
 
register.filter('slice', slice_)
470
 
register.filter(slugify)
471
 
register.filter(stringformat)
472
 
register.filter(striptags)
473
 
register.filter(time)
474
 
register.filter(timesince)
475
 
register.filter(title)
476
 
register.filter(truncatewords)
477
 
register.filter(unordered_list)
478
 
register.filter(upper)
479
 
register.filter(urlencode)
480
 
register.filter(urlize)
481
 
register.filter(urlizetrunc)
482
 
register.filter(wordcount)
483
 
register.filter(wordwrap)
484
 
register.filter(yesno)