Saturday, August 22, 2009

zodb cherrypy and lxml - simple CRUD and OO database with python.

Below I have combined three python libraries to let you do a free-form CRUD document oriented database with a webserver. Where you can just pass it most any text based html form and it will be able CReate, Update, and Delete pages.

In the post I made about cherrypy + zodb and python I combined the best python object database 'zodb' with arguably the best python webserver 'cherrypy', to create a very simple key/value datastore. This time I've combined it with lxml, to give you a very simple free form CRUD document web application.

lxml is an xml library with a number of interesting features. Including a form filling library.

Below is a script which uses 'lxml' to fill in a custom form - specified in normal html - with data you have. lxml has many html/xml related stuff in it... including a css library, and is very fast. Well worth checking out if you need to do anything webby.


You can define your html form, and it'll save whatever fields you have into the database. Then you can edit what you saved later. I guess that's the nice thing here... just define your form, and it saves data as free form objects.

All this in very few lines... these are some nice python libraries.



Note: unfortunately blogger stuffs up the code formatting... so you can download the code here: http://rene.f0o.com/~rene/stuff/zodb_cherrypy_lxml.py


import cherrypy
import lxml.html
from ZODB import FileStorage, DB

import cgi, os, transaction


page_form = """

<html><body>
<form action='savepage' method='post'>
title:<input type='text' name='title'>
<input type='hidden' name='id'>
<br>textarea:
<textarea name='content'></textarea>
<input type='submit' name='submit'></form>
</body></html>

"""

class MyZODB(object):
def __init__(self, path):
self.storage = FileStorage.FileStorage(path)
self.db = DB(self.storage)
self.connection = self.db.open()
self.dbroot = self.connection.root()

def close(self):
self.connection.close()
self.db.close()
self.storage.close()



def ehtml(s):
return cgi.escape(s)


class HelloWorld(object):

def __init__(self):

self.opendb()

def opendb(self):
self.db = MyZODB('./Data.fs')


def index(self):
r=''
# list everything passed, and allow adding more.
for k in sorted(self.get_pages()):
ek = ehtml(k)
r += "<a href="showpage?id=%s">%s</a>" % (ek,ek)

ek = ehtml( str( int(k)+1 ) )
r += "<a href="showpage?id=%s">create new page</a>" % (ek)


return r


def get_pages(self):
dbroot = self.db.dbroot
if not dbroot.has_key('pages'):
dbroot['pages'] = {}

from BTrees.OOBTree import OOBTree
dbroot['pages'] = OOBTree()
return dbroot['pages']

def savepage(self, **kwargs):
dbroot = self.db.dbroot
self.get_pages()[kwargs['id']] = kwargs

self.commit()
return "page saved <a href="index">index</a>"

def commit(self):
self.get_pages()._p_changed = True
transaction.commit()


def showpage(self, id):

dbroot = self.db.dbroot

p = self.get_pages().get(id, None)
if p is None:
p = dict(id=id, title='a', content='w', submit='submit')

form_page = lxml.html.fromstring(page_form)
form = form_page.forms[0]
form.fields = p
return lxml.html.tostring(form)



def put(self, **kwargs):
# store all the args passed into the zodb.
dbroot = self.db.dbroot
dbroot.update(kwargs)
transaction.commit()


put.exposed = True
index.exposed = True
showpage.exposed = True
savepage.exposed = True



if __name__ == "__main__":

cherrypy.config.update({"engine.autoreload_on" : False})

a = HelloWorld()
cherrypy.quickstart(a)
a.db.close()

No comments: