Django Unleashed Errata

To report errata, please email errata (at) informit (dot) com with:

  1. the name of the book,
  2. the chapter (and section/example if applicable),
  3. the page number where the error is found.

Table of Contents

Chapter 1

Page 14: Extra ‘r’ on file

Example 1.3 lists the items in the directory of our new project. One of the files is listed as __init__.pyr, but should be listed without the last ‘r’:

Page 16: Database Necessity Not Strictly True

The very first paragraph on page 16 informs the reader that it is necessary to create a database to run the new Django site. This is not strictly true: it is possible to run the site using without a database. However, the first thing Django will do is to warn you (in the shell, as demonstrated below) that you need to run migrations (the command in Example 1.5) to create the database.

$ ./ runserver
Performing system checks...

System check identified no issues (0 silenced).

You have unapplied migrations; your app may not work properly until they are applied.
Run 'python migrate' to apply them.

The message above is why we opt to run migrate before runserver.

The truth of the matter is that Django will run just fine up until it needs to communicate with a database. For instance, if you browse root (/) or /admin/ on a brand new site, everything will work. However, the moment you try to login to /admin/, Django will begin to throw errors. This is true for Django generally, not just on a new project.

Chapter 3

Page 38: Capital F in CharField

The second paragraph on page 38 refers to Django’s CharField multiple times. In one instance, the field is mistakenly printed as Charfield. The F should instead be captialized to properly refer to the Python class (as Python variables are case-sensitive).

Thanks to Jonathan Friedman for catching this.

Page 56: What requirements.txt file?

The aside on page 56 makes reference to a requirements.txt file that exists in a repository. The repository in question is the official book code hosted on GitHub.

To get the requirements file, you can either browse to the file online and then copy and paste the contents, or you can use the curl command to download the file directly to your own project, as demonstrated below.

$ curl -o requirements.txt \

The requirements file is just a list of packages for pip to install. To install all the items in the list, use the command below.

$ pip install -r requirements.txt

While having a requirements file is a Python convention (to make using a project easier for other developers), you don’t actually need a requirements file. You could simply install all of the tools you wish directly with pip. Below, I use pip to install IPython with notebook functionality enabled, using exactly the same name from the requirements.txt file online.

$ pip install ipython[notebook]

Note that between the time I finished writing the book and now, IPython notebooks have begun to shift to a new project named Jupyter. While the command above still works, eventually you’ll want to install Jupyter with the command listed below.

$ pip install jupyter

When using just IPython, the terminal command to activate notebooks was ipython notebook. With Jupyter, that command is now jupyter notebook. However, with a Django project you will still want to access notebooks with the command below.

$ ./ shell_plus --notebook

Thanks to Chris Wilkins for pointing out the ambiguity.

Page 56: Invoked file has extra ‘r’

The command in the aside on page 56 should invoke the file, not the file.

Thanks to Evan Palmer for catching the error.

Page 62: ‘Video Games’ Missing from Example Outputs

As correctly noted in Example 3.57, Examples 3.58 and 3.59 should feature <Tag: Video Games> in the output. You may see the actual code in action in the Jupyter notebook on Github.

Thanks to Jonathan Friedman for pointing this out.

Chapter 4

Example 4.70 (page 114) ends with the code printed below.

>>> template.render(context)

As noted in the IPython notebook on GitHub, the code should actually use a print() function to make the output readable.

>>> print(template.render(context))

Thanks to Dan Hitt for catching the error.

Chapter 5

Page 154: Extra Underscores in pub_date

Example 5.53 (page 154) contains the command listed below.


There should only be one underscore between pub and date (in all of the code in the book), meaning the command should actually be the code below.


Thanks to Charlie Pilgrim for catching the error.

Page 167: Last Sentence of Chapter Confusing

The very last sentence in Chapter 5 has a reference error that makes the sentence very confusing. The sentence should read as follows.

In short, URL configurations are trees of URL patterns and each URL pattern directs Django to a view, which is a function or class that contains the logic required to make a webpage.

Chapter 7

Page 206: Wrong Example Referenced

In the second paragraph on page 206, between examples 7.24 and 7.25, the text reads:

The result of is_valid() (Example 7.25) might seem confusing at first…

The text should be referencing the example above it, number 7.24, instead of example 7.25.

Chapter 8

Page 213: Slug Error Non-alphanumeric Recommendation is Inaccurate

Towards the end of section 8.2.1, I state:

Triggering a validation error with our slug field is simpler: we have the option to pass the value create, or any character that is not alphanumeric, such as a dash or an underscore.

This is not accurate. To generate an error on a SlugField, we must pass a value that is not accepted by the field. As originally discussed on in Chapter 5 on page 130, a slug will accept an alphanumeric character, a dash, or an underscore. We can use any other character to forcibly generate an error. I opt to use %%%, but you could use any of !, #, $, or even 😈. Keep in mind that spaces do not count as alphanumeric, so you could generate a validation error by passing a string with spaces in between (simply including spaces count as an empty submission).

Thanks to Jonathan Friedman for catching the error.

Page 213: 404 Error for /tag/create/

Section 8.2.1 instructs the reader to run the development server and access the site at URI /tag/create/. However, the view to actually render the template we’ve just built won’t be created until section 9.2.2, a whole chapter later.

The typo is due to a rewrite where this content was rearranged. To actually run the site, you may clone the code from the main repository, checkout commit fa52634a9e, and then follow the original instructions.

$ # remember to run Python projects in a virtual env!
$ # you can skip the cloning step if you already have the code
$ git clone
$ # the command above optionally takes a directory name for where to clone the repo
$ git checkout fa52634a9e
$ # if you've just cloned, you must first migrate
$ python migrate
$ python runserver

If you now browse to, you can see the form errors as described.

Page 226: Section 8.4 Opening Line Typos

The opening line to section 8.4 has a few typos. The sentence should read as below.

Unlike the templates for creating or updating Tag objects, the template for deleting Tag objects doesn’t need any information from the user and therefore doesn’t need to display TagForm.

Thanks to Jonathan Friedman for catching this.

Chapter 9

Page 236: Typo in sentence: ‘word’ should be ‘work’

Towards the middle of the page, the books reads (emphasis added):

Given that a Django form has three states, we know that the minimum number of states we must deal with is three. What’s more, from our preceding word, we also know that we don’t need any more states than the ones we have defined.

The text should read ‘What’s more, from our preceding work…’

Page 269: Section 9.4.1 Opening Paragraph Repeat Typo

The second line to section 9.4.1 accidentally repeats blog_post_detail.

However, to differentiate blog_post_delete from either blog_post_detail or blog_post_detail, our new URL pattern will append the /delete/ path segment to our regular expression pattern, as shown in Example 9.68.

The second URL pattern should be referring to blog_post_update.

However, to differentiate blog_post_delete from either blog_post_detail or blog_post_update, our new URL pattern will append the /delete/ path segment to our regular expression pattern, as shown in Example 9.68.

Page 275: Missing Import and Explanation for reverse_lazy()

In Example 9.85 on page 275, we use reverse_lazy() for the first time. Unfortunately, the example fails to import the function, and there is no explanation provided for what it does.

The import is on line one of commit dc53479077, printed below for convenience.

from django.core.urlresolvers import reverse_lazy

The explanation that should appear below the example is printed below.

Example 9.85 introduces a new function called reverse_lazy(). It does the same thing that reverse() does, but waits until the URL string is needed by Django before computing the URL. The advantage is that we can use reverse_lazy() in contexts when Django hasn’t yet created the full URL-pattern tree. The inherent problem is that Python files are imported by Django as Django is starting up, meaning that attributes on classes or variables (like those in are evaluated as Django starts, which is before the existence of the URL-pattern tree. If we were to use reverse() on an a class attribute like in the example above, Django would throw an error, because it cannot find any URLs when it’s starting! In short: reverse_lazy() allows our code to remain DRY in situations when reversing URLs is not yet possible.

Chapter 15

Page 369: Example Output for makemigrations is Incorrect

Example 15.42 demonstrates how to generate a data migration with a specific file name by passing the --name flag to the makemigrations command. The output in the example prints the wrong name for the file created. Instead of creating, this command will create the filename passed:

Chapter 17

Page 404: ‘Creates’ Typo

In the middle of page 404 in section, the book misprints the word ‘creates’:

In anticipation of any links we might need, Example 17.44 creats

Chapter 18

Page 426: Text should refer to DetailView, not TagDetail

In the first paragraph of section 18.5,

Given that our detail page for Post uses the year, month, and slug of the object for uniqueness, it didn’t make any sense to use TagDetail.

The TagDetail at the end of the sentence should actually refer to the DetailView generic view mentioned earlier in the paragraph. The line should therefore be printed as it is below.

Given that our detail page for Post uses the year, month, and slug of the object for uniqueness, it didn’t make any sense to use DetailView.

Page 441: Example 18.58 Shows Code in Wrong Commit

Example 18.58 shows the NewsLinkDelete class as it exists in commit 7dcdf22318. However, just as in Example 18.57 and Example 18.59, Example 18.58 should be showing the code as it exists in f4e337f96e, notably including the NewsLinkGetObjectMixin class as superclass. The code is printed below for your convenience.

class NewsLinkDelete(
    model = NewsLink
    slug_url_kwarg = 'newslink_slug'

Chapter 19

Page 459: Variable andrew Never Assigned

Example 19.12 creates a new user, but never assigns the new user to a variable. In Example 19.14 on the next page, the andrew variable is refered to for the first time without warning. Example 19.12 should assign the new user created to the variable.

>>> andrew = User.objects.create_user(
...     'andrew', # username
...     '', # email
...     'hunter2') # password
>>> andrew
<User: andrew>

Page 467: Variable extra_content should be extra_context

The paragraph before Example 19.36 refers to one of the variables as extra_content. The variable in question, printed in Example 19.36, is actually extra_context.

Chapter 20

Page 480: Variable contributor Never Assigned

Example 20.21 creates a new group, but never assigns the new group to a variable. In Example 20.22, the contributor variable is refered to for the first time without warning. Example 20.21 should assign the value.

>>> contributor = Group.objects.create(name='contributors')
>>> contributor
<Group: contributors>
>>> Group.objects.values()
[{'id': 1, 'name': 'contributors'}]

Chapter 26

Page 667: Jupyter/IPython Notebook Does Not Load

The Juypter Notebook referred to on page 667 contains a typo that makes Jupyter unable to load the notebook.

I’ve fixed the issue in the git repository, meaning that it becomes possible to run the notebook in the latest commit, but not before.

You can view the notebook on Github.

Chapter 29

Page 729: Install Development Requirements

A clarification will be added at the end of page 729, before section 29.2.3. The clarification is printed below.

If you have followed all the instructions in each Chapter, you will already have installed django-debug-toolbar, but perhaps not django-extensions or ipython. To install these dependencies to run the site in development, you may run the command below.

$ pip install -r dev-requirements.txt

Page 733: Disabling DEBUG Setting Disables Static File Loading

Clarification: the reason we use the whitenoise package beginning on page 733 is because Django does not serve static files in production. When the DEBUG setting is disabled (set to false in suorganizer/settings/ in commit 3c73f989ea) Django ceases to serve the files, instead anticipating that files will be served with another tool, because Django does not serve static files quickly. On very large sites, it is recommended to serve static files on a completely different server, usually sitting behing a Content-Distribution Network. Covering this material is beyong the scope of the book.


Page 798: PostgreSQL listed as PostreSQL

The index has a typo on page 798 (right column, 4 lines down) where PostgreSQL is listed without the g. It is therefore not listed in the correct position alphabetically, (appearing after entries such as PostManager, instead of before).

Thanks to Evan Palmer for catching the error.