Karrigell/Managing The Database

Database engine

edit

Karrigell can use any database engine (MySQL, SQLite, etc) using the appropriate module. For this example we will use a very simple module that stores the data we need : for each CD in the collection, the artist name and the title of the album

Copy this in a module called simpledb.py :

def read(filename):
    records = []
    try:
        for line in open(filename):
            records.append(line.strip().split("#"))
    except IOError:
        pass
    return records

def save(records,filename):
    out = open(filename,'w')
    for items in records:
        out.write('#'.join(items)+'\n')
    out.close()

When you import the module in a script you simply use its functions read() and save(). The information is stored in a list of tuples

For our CD collection application, the information will consist in only 2 values : the artist name and the CD title. If we call the database file mycds.db the code to print all the CDs in an HTML table will simply be :

simpledb = Import('simpledb')
cds = simpledb.read('mycds.db')
for (artist,title) in cds:
    print artist,title

Notice the way you import the module simpledb.py : you can't use the usual import statement, because in a shared environment like a web server, there are issues with the resolution of module names to files in the file system. Karrigell uses a built-in function Import(module_url) for user-defined modules ; for the modules in the standard Python distribution, you can safely use import

Home page with the CD list

edit

We can now modify the index() function to print the list of CDs:

simpledb = Import('simpledb')

def index():
    print "<h1>My record collection</h1>"
    
    # login / logout
    logged = hasattr(Session(),"user") and Session().user is not None
    if logged:
        print 'Logged in as %s<br>' %Session().user
        print '<a href="logout">Logout</a><p>'
    else:
        print '<a href="login">Login</a><p>'

    # print existing records
    cds = simpledb.read('mycds.db')
    if cds:
        print '<table border="1">'
        print '<tr><th>Artist</th><th>Title</th></tr>'
        for (artist,title) in cds:
            print '<tr><td>%s</td><td>%s</td></tr>' %(artist, title)
        print '</table><p>'
    else:
        print "No CD in the collection<p>"

    # prompt logged in users to enter a new record
    if logged:
        print '<a href="new_cd">Enter new CD</a><p>'

    # page counter
    Include('../counter.py',counter_file='counter.txt')

Notice that simpledb is imported at the module level, not inside the function index() : the names defined at module level are available in the functions, exactly like in ordinary Python scripts

Adding new CDs

edit

For logged-in users there is a link to enter new CDs in the database. The href attribute of this link is new_cd, so we must write a function new_cd()

This function will print a form to enter the CD artist and title, and submit the data to another function which will actually write the information in the database, then return to the home page

At this stage you shouldn't have problems to understand the code below :

def new_cd():
    print '<h1>New CD</h1>'
    print '<form action="insert_new_cd" method="post">'
    print 'Artist <input name="artist"><br>'
    print 'Title <input name="title"><br>'
    print '<input type="submit" value="Ok">'
    print '</form>'

def insert_new_cd(artist,title):
    cds = simpledb.read('mycds.db')
    cds.append((artist,title))
    simpledb.save(cds,'mycds.db')
    raise HTTP_REDIRECTION,"index"

Add these functions to index.ks and enter a couple of CDs in the database. Each time you are back to the home page you should see the collection growing

Editing records

edit

Logged-in users should be able to edit the information about a CD : on the list they should see a link "Edit" sending them to a page where the information will be available for editing

This requires that the information about the CD is carried from the home page to the edition page. For this we could append the information about the CD (artist + title) to the link, for instance : href = edit?artist=Beatles&title=Revolver ; but database engines usually provide record identifiers, that is, integers which identify the record

In our simple database we can use the index of the item in the list as identifier, so that we can rewrite the code to print the CD collection this way :

   # print existing records
   simple db = Import('simpledb')
   cds = simpledb.read('mycds.db')
   if cds:
       print '<table border="1">'
       print '<tr><th>Artist</th><th>Title</th></tr>'
       for num,(artist,title) in enumerate(cds):
           print '<tr><td>%s</td><td>%s</td>' %(artist, title)
           if logged:
               print '<td><a href="edit?num=%s">Edit</a></td>' %num
           print '</tr>'
       print '</table><p>'
   else:
       print "No CD in the collection<p>"

The function edit() will receive one argument called num. All arguments passed to functions in Karrigell Services are bytestrings, so before using this argument num as the index in a list don't forget to convert it to an integer

def edit(num):
    cds = simpledb.read('mycds.db')
    artist,title = cds[int(num)]
    print '<h1>New CD</h1>'
    print '<form action="update_cd" method="post">'
    print '<input name="num" type="hidden" value="%s">' %num
    print 'Artist <input name="artist" value="%s"><br>' %artist
    print 'Title <input name="title" value="%s"><br>' %title
    print '<input type="submit" value="Ok">'
    print '</form>'

def update_cd(num,artist,title):
    cds = simpledb.read('mycds.db')
    cds[int(num)] = (artist,title)
    simpledb.save(cds,'mycds.db')
    raise HTTP_REDIRECTION,"index"

Removing records

edit

The final step is to enable deletion of CDs from the base : once again, edit the function index() like this

   # print existing records
   simpledb = Import('simpledb')
   cds = simpledb.read('mycds.db')
   if cds:
       print '<table border="1">'
       print '<tr><th>Artist</th><th>Title</th>'
       if logged:
           print '<th> </th>'*2
       print '</tr>'
       for num,(artist,title) in enumerate(cds):
           print '<tr><td>%s</td><td>%s</td>' %(artist, title)
           if logged:
               print '<td><a href="edit?num=%s">Edit</a></td>' %num
               print '<td><a href="remove?num=%s">Remove</a></td>' %num
           print '</tr>'
       print '</table><p>'
   else:
       print "No CD in the collection<p>"

and add a new function, remove():

def remove(num):
    cds = simpledb.read('mycds.db')
    del cds[int(num)]
    simpledb.save(cds,'mycds.db')
    raise HTTP_REDIRECTION,"index"

Summary

edit

We now have a complete application to manage our CD collection. The structure of the application in the script index.ks is as clear as in any Python module :

simpledb = Import('simpledb')

def index():
    ...
    # login / logout
    ...
    # print existing records
    ...
    # prompt logged in users to enter a new record
    ...
    # page counter
    ...
def login():
    ...
def check_login(login,passwd):
    ...
def logout():
    ...
def new_cd():
    ...
def insert_new_cd(artist,title):
    ...
def edit(num):
    ...
def update_cd(num,artist,title):
    ...
def remove(num):
    ...

Each function matches a page of the application. For the pages that receive user input, the fields are the arguments to the function (always as strings)

Throughout this short presentation you see that all you need to know is Python and HTML. The package doesn't require any configuration, and for programmers Karrigell only provides a small set of additional built-in names