building web pages with python deleting notes
Deleting Notes
Note Deletion
All good things must come to an end. Sometimes you'll want the ability to delete a Note and that's what we're going to add in this Part.
The procedure for deleting data is pretty simple: We give the delete function a note_id to delete. First, the Note is removed from the note table. Next, all revisions with that note_id as its Foreign Key are removed as well.
The Delete Template
The delete template will be named deleteNote.html. It'll contain a simple form that has a hidden field for the note_id and a Submit button to confirm the deletion.
{% extends "base" %}
{% marker "title" set "Delete a Note" %}
{% block "content" %}
<h2>Are you sure?</h2>
<p>Are you sure you want to delete note "{{ n.note_title }}"?</p>
<p>Doing so will remove all revisions as well.</p>
<form name="delete" method="post" action=".">
<input type="hidden" name="note_id" value="{{ n.note_id }}">
<input type="submit" name="Submit" value="Delete"/>
</form>
{% endblock %}
Since this is such a simple form with only one form element, FormEncode won't be used -- that'd just be too much overhead.
The Delete Function
In order to remove the data from the database, a deleteNote() function needs to be defined in our model.
def deleteNote(note_id):
try:
c = db.connect()
transaction = c.begin()
c.execute(note.delete(note.c.note_id==note_id))
c.execute(revision.delete(revision.c.note_note_id==note_id))
transaction.commit()
c.close()
except:
transaction.rollback()
c.close()
raise
A very short and self-explanatory function. Just like what was described at the beginning of this Part, a note_id is specified, removed, and then all the subsequent Revisions are also removed. The function uses a transaction for easy rollbacks and is wrapped in a try / except block.
The Delete Controller
Deletion is a new action to this application, so we'll be creating a new controller in the controllers directory called delete.py.
from base import *
class note(baseWebpy):
def GET(self, note_id):
if note_id and noteExists(note_id):
return sendData('deleteNote', {
'n': getNotes(note_id)[0]
})
else:
raise PageNotFound
def POST(self, note_id=""):
i = formData(self.request.form)
if i['note_id'] and noteExists(i['note_id']):
try:
deleteNote(i['note_id'])
return redirect('/')
except Exception, e:
return HttpResponse('uh oh!')
else:
raise PageNotFound
The GET method takes a note_id as a parameter and checks to see if it exists. If so, it renders the delete.html template with the value of the note_id in the hidden field.
The POST method processes the form data and passes it to the deleteNote() model function. If everything was deleted OK, the user is sent back to the index page.
Save this and add the entry to __init__.py.
Adding the Delete URL
The final step for the Delete support is to add its entry to the urls map:
(r'^delete/note/(\d*)/$', controllers.delete.note),
Deleting Notes
Everything should now be in place for the Delete support. Try deleting a note from the Colubrid server.
Checkpoint
controllers/__init__.py
import view
import addEdit
import compare
import delete
controllers/delete.py
from base import *
class note(baseWebpy):
def GET(self, note_id):
if note_id and noteExists(note_id):
return sendData('deleteNote', {
'n': getNotes(note_id)[0]
})
else:
raise PageNotFound
def POST(self, note_id=""):
i = formData(self.request.form)
if i['note_id'] and noteExists(i['note_id']):
try:
deleteNote(i['note_id'])
return redirect('/')
except Exception, e:
return HttpResponse('uh oh!')
else:
raise PageNotFound
tpl/deleteNote.html
{% extends "base" %}
{% marker "title" set "Delete a Note" %}
{% block "content" %}
<h2>Are you sure?</h2>
<p>Are you sure you want to delete note "{{ n.note_title }}"?</p>
<p>Doing so will remove all revisions as well.</p>
<form name="delete" method="post" action=".">
<input type="hidden" name="note_id" value="{{ n.note_id }}">
<input type="submit" name="Submit" value="Delete"/>
</form>
{% endblock %}
app.py
from colubrid import WebpyApplication, Request, execute, HttpResponse
from colubrid.server import StaticExports
import controllers
class Notebook(WebpyApplication):
urls = [
(r'^$', controllers.view.index),
(r'^view/note/(\d*)/$', controllers.view.note),
(r'^view/note/(\d*)/(\d*)/$', controllers.view.note),
(r'^add/note/$', controllers.addEdit.note),
(r'^edit/note/(\d*)/$', controllers.addEdit.note),
(r'^compare/(\d*)/(\d*)/(\d*)/$', controllers.compare.note),
(r'^view/txt/(\d*)/$', controllers.view.txt),
(r'^view/txt/(\d*)/(\d*)/$', controllers.view.txt),
(r'^delete/note/(\d*)/$', controllers.delete.note),
]
slash_append = True
app = Notebook
app = StaticExports(app, {
'/static': './static'
})
if __name__ == '__main__':
execute(reload=True, debug=False)
models.py
from sqlalchemy import *
db = create_engine('sqlite:///sql/notebook.db')
metadata = BoundMetaData(db)
category = Table('category', metadata,
Column('category_id', Integer, primary_key=True),
Column('category_category', String(255)),
)
note = Table('note', metadata,
Column('note_id', Integer, primary_key=True),
Column('note_title', String(255)),
Column('category_category_id', Integer, ForeignKey('category.category_id')),
)
revision = Table('revision', metadata,
Column('revision_id', Integer, primary_key=True),
Column('note_note_id', Integer, ForeignKey('note.note_id')),
Column('revision_body', String),
Column('revision_time', DateTime, default=func.current_timestamp()),
)
session = create_session()
def getCategories(category_id=""):
r = select([category])
return r.execute().fetchall()
def getNotes(note_id="", revision_id=""):
r = select([note,category],
and_(note.c.category_category_id==category.c.category_id))
if note_id:
r = select([note,category,revision],
and_(note.c.category_category_id==category.c.category_id,
note.c.note_id==revision.c.note_note_id,
note.c.note_id==note_id),
order_by=[desc(revision.c.revision_time)], limit=1,)
if revision_id:
r.append_whereclause(revision.c.revision_id==revision_id)
return r.execute().fetchall()
def addEditNote(formData):
try:
c = db.connect()
transaction = c.begin()
if formData.has_key('note_id'):
formData['note_note_id'] = formData['note_id']
c.execute(note.update(note.c.note_id==formData['note_id']), formData)
else:
c.execute(note.insert(), formData)
newNote = c.execute(note.select(order_by=[desc(note.c.note_id)], limit=1)).fetchone()
formData['note_note_id'] = newNote['note_id']
c.execute(revision.insert(), formData)
session.flush()
transaction.commit()
c.close()
return formData['note_note_id']
except:
transaction.rollback()
c.close()
raise
def noteExists(note_id):
n = note.select(note.c.note_id==note_id).execute().fetchall()
if n:
return True
else:
return False
def revisionExists(revision_id):
r = revision.select(revision.c.revision_id==revision_id).execute().fetchall()
if r:
return True
else:
return False
def categoryExists(category_id):
c = category.select(category.c.category_id==category_id).execute().fetchall()
if c:
return True
else:
return False
def getRevision(note_id="", revision_id=""):
if note_id:
return select([revision],
revision.c.note_note_id==note_id,
order_by=[desc(revision.c.revision_time)]).execute().fetchall()
if revision_id:
return select([revision], revision.c.revision_id==revision_id).execute().fetchone()
def deleteNote(note_id):
try:
c = db.connect()
transaction = c.begin()
c.execute(note.delete(note.c.note_id==note_id))
c.execute(revision.delete(revision.c.note_note_id==note_id))
transaction.commit()
c.close()
except:
transaction.rollback()
c.close()
raise
