In Part I of this tutorial we built the working environment and created the TaskBuster project.

Now, we will configure the different environments for testing, developing and production, editing different Django settings files.

Moreover, we will remove Django’s SECRET_KEY from these files in order to keep it Secret.

Next, we will create a new repository to keep our code in version control and uploaded it into Bitbucket.



Ready for the next part? Here’s the guideline:

Virtual Environments and Requirements files

One important thing when working on a Project, is to control the version of your packages. For example, imagine that you’re developing in one computer that has Django 1.8 installed, and you are deploying in one server that has an older version of Django, let’s say 1.6. Your code works fine locally, but when deploying it, some incompatible errors may occur. And the same could happen if more than one developer is working in the same project, each of them with its own package versions installed.

The standard solution to this problem is to unify all the packages and save the versions used in a file named requirements.txt. This file will contain something like:

Django==1.8.5 selenium==2.48.0 1 2 Django == 1.8.5 selenium == 2.48.0

which are the packages we have installed so far (don’t worry if the versions of your environment are different).

You can see the packages installed in a virtual environment by typing

$ pip freeze 1 $ pip freeze

You might see another package, wheel, that is installed by default in some versions (don’t worry if you don’t have it). Therefore, you can create automatically the requirements.txt file by saving the output of the previous command into the file:

$ pip freeze > requirements.txt 1 $ pip freeze > requirements . txt

However, as you may notice, Selenium is only needed for the testing environment, so there is no need that the developing or the production environments have this package installed.

Let’s work out this issue by creating a requirements folder and creating a file for each environment. Go inside the taskbuster_project folder and type:

$ mkdir requirements $ touch requirements/{base.txt,development.txt,production.txt,testing.txt} 1 2 $ mkdir requirements $ touch requirements / { base . txt , development . txt , production . txt , testing . txt }

Note: don’t add any extra spaces in the previous command or it won’t work 😉 And you can delete the previous requirements.txt file, as we won’t need it. Moreover, you can also define a staging.txt file if you are planning to run a semi-private version of your site on a production server.

Let’s edit first the file base.txt. This file will contain all the packages that are common for all the environments. Now, it should only contain the Django version:

$ cd requirements $ echo "Django==1.8.5" >> base.txt 1 2 $ cd requirements $ echo "Django==1.8.5" >> base . txt

If you have another version, write yours instead!

Now let’s make the three other files to inherit the packages of the common.txt file.

$ echo "-r base.txt" | tee -a development.txt testing.txt production.txt 1 $ echo "-r base.txt" | tee - a development . txt testing . txt production . txt

Finally, we need to add Selenium into the testing file:

$ echo "selenium==2.48.0" >> testing.txt 1 $ echo "selenium==2.48.0" >> testing . txt

again, write your version here.

Ok, we have everything ready now. When a new programmer joins our team, we will tell him to create two different environments, one for testing and another for developing (the production environment is for deployment).

Next, he only needs to activate each of these environments and install the packages saved in each requirements files:

$ workon tb_dev $ pip install -r requirements/development.txt $ workon tb_test $ pip install -r requirements/testing.txt 1 2 3 4 5 $ workon tb _ dev $ pip install - r requirements / development . txt $ workon tb _ test $ pip install - r requirements / testing . txt

Different settings.py for each environment

Each environment defined previously has a different purpose, and therefore, they will need different configurations. For example, the database configuration for production and developing might be different, or the testing environment might use some Django apps that are not needed in the other environments (like selenium).

That’s why we will specify different setting files for each environment. First, we will create a folder to contain our setting files, inside the taskbuster folder:

$ mkdir taskbuster/settings 1 $ mkdir taskbuster / settings

This folder will contain:

__init__.py file to make this folder a Python package

file to make this folder a Python package base.py will contain all the settings that are common in all environments. The other setting files inherit from this one.

will contain all the settings that are common in all environments. The other setting files inherit from this one. development.py is for local development.

is for local development. testing.py is for testing.

is for testing. production.py will be used in the production environment.

will be used in the production environment. staging.py if you want to run a staging version on the production server of your project.

Let’s create these files, all inside the taskbuster/settings folder:

$ cd taskbuster/settings $ touch __init__.py development.py testing.py production.py staging.py 1 2 $ cd taskbuster / settings $ touch __init__ . py development . py testing . py production . py staging . py

And edit each of them (development.py, testing.py, production.py and staging.py) to make them inherit from the base.py file — we’ll create this file in a second :-):

# -*- coding: utf-8 -*- from .base import * 1 2 # -*- coding: utf-8 -*- from . base import *

And finally, we have to move and rename the settings.py file created by Django, to be our base.py file inside the settings folder. Working inside the settings folder, you have to type:

$ mv ../settings.py base.py 1 $ mv . . / settings . py base . py

After creating these files, we need to specify the virtual environment to work with the correct setting file.

With virtualenvwrapper, there is a way to configure different hooks that are sourced before or after activating the virtual environment, and before or after deactivating it. This means that we can define a set of statements that will be run at different stages of the virtual environment lifecycle. These hooks are saved inside the bin folder inside the virtual environment folder, and their names are preactivate, postactivate, predeactivate and postdeactivate.

In our case, we will set a postactivate script that will set the DJANGO_SETTINGS_MODULE variable just after activating the virtual environment, and a predeactivate that will clean it up before deactivating it.

$ workon tb_dev $ cd $VIRTUAL_ENV/bin 1 2 $ workon tb _ dev $ cd $ VIRTUAL_ENV / bin

The last command will take you to the virtual environment folder, where the different hooks reside. Edit the postactivate file by adding:

export DJANGO_SETTINGS_MODULE="taskbuster.settings.development" 1 export DJANGO_SETTINGS_MODULE = "taskbuster.settings.development"

and edit the predeactivate file by adding:

unset DJANGO_SETTINGS_MODULE 1 unset DJANGO_SETTINGS_MODULE

Do the same with the testing environment, with the only change:

export DJANGO_SETTINGS_MODULE="taskbuster.settings.testing" 1 export DJANGO_SETTINGS_MODULE = "taskbuster.settings.testing"

It’s time to check! Go back to the taskbuster_project folder and activate your development environment. Next, run:

$ python manage.py runserver 1 $ python manage . py runserver

and in the output displayed you should see a line indicating that you are using the taskbuster.development_settings file, something like:

Django version 1.8, using settings 'taskbuster.settings.development' 1 Django version 1.8 , using settings 'taskbuster.settings.development'

Open another tab (and leave the previous server active), and activate the testing environment. Check that it’s using the taskbuster.testing_settings file. Probably it will complain saying that that port is already in use by the development environment, so specify another port with

$ python manage.py runserver 127.0.0.1:8001 1 $ python manage . py runserver 127.0.0.1 : 8001

Next, quit the server in the testing environment and run the functional test:

$ python functional_tests/all_users.py 1 $ python functional_tests / all_users . py

Yes! We didn’t break anything 🙂

Production Settings – Debug False

One important thing to remember is to set the variable DEBUG to False in your production settings files.

Note: Previous to Django 1.8 you also need to set TEMPLATE_DEBUG to false. However, with the introduction of the new TEMPLATE setting, the old TEMPLATE_DEBUG is set automatically equal to DEBUG. If you really want to specify a value, check the official documentation.

First, cut the DEBUG variable from the base.py settings file and copy it into the development.py and testing.py settings files:

DEBUG = True 1 DEBUG = True

Next, add it on the production.py setting file and make it False:

DEBUG = False 1 DEBUG = False

This way, each environment will have the correct value of this variable. If you’ve also defined a staging.py file, copy it there too.

Django security and the Secret Key

If you open the file taskbuster/settings/base.py you will see a variable named SECRET_KEY . This variable should be kept secret, and therefore out of version control.

One option would be to add the base.py file into the .gitignore file, that is, remove it from the version control. However, during project development this file suffers many changes, and it’s quite useful to have it in version control, specially if you want to share it with your coworkers. Therefore, a better approach is to remove the secret key variable and import it from somewhere else. And this somewhere else is the one that should remain out of version control.

The approach we will follow here is to put the secret key inside our virtual environment configuration, and get the key from the environment by importing it in the base.py file.

Note: If you’re using Apache this method won’t work. The best option is that you save your SECRET_KEY in some file, and import it into the base.py file. The key file should be removed from version control by including it in the .gitignore file. I recommend you read the Two Scoops of Django 1.6 book, section 5.4. (You might want to check they new version, updated for Django 1.8!)

To include the secret key inside the virtual environment we will also work with the virtualenvwrapper’s postactivate and a predeactivate hooks.

Activate your tb_dev environment and go to its bin folder using the shortcut

$ cd $VIRTUAL_ENV/bin 1 $ cd $ VIRTUAL_ENV / bin

If you type ls you will see that it contains the files we just described. Edit the postactivate file and add the secret key line

export SECRET_KEY="your_secret_django_key" 1 export SECRET_KEY = "your_secret_django_key"

Note: don’t put any spaces around the = sign.

Next edit the predeactivate file and add the line:

unset SECRET_KEY 1 unset SECRET_KEY

This way, if you type:

$ workon tb_dev $ echo $SECRET_KEY your_secret_django_key $ deactivate $ echo $SECRET_KEY - 1 2 3 4 5 6 $ workon tb _ dev $ echo $ SECRET_KEY your_secret_django _ key $ deactivate $ echo $ SECRET_KEY -

Where the last line indicates that there is no output. This means that the variable SECRET_KEY is only visible when working in this virtual environment, as we wanted.

Repeat the same process for the tb_test virtual environment.

Next, deactivate and activate each environment to make these changes effective.

And finally, edit the base.py file, remove the SECRET_KEY and add the following lines:

from django.core.exceptions import ImproperlyConfigured def get_env_variable(var_name): try: return os.environ[var_name] except KeyError: error_msg = "Set the %s environment variable" % var_name raise ImproperlyConfigured(error_msg) SECRET_KEY = get_env_variable('SECRET_KEY') 1 2 3 4 5 6 7 8 9 10 from django . core . exceptions import ImproperlyConfigured def get_env_variable ( var_name ) : try : return os . environ [ var_name ] except KeyError : error_msg = "Set the %s environment variable" % var _ name raise ImproperlyConfigured ( error_msg ) SECRET_KEY = get_env_variable ( 'SECRET_KEY' )

The function get_env_variable tries to get the variable var_name from the environment, and if it doesn’t find it, it raises an ImproperlyConfigured error. This way, when you try to run your app and the SECRET_KEY variable is not found, we will be able to see a message indicating why our project fails.

Let’s check that it all works as expected. Save the base.py, deactivate both environments and activate them again, in different terminal tabs.

Run the development server in the tb_dev environment

$ python manage.py runserver 1 $ python manage . py runserver

and run the functional test in the tb_test environment

$ python functional_tests/all_users.py 1 $ python functional_tests / all_users . py

Hope the test also works for you!! 🙂

Note: When deploying your app, you will have to specify the SECRET_KEY in your server. For example, if you are using Heroku, you can use:

$ heroku config:set SECRET_KEY="your_secret_key" 1 $ heroku config : set SECRET_KEY = "your_secret_key"

But don’t worry, we’ll cover Heroku latter in this tutorial!! 🙂

Initialize a Git Repository and Commit

Ok! now we are ready to commit our project into a new repository! Note: you can read a basic git tutorial here.

Go into the taskbuster_project directory and type:

$ git init . 1 $ git init .

to initialize the repository in the current folder. You will see a new folder named .git, containing the new repository.

Before adding files into the repository, we have to think if there are files that we want to keep away from version control.

Note that after running the development server, we have the extra files:

db.sqlite3 – a database

– a database __pycache__ – a folder containing all the *.pyc files.

These two should be removed from version control. Create a .gitignore file inside the taskbuster_project foler and write:

db.sqlite3 __pycache__ TaskBuster.sublime-workspace 1 2 3 db . sqlite3 __pycache__ TaskBuster . sublime - workspace

where we have also included the sublime text workspace (as we saw in part I, sublime generates two different files when creating a project. We want the one ending with -project to be on version control but not the one ending with -workspace).

Next, let’s add all the files of the current directory into the staging area (except the ones in the .gitignore file):

$ git add . 1 $ git add .

And check the files added into the staging area with:

$ git status 1 $ git status

You should see something like this, with all the new files added in green:

If you see some file that you don’t want to commit, you can remove it using

$ git rm --cached path_of_file 1 $ git rm -- cached path_of_file

don’t forget to add it into the .gitignore file for subsequent commits.

Finally, let’s commit our changes:

$ git commit -m "Taskbuster project created" 1 $ git commit - m "Taskbuster project created"

The -m flag indicates that the following text will be used to describe this commit. If you simply type git commit, an editor will open to write the description of the commit (by default, this editor is VI).

You can see the commit made with

$ git log 1 $ git log

Upload your project into Bitbucket

Create a Bitbucket account if you don’t have one, and create a new empty repository. We use Bitbucket because it allows for a private repository, but the steps described here will work almost equal with GitHub.

You will have to determine the URL of this repository, which will be something like

https://user_name@bitbucket.org/user_name/repository_name.git

You can find it in the Overview –> Command line –> I have an existing project.

First we need to add Bitbucket as a remote repository. Go to the taskbuster_project folder and type:

$ git remote add origin https://user_name@bitbucket.org/user_name/repository_name.git 1 $ git remote add origin https : //user_name@bitbucket.org/user_name/repository_name.git

where you should change the url with your repository url. Note: The previous command is a single line. This will create the alias origin to refer to your Bitbucket repository (using origin as an alias for a remote repository is a common convention).

Next, let’s push our existing repository into this new Bitbucket repository with:

$ git push -u origin --all 1 $ git push - u origin -- all

where the –all flag makes all the refs under refs/heads to be pushed, and the -u flag stands for –set-upstream (add a tracking reference). You will have to enter your password.

At the end, you will see the message:

Branch master set up to track remote branch master from origin. 1 Branch master set up to track remote branch master from origin .

You can see your active branches with

$ git branch -a * master remotes/origin/master 1 2 3 $ git branch - a * master remotes / origin / master

Okey! Now that we have our first project with a good working environment, and in version control, we can work on our Home Page!

But… I’m not talking about creating models yet, just configure the static files and templates to have a nice Home Page with some CSS — I hate developing without a basic CSS, so it’s one of the first things I usually include.

Find out this and more in the next part of the tutorial! Create a Home Page with TDD, Staticfiles and Templates settings

Please, share this Tutorial with your developer friends! 😉