Part III – Create a Home Page with TDD, Staticfiles and Templates settings

Once we have our working environment set, we can focus on creating the Home page of our site.

However, this won’t be the usual blank home page with only “hello world” in it.

We will configure both static files and templates, implement HTML5 Boilerplate and Twitter Bootstrap, and create an much better version of the usual home page (yeah, it will have hello world in it too…)

Moreover, we will obey the Testing Goat and follow Test Driven Development (TDD) to create the Home Page. You’ll learn a lot here! 😉

Here’s what we will cover:

Static Files Settings

Open the common settings file (settings/base.py) file and look for the variable INSTALLED_APPS . Make sure it contains the app 'django.contrib.staticfiles' .

Next go at the end of the file and find the line:

STATIC_URL = '/static/'

This line tells Django to look for static files in a folder named static inside each of our apps.

However, some static files are used for the whole project and shouldn’t be inside a specific app. Go inside the taskbuster folder, at the same level of the settings files, and create a directory named static.

This directory will contain all the static files that are global for the project, like CSS or javascript files.

If you look at the beginning of the settings/base.py file, you will find

which points to the folder containing the folder that contains the actual file, i.e. the folder taskbuster.

Note: if you are working with a single settings.py file located inside the taskbuster folder (without the extra settings folder we created here) you’ll have to redefine BASE_DIR in order to point to the taskbuster folder. This is because without the extra settings folder in the middle, the previous BASE_DIR would point to the top taskbuster_project folder, instead of the taskbuster folder. You should redefine it with

To tell Django to look for static files in the taskbuster/static directory that we just created, write the following after the STATIC_URL statement:

Don’t forget the coma at the end! With this configuration, Django will look for static files in a folder named static inside each app and into the taskbuster/static folder we just created.

Templates Settings

A similar thing happens with templates. By default, the Django template loader looks for templates in a folder named templates inside each app.

But let’s create a templates folder inside taskbuster to contain all the templates that will be used throughout all the project, like base.html or some error page.

Next, update the settings files and edit the DIRS key in the TEMPLATE variable with:

Like with the static files, Django will look for templates located at a folder named templates inside each app and inside the taskbuster/templates folder we just created.

Initializr: HTML5 Boilerplate and Twitter Bootstrap

In order to check that the configuration of the templates and static files work, and because I like developing in Django with at least some CSS, we are going to include HTML5 Boilerplate and Bootstrap. These tools help you create responsive templates that work in many browsers.

Here, we will use Initializr, a mixed version that combines both HTML5 Boilerplate and Bootstrap. Go to its website, click on Get Custom Build, and select your project’s priorities. The configuration I selected for this project is the one shown on the image (except for the Apple Touch Icons, that are not used in this project):

Initializr

Once you download the package, unzip it and reorganize its contents:

  • Move the files index.html404.htmlhumans.txt and robots.txt into the taskbuster/templates folder.
  • Change the name of index.html to base.html. The index file is usually the template of your Home page, but we will use it as a base template — all our site templates will inherit from this base template.
  • Move the other files and folders into the taskbuster/static folder
  • If you have an icon you would like to use for your app, replace it for the favicon.ico file (I recommend you use the same name).
  • I also removed the files apple-touch-icon.png, browserconfig.xml, tile-wide.png and tile.png.

Home Page with Test Driven Development – Tests first

In order to see if the static files and templates are loading correctly, we will need a test. You know… Obey the testing Goat! Test first, test first!

Obey the testing goat

Obey the testing Goat
Test first, test first!

Actually, to work with Test Driven Development (TDD) we should have written the test even before setting the templates and static folders. But I wanted to finish editing the settings files first.

First, we will convert the functional_tests folder into a package by including an empty file named __init__.py inside.

$ touch functional_tests/__init__.py

This way, we can run our functional tests with:

$ python manage.py test functional_tests

However, the test runner only finds files that start with test, so let’s rename all_users.py to test_all_users.py.

We will let git to manage this, so that the repository detects the movement correctly:

Run a development server using the tb_dev environment, and then run the functional tests in your tb_test environment. It should work as before, nothing broken!

But I’m sure you don’t like this game with the two environments, right? Having to run the server using tb_dev and testing with tb_test. Why can’t the test itself create the server?

Moreover, changes made by these functional tests are persistent. Imagine that during one test, we create an instance of a model (for example, a new user). We want that after running the test, that instance (the user) disappears from our database, right? But with functional tests, we are just running the development server and playing around with the development database, so these changes persist even after the test is finished.

But don’t worry, there is the LiveServerTestCase to make our live much easier! 😉

As we will see, instances of this class create a server with a testing database, like when we run unittests.

Now, let’s edit the file functional_tests/test_all_users.py and test that both templates and static folders work as expected. For example, we can test these two different things.

  • The title in the home page is “TaskBuster”
  • The text color of the h1 header in the home page is rgba(200, 50, 255, 1) ~ pink color.
So let’s create this test!
Note: The file test_all_users.py contains the NewVisitorTest created in Part I. You should replace that test by this one:

Let’s go through that code step by step:

  • First, we define an auxiliar function named get_full_url that takes one argument, the namespace
    • A namespace is an identifier for a url. It’s a nice thing about Django: when you work with identifiers, you can change the url to whatever you want that the code just works as before.
    • self.live_server_url gives you the local host url. We use this method because the test server uses another url (usually http://127.0.0.1:8021), and this method is more flexible.
    • reverse gives you the relative url of a given namespace, here /
    • The resulting function gives you the absolute url of that namespace (the sum of the previous two), http://127.0.0.1:8021/.
  • The test_home_title  method tests that the home page title contains the word TaskBuster. We will create a template for that, so if the title exists it means that the template has been loaded correctly.
  • The test_h1_css method tests that the h1 text has the desired color. The css rule for the text color will be on a CSS file, which means that if the test passes, staticfiles are loading correctly.
  • Finally, note that we have removed the if __name__ == '__main__' statement, as functional_tests is now a package that will run with the Django test runner.

Once we have our test created, TDD tells us to follow the cycle:

  • run the test and see it fail
  • write some code so that it corrects the test error message (only write the code that corrects the error message shown by the test failure, don’t anticipate other possible errors).

We have to follow this cycle until the full test passes. It will be more clear in the next section.

Home Page with Test Driven Development – Code next

Now that we have the functional test for our home page, we can run it and see how it fails. In our tb_test environment:

We see that the first error it founds is that the namespace "home" is not defined. Open the file taskbuster/urls.py and import the view home from views.py (depending on your Django version, you might need to create this file first: taskbuster/views.py):

Note that we are using a relative import to import the home view. This way, we can change the name of our project or app without breaking the urls.

Next, add the following url:

If you run the test again it will fail, as we don’t have any home view defined. Let’s define a silly one, create the file taskbuster/views.py and define the view:

which gives a test failure because the the home page doesn’t have TaskBuster in its title.

Let’s focus on our templates now: open the file taskbuster/templates/base.html file with a browser to have an idea of what’s in it. Quite awful right? That’s because the static files are not loading.

This base.html will be our base template, and all the other project templates will inherit from this one, including the Home page.

So, it’s time for a unittest. Yeah, I know you just want to code the home page template but… Obey the Testing Goat! 😉

Unittests are meant to test small pieces of code, from the point of view of the developer. For example, it’s clear that the user doesn’t care if the home page template inherits from another template as long as it displays the contents. But the developer cares, and that’s why we should write a unittest. Moreover, I realized that when I have to think about the test, I write cleaner code. I guess it’s because having to define tests makes you think about what exactly you want the code to do. And that clears your mind 😉

Create a test.py file inside the taskbuster folder and write the following test:

You can run these tests using

Obviously, they will fail… First, let’s create the taskbuster/index.html template:

and edit the taskbuster/views.py so that it has:

where we have used the shortcut render, which lets you load a template, create a context adding a bunch of variables by default, such as information about the current logged-in user, or the current language, render it and return an HttpResponse, all in one function. Note: the information added by default depends on the template context processors that you have included in your settings file.

If you run again the unittests, you’ll see that the first one passes, indicating that the home page uses the taskbuster/index.html template. We just need to make this template to inherit from the base.html template.

So let’s edit the base.html template. For now, we are only interested in the title tag inside the head tag. Look for it in the file and write the following inside:

These two template tags, {% block head_title %} and {% endblock %} mark the beginning and the end of a content block, which contents can be replaced by child templates. You will see it clearly in a minute.

Edit again the index.html file, make it inherit from the base.html file and add it a title:

The idea is that index.html inherits from base.html (it uses all its contents) except for the blocks marked with these special template tags. In that case, it substitutes the content inside the template tag of index.html into the corresponding block in base.html.

Let’s run again the unittests:

Ok…!! Perfect, they passed!

What about the functional tests?

One passed, one failed. That’s something! But we still have to take care about static files!

First, let’s define our custom CSS file by editing the file taskbuster/static/css/main.css and adding:

Then, edit again the base.html and add this at the beginning of the file (even before the <!DOCTIPE html> statement):

then, look for all the links to static files and scripts of javascript like

and change them into this:

(you might want to remove the apple-touch-icon.png link).

Be careful with the "" and '' . Moreover, at the end of the file you will see something like

We cannot add the "{% static 'xxx' %}" tag because we would break the string. In this case, you can include the static file specifying the relative path:

Note: although both methods for importing static files work, it’s better to use the template tag if you are planning to use a content delivery network (CDN) for serving static files.

Ok, let’s run the functional test again! Oh nooo! I got an ugly error that wasn’t there before!

This is because the LiveServerTestCase doesn’t support static files…

But don’t worry, as usual, Django has a solution for it! I has another test class that supports static files!

To make the changes, edit the functional_tests/test_all_users.py, remove the lines with a minus sign and add the ones with a plus:

Run your tests again and yes! They passed! 🙂

If you want to run both the unittests and functional tests together, you can use

You can also take a look at the localhost and see how pretty the home page is now that the CSS files are loading correctly 😉

… probably not the best choice for the h1 color text, though!

Note: if when running the functional tests you get an error with Selenium that says The browser appears to have exited before we could connect, try to upgrade selenium in your working environment:

It should fix your problem 😉

Commit again to your local repository and Bitbucket

It’s a good time to make another commit!

make sure you add only the files you want to commit. Moreover, at the beginning of the output it says

which means that the actual master branch is at the same state as the origin branch in Bitbucket. Let’s see what happens after we commit the new changes:

And let’s check the status again…

So the local master branch is one commit ahead of the origin master branch. Let’s fix that by pushing the recent commit into the Bitbucket repository:

So now, our branch is again up-to-date with the origin/master in Bitbucket.

 

That’s all for now, we have created a nice Home Page!

In the next part of this TaskBuster Django Tutorial, we will talk about configuring other files download with the Initializr package: robots.txthumans.txt and the favicon.ico image.

Moreover, I’ll show you how to use coverage, a tool to measure how many code is covered by tests.

Check the next part:  Website files and Testing with coverage

And remember to share it with your friends! 🙂

Google+TwitterLinkedInFacebookReddit

Please, add +Marina Mele in your comments. This way I will get a notification email and I will answer you as soon as possible! :-)