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.
