Django Tutorial: Building a note taking app

Django

If you want to start with python web development, you could use a web framework named Django. It is designed to be fast, secure and scalable. It comes with an object-relational mapper (ORM), which means that objects in Python are mapped to objects in a database.

Applications created with Django are separated in three separate layers: model (database), view (appearance) and controller (logic), or shortly themodel-view-controller (MVC) architecture.

Related courses

Setting up Django

Start with:

django-admin startproject mysite

This will create the directory mysite. Open mysite/mysite/settings.py. You can configure your desired database here:

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

Pick from sqlite3, postgresql_psycopg2, mysql or oracle. Name is the name of your database. If you use SQLite the database will be created automatically. For MySQL and Postgresql you need to create the database yourself. Go up one directory to /mysite/ and run:

python manage.py runserver

The terminal should say:

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 manage.py migrate' to apply them.
 
August 16, 2015 - 14:45:29
Django version 1.7.1, using settings 'myapp.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
[16/Aug/2015 14:45:35] "GET / HTTP/1.1" 200 1759

Open http://127.0.0.1:8000 in your web browser and you should see:

django
Our first Django app.

Now we created a project, we create an app. A project can have many apps.

python manage.py startapp notes

This creates the files:

notes/
    __init__.py
    admin.py
    migrations/
        __init__.py
    models.py
    tests.py
    views.py

Django database model

Change /mysite/notes/models.py to:

from django.db import models
 
class Note(models.Model):
    text = models.CharField(max_length=120)
    created = models.DateTimeField(auto_now_add=True)

Open /mysite/mysite/settings.py, add the web app:

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

Run

python manage.py syncdb

which will update the database. We then update /mysite/mysite/admin.py to:

from django.contrib import admin
 
# Register your models here.
from .models import Note
 
class NoteAdmin(admin.ModelAdmin):
    class Meta:
        model = Note
 
admin.site.register(Note,NoteAdmin)

Run:

python manage.py makemigrations notes
python manage.py migrate

Start your server using:

manage.py runserver

Once you open up the admin panel http://127.0.0.1:8000/admin, Notes will appear on the page:

django_admin
Django admin panel

If you click on notes you can view all notes and add/delete them:

django_database
Django database admin menu.

Show the data

We have all our data in the database, now we want to create our app. Open /mysite/settings.py and add:

#print "base dir path", BASE_DIR
#print os.path.join(os.path.dirname(BASE_DIR), "mysite", "static",  "templates")
 
TEMPLATE_DIRS = (
    os.path.join(os.path.dirname(BASE_DIR), "mysite", "static",  "templates"),
    #'/home/frankbox/python/djangoapp/mysite/static/templates',
)

to the bottom of the file. This defines the directory of our templates (html).

Change /mysite/mysite/urls.py to:

from django.conf.urls import patterns, include, url
from django.contrib import admin
 
urlpatterns = patterns('',
    # Examples:
    # url(r'^$', 'mysite.views.home', name='home'),
    # url(r'^blog/', include('blog.urls')),
    url(r'^$', 'notes.views.home', name='home'),
    url(r'^admin/', include(admin.site.urls)),
)

Finally create /mysite/static/templates/ and add note.html, which is a simple static html file.

<!DOCTYPE html>
    <html>
        <head>
        </head>
 
        <body>
            <b>Hello</b>
        </body>
    </html>

Open http://127.0.0.1:8000/ to test if works. Change note.html to:

<!DOCTYPE html>
    <html>
        <head>
        </head>
 
        <body>
          <h2>Notes</h2>
          <ul>
          {% for note in notes.all %}
              <li>{{ note.text }}</li>
          {% endfor %}
        </ul>
        </body>
    </html>

Then open /mysite/notes/views.py and change to:

from django.shortcuts import render, render_to_response, RequestContext
from django.template import RequestContext, loader
from django.http import HttpResponse
from .models import Note
 
# Create your views here.
 
def home(request):
    notes = Note.objects
    template = loader.get_template('note.html')
    context = {'notes': notes}
    return render(request, 'note.html', context)
    #return render_to_response("note.html", notes)

Once you fire up your browser you will see the list of notes:

django app
django app

Insert data

While it’s nice to have a list, we want to add some notes to it.
Create the file /mysite/notes/forms.py

from django import forms
from .models import Note
 
class NoteForm(forms.ModelForm):
    class Meta:
        model = Note

Change view.py to:

from django.shortcuts import render, render_to_response, RequestContext
from django.template import RequestContext, loader
from django.http import HttpResponse
from .models import Note
from .forms import NoteForm
 
# Create your views here.
 
def home(request):
    notes = Note.objects
    template = loader.get_template('note.html')
    form = NoteForm(request.POST or None)
    if form.is_valid():
        save_it = form.save(commit=False)
        save_it.save() 
 
    context = {'notes': notes, 'form': form}
    return render(request, 'note.html', context)
    #return render_to_response("note.html", notes)

Finally we update note.html to:

<!DOCTYPE html>
    <html>
        <head>
        </head>
 
        <body>
          <h2>Notes</h2>
          <ul>
          {% for note in notes.all %}
              <li>{{ note.text }}</li>
          {% endfor %}
        </ul>
 
        <form method='POST' action=''>{% csrf_token %}
            {{ form.as_p }}
            <input type='submit'>
        </form>
 
        </body>
    </html>

Run it and we have our note taking app 🙂

django_app_insert
Djano note taking app

Styling the app

By modifying the note.html we can style it like any other html/css website. If you change note.html to:

<!DOCTYPE html>
    <html>
        <head>
            <link href="http://codepen.io/edbond88/pen/CcgvA.css" media="screen" rel="stylesheet" type="text/css" />
            <style>
            body {
              background: rgba(222,222,222,1);
              margin: 20px;
            }
            </style>
        </head>
 
        <body>
          <h1>Django Note Taking App</h1>
 
          {% for note in notes.all %}
            <aside class="note-wrap note-white">
              <li>{{ note.text }}</li>
            </aside>
          {% endfor %}
 
        <form method='POST' action=''>{% csrf_token %}
            {{ form.as_p }}
            <input type='submit' value='Add note'>
        </form>
 
        </body>
    </html>

You will get:

django_note_app
Django note taking app

 

 

ORM with SqlAlchemy

An object relational mapper maps a relational database system to objects.  If you are unfamiliar with object orientated programming, read this tutorial first. The ORM is independent of which relational database system is used. From within Python, you can talk to objects and the ORM will map it to the database. In this article you will learn to use the SqlAlchemy ORM.

What an ORM does is shown in an illustration below:

ORM Object Relational Mapping
ORM Object Relational Mapping. We communicate with the database using the ORM and only use Python objects and classes.

Related courses

Creating a class to feed the ORM
We create the file tabledef.py. In this file we will define a class Student. An abstract visualization of the class below:

class
Class definition

Observe we do not define any methods, only variables of the class. This is because we will map this class to the database and thus won’t need any methods.

This is the contents of tabledef.py:

from sqlalchemy import *
from sqlalchemy import create_engine, ForeignKey
from sqlalchemy import Column, Date, Integer, String
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship, backref
 
engine = create_engine('sqlite:///student.db', echo=True)
Base = declarative_base()
 
########################################################################
class Student(Base):
    """"""
    __tablename__ = "student"
 
    id = Column(Integer, primary_key=True)
    username = Column(String)
    firstname = Column(String)
    lastname = Column(String)
    university = Column(String)
 
    #----------------------------------------------------------------------
    def __init__(self, username, firstname, lastname, university):
        """"""
        self.username = username
        self.firstname = firstname
        self.lastname = lastname
        self.university = university
 
# create tables
Base.metadata.create_all(engine)

Execute with:

python tabledef.py

The ORM created the database file tabledef.py.  It  will output the SQL query to the screen, in our case it showed:

CREATE TABLE student (
	id INTEGER NOT NULL, 
	username VARCHAR, 
	firstname VARCHAR, 
	lastname VARCHAR, 
	university VARCHAR, 
	PRIMARY KEY (id)
)

Thus, while we defined a class, the ORM created the database table for us. This table is still empty.

Inserting data into the database
The database table is still empty. We can insert data into the database using Python objects. Because we use the SqlAlchemy ORM we do not have to write a single SQL query. We now simply create Python objects that we feed to the ORM.  Save the code below as dummy.py

import datetime
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from tabledef import *
 
engine = create_engine('sqlite:///student.db', echo=True)
 
# create a Session
Session = sessionmaker(bind=engine)
session = Session()
 
# Create objects  
user = Student("james","James","Boogie","MIT")
session.add(user)
 
user = Student("lara","Lara","Miami","UU")
session.add(user)
 
user = Student("eric","Eric","York","Stanford")
session.add(user)
 
# commit the record the database
session.commit()

Execute with:

python dummy.py

The ORM will map the Python objects to a relational database. This means you do not have any direct interaction from your application, you simply interact with objects. If you open the database with SQLiteman or an SQLite database application you’ll find the table has been created:

Data in database table.
Data in database table.

Query the data
We can query all items of the table using the code below. Note that Python will see every record as a unique object as defined by the Students class. Save the code as demo.py

import datetime
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from tabledef import *
 
engine = create_engine('sqlite:///student.db', echo=True)
 
# create a Session
Session = sessionmaker(bind=engine)
session = Session()
 
# Create objects  
for student in session.query(Student).order_by(Student.id):
    print student.firstname, student.lastname

On execution you will see:

James Boogie
Lara Miami
Eric York

To select a single object use  the filter() method. A demonstration below:

import datetime
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from tabledef import *
 
engine = create_engine('sqlite:///student.db', echo=True)
 
# create a Session
Session = sessionmaker(bind=engine)
session = Session()
 
# Select objects  
for student in session.query(Student).filter(Student.firstname == 'Eric'):
    print student.firstname, student.lastname

Output:

Eric York

Finally, if you do not want the ORM the output any of the SQL queries change the create_engine statement to:

engine = create_engine('sqlite:///student.db', echo=False)