Previous Page Next Page

Formatting Text

Now that you understand how to apply filters, let's look at some filters that allow you to format text. Django provides several different filters that allow you to manipulate and enhance the text that is rendered to the web pages.

The following sections show some examples of some of the more common filters that you can use to format text.

Changing Text Case

Often you will parse text from an object or a web request, and you need to change the text's case. Django provides several filters for doing so. The following is a list of useful filters to change the case of text in a template:

The following example shows what happens with the capfirst, title, upper, and lower filters:

{{ title|capfirst}}<p>
{{ title|title}}<p>
{{ title|upper}}<p>
{{ title|lower}}<p>

When these filters are applied to a variable title with a value of teST titLE, the following HTML code is rendered:

TeST titLE<p>
Test Title<p>
TEST TITLE<p>
test title

By the Way

Notice that the capfirst filter results in TeST titLE. You could pipe the title variable through the lower filter first to render title as Test title:

{{ title|lower|capfirst}}<p>


escape

The escape filter allows you to escape HTML code in a string so that the code appears in the view as text. The web browser does not parse the HTML code in the text. This can be useful if you want to display HTML code as part of the view.

The HTML characters in the string are replaced with the HTML escape codes. The < character is replaced with &lt, the > character is replaced with &gt, and so on. The result is that the HTML tags in the filtered block of text show up as text in the web page.

For example, the following template code results in the HTML code being displayed in the browser, as shown in Figure 9.1:

<h2>The following code:</h2><p>
{% filter escape %}
<li>List Item1</li>
<li>List Item2</li>
<li>List Item3</li>
<li>List Item4</li>
<li>List Item5</li>
{% endfilter %}
<h2>Generates this list:</h2>
<li>List Item1</li>
<li>List Item2</li>
<li>List Item3</li>
<li>List Item4</li>
<li>List Item5</li>

Figure 9.1. Web page that displays HTML code as plain text.


length

The length filter returns the length of the object being filtered. If the object is a string, it returns the number of characters in the string. If the object is a list, it returns the number of elements in the list.

The length filter is especially useful for formatting HTML elements around the length of a string or the number of items in a list. An example of how length can be used to format HTML elements is using the length of a list to define the number of columns to span in a table. If you pass into the template a list of headers and a title, you can use the following code snippet to build the table and span the title row across all the columns that the headers form:

<table>
  <tr>
      <td colspan="{{ headers|length }}">{{ title }}</td>
  </tr>
  <tr>
    {% for h in headers %}
        <td>{{ h }}</td>
    {% endfor %}
  </tr>
</table>

linebreaks

The linebreaks filter replaces the line breaks in plain text with the HTML line break <br />. Because the HTML parser ignores line breaks and allows the text to run together, the linebreaks filter is indispensable when you render large amounts of text.

The linebreaks filter does not accept any arguments. For example, to apply the linebreaks filter to a variable called data, use the following syntax:

{{ data|linebreaks }}

By the Way

If the linebreaks filter encounters two consecutive line breaks, it replaces them with an HTML paragraph <p>.


stringformat

The stringformat filter formats the variable according to the Python string formatting syntax specified as an argument. The stringformat filter accepts only one argument—a valid Python string formatting operation with the leading % character dropped.

The best way to illustrate the string format function is with the following examples, where the value of num is 380:

int = {{ num|stringformat:"i" }}
hex = {{ num|stringformat:"x" }}
padded = {{ num|stringformat:"08X" }}
prec2float = {{ num|stringformat:"2.f" }}

This renders the following:

int = 380
hex = 17c
padded = 0000017C
prec2float = 380.00

Did you Know?

You can find more information about the Python string formatting options at: http://docs.python.org/lib/typesseq-strings.html.


striptags

The striptags filter removes all (X)HTML tags from a string of text. The striptags filter can be used for several purposes. One of the best uses is to clear out HTML codes before displaying text that was retrieved from an unsecured source, such as a user form. You can protect against users adding HTML code that could pose problems.

For example, if you accept blog entries and then display them, you can use the following line of code to render the blog text without any HTML elements the user may have added:

{{ blog.text|striptags }}

Did you Know?

Django also includes the removetags filter, which allows you to remove specific HTML codes from text. The removetags filter accepts a list of space-separated codes. For example, the following line of code removes all the <li>, <p>, and <br> tags from blog.text:

{{ blog.text|removetags:"li p br"}}


wordwrap

The wordwrap filter allows you to specify a length at which lines of text should wrap. When the wordwrap filter renders text, it determines if the next word will exceed the maximum line length. If it will, the filter enters a line break after the current word.

For example, to render text with a maximum line length of 40, you would use the following line of code:

{{ text|wordwrap:"40" }}

Watch Out!

The wordwrap filter adds only plain-text line breaks to the text. If you want to wrap the text inside an HTML element such as a table cell, use the linebreaks filter also:

{{ text|wordwrap:"40"|linebreaks}}


pluralize

The pluralize filter is used to add a plural suffix if the value of a variable is not 1. This can be useful in adding a human element to the website by eliminating messages such as "You have 1 unread messages." Using the pluralize filter enables you to write code in your template to print the message correctly. For example:

You have {{ msgNum }} unread message{{ msgNum|pluralize }}

If the value of msgNum is 1, the template renders "You have 1 unread message." If the value of msgNum is 3, the template renders "You have 3 unread messages."

The default suffix is s, but the pluralize filter also accepts a comma-separated list. If only one argument is passed into the pluralize filter, it is treated as the alternate string to apply for plural values. The following example uses the plural suffix es instead of s:

I rode {{ busCnt }} bus{{ busCnt|pluralize:"es" }}

The pluralize filter can also handle cases when a singular suffix must be applied. If two arguments are passed into the pluralize filter, the first argument is treated as the singular suffix, and the second is treated as the plural suffix. For example, if you wanted to render the string "Updated # entry(ies)" in a more user-friendly format, you could use the following pluralize filter:

Updated {{ eNum }} entr{{ eNum|pluralize:"y,ies" }}

By the Way

The length filter can help a lot with the pluralize filter. For example, if all you have is a list of entries, you could apply the length filter to the list first to get a count to use for the pluralize filter:

entr{{ entries|length|pluralize:"y,ies" }}


yesno

The yesno filter can be applied to a variable. It accepts either a "yes,no" or "yes,no,maybe" string of arguments. The yesno filter tests the variable and renders the yes string if the variable is true, the no string if the variable is false, and the maybe string if the variable value is none. If only a "yes,no" string is passed, the filter renders the no string if the variable value is none.

For example, the following line of code renders the string It is true if the variable is true and the string It is false if the variable is not true:

{{ var|yesno:"It is true,It is false" }}

Obviously, the variable can be a Boolean True or False value, and it can be a None value. If the variable is in numeric form, a value of 0 renders the no string, and any other value renders the yes string. If the variable is a list or dictionary, if the variable is empty, the no string is rendered. If the variable has at least one entry, the yes string is rendered.

The yesno tag may seem simple, but it can be used in many creative ways to save a lot of code. The following code snippet shows an example of using the yesno tag in a for loop to build a table:

{% for i in myList %}
{{ forloop.first|yesno:"<table>,"}}
<tr><td>{{ i }}</td></tr>
{{ forloop.last|yesno:"</table>,"}}
{% endfor %}

If the <table> tags in the preceding example were placed outside the for loop, they would appear in the rendered text even if there were no items in the text to render. The yesno filter lets you place the <table> tags only if you are on the first or last item in the list.

By the Way

The preceding example shows a couple of things. One is that the yesno filter accepts an empty string as one of its arguments. The other is that you can use HTML code in the string.


Try It Yourself: Add Text Formatting Filters to Templates

In this section, you will extend the person_details.py template to include the friends and blogs fields of the Person object. You will also use text formatting filters to enhance the text that is rendered by the template:

Follow these steps to modify the person_details.py template:

1.
Open the iFriends/templates/person_details.py file in an editor.

2.
Add the following HTML table row code, after the last </tr> tag in the table, to add new table cells for the friends and blogs fields:

<tr>
<td width="30%" bgcolor="556677" valign="top">
    <font color="white" size="4">
    <h3>
        iFriends
    </h3>
    </font>
</td>
<td width="70%" bgcolor="555555" colspan="2" valign="top">
    <font color="white" size="4">
    <h3>
        Blogs
    </h3>
    </font>
</td>
</tr>

3.
The Person object is stored in variable p, so you can access the list of friends and blogs using p.friends.all and p.blogs.all, respectively. Create a with tag block for each, inside the <font> tag of each table cell, using the following code:

{% with p.friends.all as fl %}
{% endwith %}
{% with p.blogs.all as bl %}
{% endwith %}

4.
Modify the Friends header created in step 2 using the following code so that the header renders No iFriends, iFriend, or iFriends, depending on whether there are zero, one, or more friends, respectively:

<h3>
    {{ fl|length|yesno:"iFriend,No Friend"}}{{fl|length|pluralize}}
</h3>

5.
Modify the Blogs header created in step 2 using the following code so that the header renders No Blogs, Blog Entry, or Blog Entries, depending on whether there are zero, one, or more blogs, respectively:

<h3>
    {{ bl|length|yesno:"Blog,No Blog"}}
    Entr{{ bl|length|pluralize:"y,ies"}}
</h3>

6.
Add the following code to the template to generate a list of friends:

{% for f in fl %}
 <li>{{ f.name }}</li>
{% endfor %}

7.
Add the following code to the template to generate a list of blogs:

{% for b in bl %}
<li>{{ b.title }}</li>
{% endfor %}

8.
Save the file.

9.
Access some different person details pages on the website to verify that the filters are working correctly. Figures 9.2 and 9.3 show web pages with different headers for the friends and blogs lists.

Figure 9.2. Person details view that has a couple friend entries but only one blog entry.


Figure 9.3. Person details view that has no friend entries but several blog entries.


By the Way

If you haven't already created some more users, you might need to do so. You might want to use the admin interface to create the new objects. To add blog entries, you may need to enable the admin interface for the blog class, as discussed in Hour 3, "Adding Models and Objects to Your Website."


Listing 9.1 shows the complete person_details.py file.

Listing 9.1. Full Contents of iFriends/template/person_details.py

{% extends "iFriends_base.html" %}

{% block title %}Details{% endblock %}
{% block content %}
<table width=100%>
<tr bgcolor="aabbcc"><td colspan="3">
<font size="5" color="white">Personal Information</font>
</td></tr>
<tr valign="top"><td width=30% bgcolor="aaaaaa"><font color="white" size="5">
    <li>Name: {{p.name}}</li>
    <li>Birthday: {{ p.birthday }}</li>
    <li>Gender:
        {% ifequal p.gender "M" %}
            Bloke
        {% else %}
            Sheila
        {% endifequal %}
    </li>
    <li>Desc: {{ p.desc }} </li>
</font></td>
<td width=40% bgcolor="aa99aa"><font color="white" size="4">
    {% include "quote.html" %}
</font></td><td width=30%>
    <h3>Contact Info</h3>
    <li>Email: {{ p.email }}</li>
    <li>Website: {{ p.favoriteURL }}</li>
</td></tr>
<tr>
<td width="30%" bgcolor="556677" valign="top">
    <font color="white" size="4">
    {% with p.friends.all as fl %}
    <h3>
        {{ fl|length|yesno:"iFriend,No Friend"}}{{fl|length|pluralize}}
    </h3>
    {% for f in fl %}
    <li>{{ f.name }}</li>
    {% endfor %}
    {% endwith %}
    </font>
</td>
<td width="70%" bgcolor="555555" colspan="2" valign="top">
    <font color="white" size="4">
    {% with p.blogs.all as bl %}
    <h3>
        {{ bl|length|yesno:"Blog,No Blog"}}
        Entr{{ bl|length|pluralize:"y,ies"}}
    </h3>
    {% for b in bl %}
    <li>{{ b.title }}</li>
    {% endfor %}
    {% endwith %}
    </font>
</td>
</tr>
</table>
{% endblock %}


					  


Previous Page Next Page