I'm trying to update the QuickWiki tutorial code by following the
recommendation from Mike Bayer to use sessions instead of
mods.threadlocal (and so that I can use it in my own app).
I modified the BaseController as follows:
---
from sqlalchemy import *
class BaseController(WSGIController):
def __call__(self, environ, start_response):
conn = model.meta.connect(
request.environ['paste.config']['app_conf']['dsn']
)
sess = create_session(bind_to=conn)
sess.clear()
response = WSGIController.__call__(self, environ,
start_response)
sess.flush()
return response
---
This appears to work and I'm able to edit a wiki page and it appears to
save it, but it doesn't really. The problem is that in page.py, the
__before__() and delete() methods use objecstore. SA has an
object_session() function that can be used to obtain the session for an
object, but I'm not sure what object to use. I'm hoping someone could
offer some guidance (and comment on the code above, too).
On a related note, is there some reason for the pylons.database module
providing "convenient access" only to a SQLObject-managed database,
other than SO being there first?
Joe
The approach I have taken when going trought tutorial recently is to
define database connection in my model pages.py like this
===================================================
from sqlalchemy import *
import re
from docutils.core import publish_parts
import quickwiki.lib.helpers as h
wikiwords = re.compile(r"\b([A-Z]\w+[A-Z]+\w+)")
meta = BoundMetaData('sqlite:///qwicki.db')
page = Table('page', meta,
Column('title', String(40), primary_key=True),
Column('content', String(), default='')
)
meta.create_all()
class Page(object):
content = None
def __str__(self):
return self.title
def get_wiki_content(self):
content = publish_parts(self.content,
writer_name="html")["html_body"]
titles = wikiwords.findall(content)
if titles:
for title in titles:
content = content.replace(
title,
h.link_to(
title,
h.url_for(
controller='page',
action='index',
title=title
),
),
)
return content
mapper(Page, page)
--------------------------------------------------------------------------------
and the controller pages.py looks like this
==============================================
from qwiki.lib.base import *
from sqlalchemy import create_session
class PageController(BaseController):
def __before__(self):
db = self.db = create_session()
self.qry = db.query(model.Page)
def __after__(self):
self.db.close()
def index(self, title):
pg = self.qry.get_by(title=title)
if pg:
c.content = pg.get_wiki_content()
return render_response('/page.myt')
elif model.wikiwords.match(title):
return render_response('/new_page.myt')
abort(404)
def edit(self, title):
pg = self.qry.get_by(title=title)
if pg:
c.content = pg.content
return render_response('/edit.myt')
def save(self, title):
pg = self.qry.get_by(title=title)
if not pg:
pg = model.Page()
pg.title = title
pg.content = request.params['content']
c.title = pg.title
c.content = pg.get_wiki_content()
c.message = 'Content Saved'
self.db.save_or_update(pg)
self.db.flush()
return render_response('/page.myt')
def list(self):
c.titles = (pg.title for pg in self.qry.select())
return render_response('/titles.myt')
def delete(self):
title = request.params['id'][:5]
pg = self.qry.get_by(title)
self.db.delete(pg)
self.db.flush()
c.titles = (pg.title for pg in self.qry.select())
return render_response('/list.myt', fragment=True)
=================================================
I did not touch BaseController prefering to keep database session
locally where I can see it :-)
It did seem to work OK. At least for the tutorial purposes.
The only bad part is that the path to the database is hardcoded in
models/page.py.
I would prefer to get it from configuration file but I could not figure
out
where all the settings live. Should be somwhere in paste I think.
Waldemar
Are you explicitly saving [1] newly created objects (such as your wiki
page) to the SQLAlchemy session where needed? The threadlocal plugin
[2] will automagically do this for you, so if you remove it, you have
to do it manually or flush'ing a session wil do nothing.
> SA has an object_session() function that can be used to obtain the
> session for an object, but I'm not sure what object to use.
You might want to read SQLAlchemy's documentation on sessions [3]. This
should get you started.
Here is a small, exemplary snippet of code to show you how to create
and save objects without threadlocal magic in SQLAlchemy:
---------------------- snipp -------------------
page = WikiPage(name='PylonsForRunaways')
session.save(page) # save page to session
session.flush() # write session changes to the database
---------------------- snipp -------------------
Hope that helps,
Michael
[1] http://www.sqlalchemy.org/docs/unitofwork.myt#unitofwork_api_save
[2] http://www.sqlalchemy.org/docs/plugins.myt#plugins_threadlocal
[3] http://www.sqlalchemy.org/docs/unitofwork.myt
Here is a small, exemplary snippet of code to show you how to create
and save objects without threadlocal magic in SQLAlchemy:
---------------------- snipp -------------------
page = WikiPage(name='PylonsForRunaways')
session.save(page) # save page to session
session.flush () # write session changes to the database
---------------------- snipp -------------------