SQLAlchemy Session Store webpy DBStore

新博客地址: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

3. 从上面可以看到session是web.session.Session这个类的实例,而构造时的第二个参数要web.session.DBStore(或者DiskStore)这个类的实例,查看webpy的源码(E:\Python26\Lib\site-packages\web\session.py),可以看到这两个类都是继承自Store类,所以可以使用类似的方法自己构造一个可以用于sqlalchemy的类。

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个方法。

下面开始构造:

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())

你可能感兴趣的:(web,Python)