13.12 The built-in filters
The built-in filters are the functions of django/, from |upper and |date to |default and |length, which every template has without {% load %}. Each is a plain function of a value and at most one argument, most of them registered with flags that tell FilterExpression how to treat its input and its output.
The parser finds a filter by name when it compiles {{ ship, and checks its arguments (Variables and filters: FilterExpression and Variable); at render time FilterExpression passes the value through each filter in turn.
How the module registers its filters
django/ makes one Library, register, and decorates each filter with Library.filter, which stores it under its own name or the one given, as escape_filter is stored as |escape, and sets the flags it is given as attributes on it and, for a decorator such as stringfilter to read, on the innermost function under it. The module is one of Engine, so every engine loads it (Libraries: Library, custom tags and {% load %}).
Most string filters also wear stringfilter, which calls str on the first argument, so that |lower works on a number’s text, and marks the result safe when that argument was a SafeData and the function has is_safe=True. What safety means is told in Autoescaping and safe strings.
Strings
The string filters carry is_safe=True: a safe value in gives a safe value out, marked by FilterExpression. |upper, |urlencode and |wordcount carry is_safe=False, and |cut no flag: it keeps its input’s safety unless the text removed was ";".
| filter | returns |
|---|---|
|addslashes |
a backslash before each backslash and quote |
|capfirst |
the first character upper-cased |
|center, |ljust, |rjust |
the value padded to the width given |
|cut |
the value without the argument |
|iriencode |
iri_to_uri |
|lower, |upper |
str.lower, str.upper |
|phone2numeric |
letters as keypad digits |
|pprint |
pprint.pformat, or the error |
|slugify |
django |
|stringformat |
Python’s %, "03d" meaning "%03d" |
|title |
str.title, less a capital after a lower-case ASCII letter and an apostrophe, or after a digit |
|truncatechars, |truncatewords, |truncatechars_, |truncatewords_ |
Truncator.chars, Truncator.words; the HTML ones close open tags |
|urlencode |
urllib |
|wordcount |
the number of words |
|wordwrap |
django |
HTML and escaping
|linebreaks, |linebreaksbr, |linenumbers, |urlize, |urlizetrunc, |unordered_list and |join carry needs_autoescape=True, so they are passed the context’s autoescaping. When it is on, each escapes what of its input is not safe, adds its markup, numbers or separator and returns the whole through mark_safe; called from Python, they escape by default.
| filter | returns |
|---|---|
|escape, |force_escape |
conditional_, unless safe; escape, even when safe |
|safe |
mark_safe |
|escapeseq, |safeseq |
a list, each item through conditional_ or mark_safe |
|escapejs |
django |
|json_script |
django |
|striptags |
strip_tags |
|linebreaks, |linebreaksbr |
newlines as <br>, blank lines as paragraphs; newlines only |
|linenumbers |
each line numbered |
|urlize, |urlizetrunc |
URLs and email addresses as links; the second cuts their text to the length given |
|urlize and |urlizetrunc call django with nofollow=True, which splits the text at white space, quotes and angle brackets, trims each word’s wrapping and trailing punctuation, and links what is left if it is an "http" or "https" URL, a name beginning "www." or ending in one of the seven original top-level domains, or an email address, given "mailto:" and no rel="nofollow". With autoescaping on, an unsafe input is escaped word by word, links’ text included.
Numbers
| filter | returns |
|---|---|
|add |
the sum as integers; else the value + the argument; else "" |
|filesizeformat |
a size in bytes, KB, MB, GB, TB or PB, localized |
|floatformat |
the value rounded to some decimal places, localized |
|get_digit |
the digit at the place given, from the right |
floatformat reads the value as a decimal.Decimal, through str or else float, and gives "" for what is not a number. Its argument, -1 by default, counts places: a positive one gives that many, rounded half up; a negative one as many, or none for a whole value. So 34.0 prints "34" under -1 and "34.000" under 3; 34.23234, "34.2" and "34.232". A "g" suffix forces the thousands to be grouped. The active language’s separators apply even inside {% localize off %}, unless a "u" suffix turns localization off.
Lists and dictionaries
| filter | returns |
|---|---|
|dictsort, |dictsortreversed |
the list sorted by a key or attribute of its items |
|first, |last |
the first or the last item, or "" |
|join |
the items joined by the argument, each escaped when autoescaping |
|length |
len of the value, or 0 |
|make_list |
the value’s characters as a list |
|random |
a random item |
|slice |
the value sliced by "start:, or whole on a bad argument |
|unordered_list |
nested lists as <li> items, without the outer <ul> |
dictsort and dictsortreversed sort by a key that _property_resolver makes. An argument float accepts becomes operator of itself: |dictsort:0 sorts pairs by their first item. Any other is a dotted path, each part tried as a key and then an attribute, never as an index and never called; a method’s name gives bound methods, which do not compare, so a list of two or more gives "", as does a part that begins with an underscore.
length is len, or 0. A QuerySet meets the list filters as it meets Python (Evaluation and the result cache). |length calls QuerySet.__len__, which fills the result cache, so a {% for %} over the same QuerySet sends no second query; a variable that ends in a method, as {{ port does, gives a new QuerySet, and a new query, each time it is resolved. |last asks for index -1, which QuerySet refuses with ValueError, and as last catches only IndexError, the render fails.
Dates and times
date and time format with the letters of PHP’s date function. Their expects_localtime=True has FilterExpression first convert an aware datetime to the current time zone, unless Context.use_tz, or USE_TZ when that is unset, is false, as inside {% localtime off %}, or a filter of {% load tz %} such as |utc has converted it already. Printing does the same, but a datetime through |date is printed as a string.
date passes its argument to django, which looks it up as a format’s name, in the active language’s format modules and then the format settings, and takes an argument that names none as the format itself. For 27 September 2026, |date: gives "09/27/2026" in American English and "27.09.2026" in German; |date:"Y-m-d" is the same in both; no argument means "DATE_FORMAT". {% localize off %} changes nothing, as Context.use_l10n is read only where a value is printed. time works alike with "TIME_FORMAT". Both give "" for None, "" or a value without the parts its letters ask for; but a datetime.date asked for a time letter, as by |date:"H:i", raises TypeError, which date does not catch, and the render fails.
|timesince and |timeuntil put the time between the value and the argument, or now, into words.
Logic
default returns value or arg, replacing any false value; default_if_none replaces only None. They part on a variable that does not resolve. With the engine’s "string_if_invalid" empty, the default, FilterExpression hands the filters "": |default: prints "unknown", |default_if_none: nothing. With it set, the string is returned at once and no filter runs. An argument written in quotes arrives marked safe, so |default: prints its angle brackets unescaped.
pluralize takes a plural suffix, "s" by default, or a singular and a plural, "y,ies". A value float makes 1 is singular, "1" and "1.0" too; one float cannot take, a list, is singular at length 1. A string that is not a number, None, or an argument of more than two parts gives "".
|yesno maps true, false and None to the words of its argument, by default "yes,no,maybe" translated. |divisibleby tells whether int of the value divides by int of the argument, and a value that is not a number ends the render.