building web pages with python extras

Extra Features

Making Notebook More Fashionable

OK, I realize we've been working with a standard XHTML document with absolutely no formatting this whole time. If you're interested, here's the CSS style sheet I use:

body {
    font-family: Arial, sans-serif;
}

a {
    text-decoration: none;
}

ul {
    list-style-type: none;
}

label {
    font-size: 14px;
}
input {
    font-size: 20px;
}

textarea {
    font-size: 14px;
}

#header {
    border-bottom: 1px solid #000000;
}

#header h1, #header h1 a {
    color: #92C25F;
}

#content {
    float: left;
    width: 65%;
}

#content a {
    color: #718E58;
}

#content .add {
    list-style-image: url('/static/images/page_add.png');
}

#content .existing {
    margin-left: -20px;
}

#content del {
    color: #C2CDCF;
    text-decoration: none;
}

#content del:after {
    content: " ";
}

#content ins {
    text-decoration: none;
}

#sidebar {
    margin-top: 7px;
    margin-right: 7px;
    float: right;
    background-color: #EDF5F8;
    padding: 15px;
    border: 1px solid #5D657A;
}

#sidebar h3 {
    margin-top: -3px;
}

#sidebar a {
    color: #5D657A;
}

#sidebar ul {
    margin-left: -35px;
}

#sidebar .functions {
    margin-left: -10px;
}

#sidebar .edit {
    list-style-image: url('/static/images/page_edit.png');
}

#sidebar .delete {
    list-style-image: url('/static/images/page_delete.png');
}

Simply replace your blank style sheet in /static/styles with this one.

The icons I use are from the FamFamFam Silk package.

Working with Categories

Though we've created functions to view, add, edit, and delete Notes, we did not do anything with Categories. In fact, Categories were only added directly through the SQLite shell.

Of course it's perfectly possible to add support to add, edit, and delete Categories, but I'm going to leave that up to you, the reader. If I've done a decent job at describing this whole process, adding support to manipulate Categories should be cake. But as a hint, here is what the completed addEdit.py controller would look like:

from base import *

class note(baseWebpy):
    def GET(self, note_id=""):
        if note_id and noteExists(note_id):
            note = makeWritable(getNotes(note_id)[0])
        else:
            note = {}       
        return sendData('addNote', {
            'form': createAddNoteForm(note)
        })

    def POST(self, note_id=""):
        i = formData(self.request.form)
        eForm = validateAddNoteForm(i)
        if eForm:
            return sendData('addNote', {
                'form': eForm
            })
        else:
            try:
                note_id = addEditNote(i)
                return redirect('/view/note/%s' % str(note_id))
            except Exception, e:
                return HttpResponse(traceback.format_exc())

class category(baseWebpy):
    def GET(self, category_id=""):
        if category_id and categoryExists(category_id):
            category = makeWritable(getCategories(category_id)[0])
        else:
            category = {}
        return sendData('addCategory', {
            'form': createAddCategoryForm(category)
        })

    def POST(self, category_id=""):
        i = formData(self.request.form)
        eForm = validateAddCategoryForm(i)
        if eForm:
            return sendData('addCategory', {
                'form': eForm
            })
        else:
            try:
                id = addEditCategory(i)
                return redirect('/')
            except Exception, e:
                return HttpResponse(traceback.format_exc())

Publishing to Apache

To get this web application to run through Apache, it's not that hard at all. First, you'll need to make sure you have FastCGI installed and working. Second, you need to create a wrapper script to run the application. Here's what mine looks like:

#!/usr/bin/python
from flup.server.fcgi import WSGIServer
from app import app as appy

WSGIServer(appy).run()

As you can see, it uses Flup. The installation for Flup was described way back in Part 2.

Third, you need to configure Apache to host the site. Personally, I have mine in a VirtualHost. It looks like this:

<VirtualHost *:80>
  RewriteEngine On
  RewriteCond %{REQUEST_URI} ^/$
  RewriteRule ^(.*)$ /wrap.py/index/
  RewriteCond /Users/joe/Sites/notebook/%{REQUEST_URI} !-f 
  RewriteCond /Users/joe/Sites/notebook/%{REQUEST_URI} !-d 
  RewriteRule ^(.*)$ /wrap.py$1 [L]

  ServerName notebook
  DocumentRoot /Users/joe/Sites/notebook
  ErrorLog /var/log/httpd/notebook-error.log
  CustomLog /var/log/httpd/notebook-access.log combined

  <Directory /Users/joe/Sites/notebook>
    Options ExecCGI
    <Files wrap.py>
      SetHandler fastcgi-script
    </Files>
  </Directory>
</VirtualHost>

As far as Apache configuration goes, this is pretty standard. I'm using the Rewrite Engine to map the URLs to the wrap.py script.

At the bottom, I'm telling Apache to treat wrap.py as a fastcgi-script.