新博客地址:http://gorthon.sinaapp.com/
使用SQLAlchemy+webpy的时候出现了一些问题,记录以备后用。
环境:
>>> web.__version__
'0.36'
>>> sqlalchemy.__version__
'0.7.6'
>>> MySQLdb.__version__
'1.2.3c1'
>>>
1. sqlalchemy与webpy的结合看webpy的cookbook就可以了-- 这里
2. 当启用webpy的session功能后,问题来了,因为webpy提供的是DiskStore、DBStore,他们的使用方法cookbook里面有,猛击这里。
如果不用sqlalchemy而是使用DBStore的话有些注意的地方,连接mysql如下:
# 使用webpy自带数据库api
db = web.database(
dbn='mysql',
db="db_name",
user="root",
pw="123456",
host="127.0.0.1",
port=3306,
)
# webpy session
web.config.session_parameters = web.utils.storage({
'cookie_name': 'session_id',
'cookie_domain': None,
'cookie_path' : None,
'timeout': 86400, #24 * 60 * 60, # 24 hours in seconds
'ignore_expiry': True,
'ignore_change_ip': True,
'secret_key': 'fLjUfxqXtfNoIldA0A0J',
'expired_message': 'Session expired',
'httponly': True,
'secure': False
}) # webpy cookbook和api文档里面都没有提到,可以看webpy的源码来进行设置
调试模式下使用session:
app = web.application(urls, globals())
if web.config.get('_session') is None:
session = web.session.Session(app, web.session.DBStore(db, 'sessions'))
web.config._session = session
else:
session = web.config._session
class Store:
"""Base class for session stores"""
def __contains__(self, key):
raise NotImplementedError
def __getitem__(self, key):
raise NotImplementedError
def __setitem__(self, key, value):
raise NotImplementedError
def cleanup(self, timeout):
"""removes all the expired sessions"""
raise NotImplementedError
下面开始构造:
4. 创建session数据库(models.py):
# coding: utf-8
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, CHAR, Text, TIMESTAMP, func
from sqlalchemy.orm import sessionmaker, scoped_session
mysql_engine = create_engine(
'mysql://%s:%s@%s:%s/app_gorthon?charset=utf8' %
("root", "123456", "127.0.0.1", 3306),
encoding='utf8',
echo=True
)
sql_session = scoped_session(sessionmaker(bind=mysql_engine))
def loadSqla(handler):
try:
return handler()
except web.HTTPError:
sql_session.commit()
raise
except Exception:
sql_session.rollback()
raise
finally:
sql_session.commit()
Base = declarative_base()
class WebpySession(Base):
__tablename__ = 'sessions'
session_id = Column(CHAR(128), nullable=False, primary_key=True)
atime = Column(TIMESTAMP, nullable=False, default=func.current_timestamp())
data = Column(Text, nullable=True)
webpy_table = WebpySession.__table__
metadata = Base.metadata
if __name__ =='__main__':
metadata.create_all(mysql_engine)
先python models.py创建数据库。
5. 接口(utils.py),代码来自group,做了一点修改(第31行加了commit()),其实可以改成用sqlalchemy的session来做,下面这个代码用的是元数据操作的:
#!/usr/bin/python
#-*- coding: utf-8 -*-
import datetime
import web
from models import sql_session
class SQLAStore(web.session.Store):
def __init__(self, table):
self.table = table
def __contains__(self, key):
return bool(sql_session.execute(self.table.select(self.table.c.session_id==key)).fetchone())
def __getitem__(self, key):
s = sql_session.execute(self.table.select(self.table.c.session_id==key)).fetchone()
if s is None:
raise KeyError
else:
sql_session.execute(self.table.update().values(atime=datetime.datetime.now()).where(self.table.c.session_id==key))
return self.decode(s[self.table.c.data])
def __setitem__(self, key, value):
pickled = self.encode(value)
if key in self:
sql_session.execute(self.table.update().values(data=pickled).where(self.table.c.session_id==key))
else:
sql_session.execute(self.table.insert().values(session_id=key, data=pickled))
sql_session.commit()
def __delitem__(self, key):
sql_session.execute(self.table.delete(self.table.c.session_id==key))
def cleanup(self, timeout):
timeout = datetime.timedelta(timeout/(24.0*60*60))
last_allowed_time = datetime.datetime.now() - timeout
sql_session.execute(self.table.delete(self.table.c.atime
6. 主文件(请自行import缺少的模块):
app = web.application(urls, globals())
if web.config.get('_session') is None:
session = web.session.Session(app, SQLAStore(webpy_table))
web.config._session = session
else:
session = web.config._session
app.add_processor(loadSqla)
application = sae.create_wsgi_app(app.wsgifunc())