Let's Take Notes With Django - Part 1

Let's Take Notes With Django - Part 1

part of the Startproject To Deployment - Django Tutorial series

show all in series

back to index

There's no shortage of tutorials out there telling you how to set up a new Django project. Let's add one more to the pile.

We're going to make a simple note-taking application with Django, from startproject to deploying online. There are many, many different ways to go about doing this. This is just one path. We're going to work with Django 1.7, Python 2.7, and eventually nginx/gunicorn on Ubuntu 14.04.

(Note: this tutorial is compatible through Django version 1.9)

First things first, let's talk about the application we'll be building - DjangoNote! Our goal is simple: we want to be able to visit a website and privately record our innermost thoughts from time to time. We'll expand this with some additional functionality later on, but this is a great jumping-off point with plenty to start working on:

1. Basic project layout and design
2. Model & ModelForm architecture
3. User authentication
4. User gating
5. Basic static file management and deployment
6. Fun with databases
7. Making things only moderately ugly with some minimal CSS & javascript
8. A teeny-tiny bit of server stuff during deployment
9. Maintaining sanity through the use of git

Before we hit startproject, we'll need to think for a moment about how we want to lay out our DjangoNote project.

First we're going to create a top-level directory called djangonote_project then cd into it. This project directory is going to serve as the root of our git repo (which we'll get to later), and will also hold our docs directory, our readme.rst and our requirements.txt. Our readme file will be a brief description of the cool stuff we're doing, and our requirements file will detail any stuff a user would need to install to run our code. In fact, we can go ahead and create both files inside this djangonote_project directory.

# /djangonote_project/readme.rst
A cool project that lets a user store private notes online!

If we format our requirements.txt properly, it can be used to automagically install our requirements later. We won't use that feature in this tutorial, but it's nice to include for others. We've only got a couple right now. By the way, this would be a good time to pip install django-extensions:

# /djangonote_project/requirements.txt
Django==1.7.0
django-extensions==1.3.11

Now let's start our DjangoNote project. While still in the djangonote_project directory, we'll fire things up with django-admin.py startproject djangonote. Once you do that, your djangonote_project directory should contain three items: a requirements file, a readme file, and a new directory called djangonote. Let's cd into that new directory.

In djangonote_project/djangonote, we find two items: another directory called djangonote, and a file called manage.py. This is the core of our budding project, which we will extend with our first app soon. Remember, in Django a project is made up of one or more apps. Let's look inside our new djangonote directory and see what's inside.

Four files have been created for us in the djangonote_project/djangonote/djangonote directory: __init__.py, settings.py, urls.py and wsgi.code. Let's open up settings.py first and make some basic tweaks.

When you open the file with the editor of your choice, you'll immediately see that quite a lot of boilerplate code has been taken care of for you - sweet! Let's add a couple of things to make it our own. The first two uncommented lines in your settings.py file look like this:

import os
BASE_DIR = os.path.dirname(os.path.dirname(__file__))

This tells our Django project where to find the "base directory" for everything. We're going to have some HTML templates in our project that we'll want to reference, and this is a sensible place to define where it'll be. We'll add one line below the BASE_DIR definition:

import os
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
TEMPLATE_DIRS = [os.path.join(BASE_DIR, 'templates')]

Just so we don't forget later, let's go ahead and mkdir templates one directory up - in the same directory as your manage.py file.

A little farther down in our settings.py file we'll find this line:

ALLOWED_HOSTS = []

We're in the early building-and-debugging stage of things, so we're not going to worry too much about this for now. Let's change it to this:

ALLOWED_HOSTS = ['*']

This will work for development, but don't leave it on in production or everyone in Hong Kong is going to use your server as a proxy and eat up your resources.

Just below the ALLOWED_HOSTS definition, we find our INSTALLED_APPS:

INSTALLED_APPS = (
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
)

Every time we create a new app or add a new django package, we'll need to include it here. The only one we've got so far is django_extensions, but we'll have one more soon when we start our project's first application. We're going to call our app "notes," so let's go ahead and include both now.

INSTALLED_APPS = (
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'django_extensions',
'notes',
)

Let's skip down and take a look at the database info that's been automatically generated for us:

DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}

You have plenty of options for your database backend, and you can lose plenty of braincells listening to people try to talk you into using a NoSQL solution, but we're just going to keep it simple and effective: sqlite for development, and postgresql for production. This gives us the best of both worlds. In development, having a database that is essentially just a text file is the height of convenience. Make a mistake and need to dump the db? Just delete the file and sync it again. In production, postgresql is fast, reliable, and easy to set up. We don't have to worry about making any changes here until we're closer to deployment, so let's move on.

(But but but MongoDB is web scale...)

The very last line in our settings.py file defines a STATIC_URL. Static deployment is often a point of confusion for programmers new to Django. We're going to add two items to the end of our settings.py file to make life with our static assets more bearable. We're going to define a STATIC_ROOT and a STATICFILES_DIRS. Later on, after deployment, running python manage.py collectstatic will collect the files in our STATICFILES_DIR and copy them to our STATIC_ROOT. Add the two definitions below your STATIC_URL, then mkdir static back in the directory with manage.py and your new templates directory.

STATIC_ROOT = '/var/www/souldeux/static'
STATICFILES_DIRS = (
os.path.join(BASE_DIR, "static"),
)

We're done with our settings.py for right now. Back in our main djangonote_project/djangonote directory, we now have four files: our core djangonote directory, manage.py, and the two empty directories we created: templates and static.

The way Django collects static assets can be quirky, and the best practice is to "nest" our local static directory by one level. Inside our static directory, we're going to mkdir djangonote. Later, we'll place our static assets in djangonote_project/djangonote/static/djangonote.

Back in djangonote_project/djangonote, let's start our first application - Notes. Executing django-admin.py startapp notes gives us a brand-new notes directory to play in. Take a look inside to see the stuff we'll be tinkering with soon - a small amount of boilerplate has been automatically created for us. In part 2, we'll start customizing these files - that's when our project really starts to take shape!

Continue to Part 2


<< back to blog index