Django project template for starting a new project.
This project assumes at least a passing familiarity with Django and the Terminal window. If you haven't done so, it is highly recommended that those unfamiliar with the Terminal window begin with The Designer's Guide to the OSX Command Prompt and those unfamiliar with Django read through the tutorial to understand some of the concepts discussed below.
To start a new project with this template, execute:
django-admin.py startproject --template=https://github.com/jbergantine/django-newproj-template/zipball/master --extension=py,rst <project_name>
However, this template is intended to be used in conjunction with Vagrant as part of a broader project as documented in the Usage directions below.
Vagrant offers the ability to create unique virtual machines on a per-project basis. Using Vagrant you can install system-level libraries without conflicting with other projects and share virtual machines with others on your team so you're all using the same thing.
These instructions go through the configuration of a new Ubuntu 64-bit operating system on a Vagrant Box hosted on an Apple Macintosh computer with Git and Curl as a minimum. These same set of instructions should work on a Linux box with a similar configuration.
Using the Vagrant box requires you to interact with manage.py from within the virtual environment although you can use a text editor or IDE of your choice for editing on your host system via a shared folder and you can access the site through a web browser of your choice by taking advantage of port forwarding between the virtual environment and the host.
This configuration uses a post-merge Git hook to sync/migrate the database and compile SASS, as such managing Git must be done within the virtual environment as well rather than through the Tower or GitHub apps for example on the host. For simplicity sake it is recommended that SASS stylesheets be compiled within the virtual environment and a shortcut is added to the bash profile to help facilitate this as well rather than using an app like Scout on the host.
The Vagrantfile configures a virtual environment to include:
- Python 2.7.3
- PIP
- Virtualenv
- VirtualenvWrapper
- Postgres 9.1
- Git
- libfreetype
- libjpeg
- zlib
- Xapian
Additionally, the Vagrantfile installs the recipes from a Chef Cookbook (Chef-Cookbook-DjangoNewProj) intended to be used with this project which sets up a new Django project called myproject in a virtual environment named djangoproj and connects that to a PostgreSQL database called django_db.
This template sets up a number of defaults for django-admin.py startproject
by making a number of assumptions about your preferences, application choices, encouraging a particular dev environment configuration and by loading in an initial set of templates, and if used as intended, CSS files and JavaScript libraries.
This should be obvious by now.
These are defacto standards for Python development. Virtualenv allows you to have multiple versions of packages installed on one machine which it collects into sets called "virtual environments". PIP is a package manager for installing, updating and removing packages.
This template sets up separate development and production settings files that inherit from a common base settings file.
Chef-Cookbook-DjangoNewProj configures postactivate and postdeactivate virtualenv hooks for specifying the proper settings file when working in the virtual environment within Vagrant for development so the --settings=
flag doesn't need to be explicitly used. Something similar will need to be done in production.
This settings files in this template are explicitly configured to connect to a PostgreSQL server.
Chef-Cookbook-DjangoNewProj configures your Django project for use with a PostgreSQL database (django_db) which it installs along with a user (django_login) for said database and installs South for database migrations.
This template includes a sitemaps module (sitemaps.py) which is initially configured to create a sitemaps XML file referencing "static" pages of a site but which can be expanded to most any application. The sitemap module is imported into urls.py which sets up routing.
This template also installs Django-Robots, a small app for creating a robots.txt file.
The settings file in this template reference django_mobile middleware and templatetags to do device detection for making server or template-level modifications on a platform or device level.
Chef-Cookbook-DjangoNewProj installs django-floppyforms to take advantage of HTML5 form fields to greatly enhance the mobile user experience.
This template includes a fabfile with a number of pre-configured methods for deployment and server management.
By default the base.html template has an HTML5 doctype. For backwards compatibility Chef-Cookbook-DjangoNewProj installs modernizr.js with an HTML5 shiv for older versions of Internet Explorer to keep them from puking. Finally, Chef-Cookbook-DjangoNewProj installs and configures Compass to instantiate the Compass +global-reset
mixin which resets HTML5 element's display-roles for older browsers.
Chef-Cookbook-DjangoNewProj installs Xapian with Python bindings. You will have to additionally install the django-haystack and xapian-haystack Python packages and configure the project to use this.
Chef-Cookbook-DjangoNewProj installs the necessary libraries (libjpeg, libfreetype, zlib) to use PIL (you will have to still install the pil Python package, however). To use SORL-Thumbnail you will have to install the pil and sorl-thumbanil Python packages and configure the project as appropriate.
Review stable-req.txt for other default application choices.
(host)
is for commands to run on the host machine, and (vm)
is
for commands to run inside the VM.
This step only ever needs to be done once. Once the precise64 box is installed on a system the remaining steps refer to that same box regardless of the project.
Download virtualbox from http://www.virtualbox.org/wiki/Downloads, install dmg.
Download vagrant from http://downloads.vagrantup.com/, install dmg.
Launch a terminal window, check that it installed:
(host) $ which vagrant
Add a vagrant box (we'll be using Ubuntu Precise Pangolin (12.04 LTS) 64-bit):
(host) $ vagrant box add precise64 http://files.vagrantup.com/precise64.box
Make a directory for the project and change to it, replacing <path_to>
with the path to the project and <project_name>
with the name of the project.
(host) $ mkdir <path_to>/<project_name> && cd $_
For example, to create a project called 'website' in your home directory:
(host) $ mkdir ~/website && cd $_
When you're all done, this directory will contain a directory named myproject that matches up with /vagrant/myproject in the virtual envirionment. Virtualbox keeps the two directories in sync so changes to one will be made in the other. This directory contains Django's manage.py file as well as the project's fabfile and PIP requirements doc. Within it is a second myproject directory which contains the Django project. On your host launch the text editor of your choice (Panic Coda, TextMate, Sublime, whatever), make edits to any of these files and those edits will be reflected in the virtual environment immediately.
Create a place for the Chef cookbooks. From within the Vagrant project directory on the host run the following command.
So, extending our example, this would be run from within ~/website/.
(host) $ mkdir cookbooks && cd $_
Clone the Chef cookbooks repositories as needed (we will use the following cookbooks in this guide).
(host) $ git clone git://github.com/opscode-cookbooks/apt.git
(host) $ git clone git://github.com/opscode-cookbooks/build-essential.git
(host) $ git clone git://github.com/opscode-cookbooks/git.git
(host) $ git clone git://github.com/opscode-cookbooks/openssl.git
(host) $ git clone git://github.com/opscode-cookbooks/postgresql.git
(host) $ git clone git://github.com/opscode-cookbooks/python.git
(host) $ git clone git://github.com/opscode-cookbooks/zlib.git
(host) $ git clone git://github.com/jbergantine/chef-cookbook-python-psycopg2.git
(host) $ git clone git://github.com/jbergantine/chef-cookbook-libjpeg.git
(host) $ git clone git://github.com/jbergantine/chef-cookbook-libfreetype.git
(host) $ git clone git://github.com/jbergantine/chef-cookbook-xapian.git
(host) $ git clone git://github.com/jbergantine/chef-cookbook-djangonewproj.git
Back out of the cookbooks directory and copy in the Vagrantfile.
(host) $ cd ../; curl https://raw.github.com/gist/3875868/gistfile1.rb > Vagrantfile
Startup Vagrant and install cookbooks (first time through), use $ vagrant provision
instead if you mess something up and have to go through it again:
(host) $ vagrant up
SSH in to the virtualbox:
(host) $ vagrant ssh
Creating keys makes pushing and pulling changes from Bitbucket or GitHub or the server a lot easier since you will only have one password to remember.
SSH into the box if you aren't already, from the project directory (the one you made in using the new Vagrant Base Box) on your host system run:
(host) $ vagrant up
(host) $ vagrant ssh
Move into the ~/.ssh directory:
(vm) $ cd ~/.ssh
Create the key, replacing your_email@youremail.com with your email address:
(vm) $ ssh-keygen -t rsa -C “your_email@youremail.com”
When prompted with "Enter file in which to save the key (/home/vagrant/.ssh/id_rsa):" hit the return key to accept the default value.
When prompted for a passphrase enter a strong passphrase and hit the return key or hit the return key to create a key without a passphrase.
Print the public key to the terminal window. The following will spit out about 5 lines of text beginning with "ssh-rsa" and ending with your email address. Once you've ran the following command, select all of its output with your mouse and copy it (Command + C should do it to copy it).
(vm) $ cat id_rsa.pub
Now login to GitHub or Bitbucket or whatever service you're using for Git and add a new key for your account, pasting in the public key from your clipboard. You should now be able to push, pull and clone without having to enter a passphrase for the account (if you set a passphrase for the key you will have to enter that).
Label your commits with your name.
(vm) $ git config --global user.name "Your Name Here"
Git saves your email address into the commits you make. GitHub uses the email address to associate your commits with your GitHub account.
(vm) $ git config --global user.email "your_email@youremail.com"
This project utilizes separate settings files for development and production that both inherit from a common base file.
- Set
ADMINS
andMANAGERS
for both local and production. - Set
EMAIL_HOST
,EMAIL_HOST_USER
,EMAIL_HOST_PASSWORD
,DEFAULT_FROM_EMAIL
values for both local and production. - Set all
DATABASES
settings for production. - Set
MEDIA_ROOT
,MEDIA_URL
, andSTATIC_ROOT
for production. - Set production
CACHES
. - Change your
TIME_ZONE
if desired.
- Configure the environments and default call to Python as described in the Configuration notes within the file. Read the full configuration and usage notes to understand how the fabfile works with the production environment.
Update the 500 Error template
- Replace
[email address]
(2 occurrences) with an email address for the system administrator.
Update the base template
- There are numerous things to update and customize here including the Google Analytics account number, default Facebook Graph API data, creating the favicon and Apple Touch icons and putting them in the locations referenced, TypeKit script files, the name of the site in the
<title>
tag and site meta data.
If you've been configuring your SSH Keys, you'll need to move back to /vagrant/ before continuing.
(vm) $ cd /vagrant/
Additionally, make sure you're working on the djangoproj virtual environment. You should be able to see this in the terminal prompt. It should look like:
(djangoproj)vagrant@precise64:/vagrant/myproject$
The bit in parens at the beginning is the name of the virtual environment (djangoproj). It is followed by the current user (vagrant), the name of the host (precise64) and the current directory (/vagrant/myrpoject). If you're not working on the djangoproj project, run the following virtualenvwrapper command to instantiate it:
(vm) $ workon djangoproj
(vm) $ git add -A
(vm) $ git commit -am "initial commit"
(vm) $ cd /vagrant/myproject/
(vm) $ dj syncdb
(vm) $ dj migrate
The Vagrantfile forwards port 8000 on the virtual environment to port 8001 on the host. In order to access the site in a browser on the host when you execute $ runserver
on the virtual environment, you need to add a port configuration to the runserver command:
python manage.py runserver [::]:8000
Chef-Cookbook-DjangoNewProj sets up a bash alias to avoid keyboard fatigue when running this command:
(vm) $ rs
(vm) $ cw
Note that you will likely want to have both runserver and compass watch running at the same time so you can review your changes in a web browser. To do this SSH into Vagrant from two different terminal windows on your host, on one window execute $ rs
and in the other execute $ cw
.
This template includes a number of HTML templates and template tags as well as other things.
A hook that runs every time a merge is made. A merge will happen every time $ git pull
is executed (and there are changes to be brought in; it won't happen if there are no changes) in addition to the explicit $ git merge
command. This hook will compile stylesheets, sync and migrate the database and install new requirements if stable-req.txt is updated. This hook lives in .git/hooks/post-merge and can be disabled by either removing the file (post-merge) or making it non-executable. If you want to use Scout to compile SASS or use Tower or a similar application to manage Git you will want to disable or remove this hook as it relies on the presence of SASS, Compass, Susy, Django and a database among other things.
A default 404-type error page. Required for production deployment.
A default 500-type error page. Required for production deployment.
A default template to base other templates off of. Loads base.html and includes all the customizable blocks from that template. Copy this when creating new pages. eg:
$ cp __default.html home.html
An include for forms that creates properly-semantically-structured forms. To use it, include it within the body of a form like so:
<form action="" method="post">
{% csrf_token %}
{% include "_form_snippet.html" %}
<div>
<input type="submit" value="Submit" id="submit" />
</div>
</form>
Global site nav. Built as an include to be placed on the header or footer of the site depending on whether the site is being viewed on a mobile device or not.
The basis to inherit all other templates off of. A responsive-design (mobile) friendly HTML5 template. Sitewide stylesheets and script files are referenced in the appropriate places and wrapped in django-compressor to minimize page load times. This template also includes Google Analytics, default meta data and Facebook Graph API data for page sharing purposes as well as a link to a favicon and Apple Touch icons for Web application development purposes.
When you run the script to create the project, the script downloads the latest version of jQuery (which is then referenced both locally and via Google's AJAX load in base.html) as well as a customized basic version of modernizr.js which includes only the shims for the HTML5 doctype.
This project utilizes the Compass SASS framework and creates a stylesheet directory following the requirements of that application. CSS files will be created in the appropriate spots the first time you run either $ compass watch static_media/stylesheets
or $ compass compile static_media/stylesheets
. The bash shortcut cw
is set up to reduce keyboard fatigue.
Documentation for these files is contained in a seperate repo.
A stylesheet specifically for dealing with modifications necessary for Internet Explorer. Meant to be used in a way that styles defined here override screen.sass.
Returns a specific number of entries for a particular model. (If the model is sorted by date published they will be sorted that way hence the name get_latest_content.)
Example usage:
{% load fetch_content %}
{% get_latest_content application_name.model_name 5 as foo %}
{% for bar in foo %}
{{ bar.attribute }}
{% endfor %}
Can also be used to return all entries for a particular model.
Example usage:
{% load fetch_content %}
{% get_all_content application_name.model_name as foo %}
{% for bar in foo %}
{{ bar.attribute }}
{% endfor %}
Handles navigation item selection.
Example usage:
{# Set up the variable for use across context-stacking tags #}
{% nav %} or {% nav for mynav %}
{# Set the context so {{ nav.home }} (or {{ mynav.home }}) is True #}
{% nav "home" %} or {% nav "home" for mynav %}
The most basic (and common) use of the tag is to call {% nav [item] %}
,
where [item]
is the item you want to check is selected.
By default, this tag creates a nav
context variable. To use an
alternate context variable name, call {% nav [item] for [var_name] %}
.
To use this tag across {% block %}
tags (or other context-stacking
template tags such as {% for %}
), call the tag without specifying an
item.
Your HTML navigation template should look something like:
{% block nav %}
<ul class="nav">
<li{% if nav.home %} class="selected"{% endif %}><a href="/">Home</a></li>
<li{% if nav.about %} class="selected"{% endif %}><a href="/about/">About</a></li>
</ul>
{% endblock %}
To override this in a child template, you'd do:
{% include "base.html" %}
{% load nav %}
{% block nav %}
{% nav "about" %}
{{ block.super }}
{% endblock %}
This works for multiple levels of template inheritance, due to the fact
that the tag only does anything if the nav
context variable does not
exist. So only the first {% nav %}
call found will ever be processed.
To create a sub-menu you can check against, dot-separate the item:
{% nav "about_menu.info" %}
This will be pass for both {% if nav.about_menu %}
and
{% if nav.about_menu.info %}
.
From: http://djangosnippets.org/snippets/17/
"Widows" are single words that end up on their own line, thanks to automatic line-breaks. This is an no-no in graphic design, and is especially unsightly in headers and other short bursts of text. This filter automatically replaces the space before the last word of the passed value with a non-breaking space, ensuring there is always at least two words on any given line. Usage is like so:
{{ blog.entry.headline|widont }}
(vm) $ exit
(host) $ vagrant halt
(host) $ vagrant suspend
(host) $ vagrant up
(host) $ vagrant destroy
(host) $ vagrant status
(host) $ vagrant provision
More information is available in the Vagrant documentation.
Replacing <virtualenv_name>
with the name of the virtual environement (IE: djangoproj
).
(vm) $ mkvirtualenv <virtualenv_name>
(vm) $ workon <virtualenv_name>
(vm) $ deactivate
(vm) rmvirtualenv <virtualenv_name>
(vm) $ pip freeze
The output of this command can be routed to a file as in:
(vm) $ pip freeze > <path_to_file>
As in:
(vm) $ pip freeze > requirements.txt
(vm) $ pip install <package_name>
(vm) $ pip install <package_name> --upgrade
(vm) $ pip install <package_name>==x.x.x
(vm) pip install -r <path_to_file>
As in:
(vm) $ pip install -r requirements.txt
(vm) $ pip uninstall <package_name>
The following bash aliases are added to the shell.
cw | compass watch myproject/static_media/stylesheets |
---|
dj |
python manage.py Example usage, interact with the Django shell: dj shell |
---|
rs |
python manage.py runserver [::]:8000 This is necessary to enable port forwarding from the virtual machine to the host. In a host the site will now be available at http://127.0.0.1:8001. |
---|---|
sh | python manage.py shell |
br | branch |
---|---|
ci | commit |
co | checkout |
st | status |
ga | git add |
---|---|
gb | git branch |
gco | git checkout |
gl | git pull |
gp | git push |
gst | git status |
gss | git status -s |
py |
python Launches a Python interactive shell. |
---|---|
pyclean |
find . -name "*.pyc" -delete Removes all files ending in ".pyc". |