发布于 2015-11-09 15:33:49 | 400 次阅读 | 评论: 0 | 来源: PHPERZ
SQLAlchemy Python的ORM框架
SQLAlchemy是Python编程语言下的一款开源软件。提供了SQL工具包及对象关系映射(ORM)工具,使用MIT许可证发行。
在学tornado的时候涉及以下数据库操作,现在暂时使用mysql数据库,所以选择了一个比较好用的ORM工具sqlalchemy,顺便记一下使用过程
首先安装mysql
pip安装必要的库:pip install sqlalchemy
下载mysql-python驱动:
http://www.codegood.com/archives/129
如果是32位版本的windows选win32,如果是64的可以选择amd64
首先需要一个数据库配置文件
# -*- coding: utf-8 -*-
DB_HOST = '127.0.0.1'
# DB_HOST = '127.0.0.1'
DB_USER = 'root'
# DB_USER = 'root'
DB_PWD = ''
# DB_PWD = '084358'
DB_NAME = 'my404'
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base() #create Base lei
engine = create_engine('mysql://%s:%s@%s/%s?charset=utf8' %
(DB_USER, DB_PWD, DB_HOST, DB_NAME),
encoding='utf-8', echo=False,
pool_size=100, pool_recycle=10)
这里我写了一个db.py文件,目录在tornado项目根目录下的mod.databases下
接下来是一段类似于orm里实体类部分的代码,我同样放在了mod.databases下,名字为tables.py
from sqlalchemy import Column, String, Integer, VARCHAR,ForeignKey, Float
from sqlalchemy.orm import relationship,backref
from db import engine,Base
class Article(Base):
__tablename__ = 'articles'
user = Column(VARCHAR(20),primary_key = True)
title = Column(VARCHAR(40))
time = Column(VARCHAR(20))
content = Column(VARCHAR(2000))
每个类对应一个表,上方导入必要的库和db里的一些配置信息,注意一定要设置一项为primary_key,不然在查询时会报错Could not assemble any primary key columns for mapped table
这就是大概需要配置的部分,如果需要用新的表就在tables.py里面加入新的类就好了
如下,在自己的main.py里需要对定义的application里面做一下数据库的设置,通过self.db修改属性来设置一些和数据库相关的操作。但是具体其中的属性还不太了解,就先放着了。
class Application(tornado.web.Application):
def __init__(self):
handlers = [
(r"/", IndexHandler),
]
settings = dict(
debug=True,
static_path=os.path.join(os.path.dirname(__file__),"static"),
template_path=os.path.join(os.path.dirname(__file__), "templates")
)
tornado.web.Application.__init__(self, handlers, **settings)
self.db = scoped_session(sessionmaker(bind=engine,
autocommit=False, autoflush=True,
expire_on_commit=False))
if __name__ == '__main__':
tornado.options.parse_command_line()
Application().listen(options.port, address='127.0.0.1')
tornado.ioloop.IOLoop.instance().start()
在具体的handler里使用时如下
from tornado.httpclient import HTTPRequest, AsyncHTTPClient
from mod.databases.tables import Article
import tornado.web
import tornado.gen
import urllib
class DbHandler(tornado.web.RequestHandler):
@property
def db(self):
return self.application.db
def get(self):
data = self.db.query(Article).all()
for item in data:
print item.content
一方面对使用的实体类要进行导入,如
from mod.databases.tables import Article
另一方面db函数上方
@property
标注是不能少的,否则会报错无法查询
具体的查询语句就是
data = self.db.query(Article).all()
这里我从数据库里取出数据后只把每一项的content列输出了,并没有进行其他操作。
其他的使用方法可以参考sqlalchemy的官方文档
http://docs.sqlalchemy.org/en/rel_1_0/orm/tutorial.html
new_user = User(user_email = email,user_name = name,user_psd = psd)
self.db.add(new_user)
self.db.commit()
需要注意的地方是commit函数,如果没有commit,那么self.db里还是保存着之前的信息,这样说似乎不太明白,但是我在使用的过程中发生了一个这样的情景:
我搭建了一个小网站,可以用于注册登录,在我注册时我先检测相关信息是否合法,例如用户名(邮箱)是否已存在:
user = self.db.query(User).filter(User.user_email == self.email).first()
if user!=None:
表示用户名已存在
返回错误信息
else:
用户名不存在,可以注册
new_user = User(user_email = email,user_name = name,user_psd = psd)
self.db.add(new_user)
self.db.commit()
但紧接着,我又做了一件没有什么必要做的事情(请不要吐槽,我只是这么写了一下,其实目的是检测一下这个用户是否在数据库中存在了,然后返回注册成功的信息
user = self.db.query(User).filter(User.user_name == name).first()
if(user.user_email == email):
self.db.commit()
data["status"] = 200
data["data"] = "Register Success"
标记2
self.write(data)
但是这么做令我出现了一个麻烦
在我注册成功后,我从数据库中紧接着删除了这个用户,然后重新注册,这时候他显示这个用户还是存在的…
在我将tornado的服务重启后,用同样的用户名去注册,发现这时候又不显示该用户存在了,于是注册成功
之后我在标记2处加了一句self.db.commit()后这个问题就不再出现了。
于是感觉原因可能是因为self.db其实是sqlalchemy的scoped_session,他相当于未commit时有个缓存,查询结果也会缓存在其中。于是虽然数据库里删除了某用户,但是在删除之前我做了一次对这个用户的查询,导致self.db里缓存了这个用户。所以下次他直接在缓存里找到了这个用户。
重启服务后缓存清掉了,也就恢复正常和数据库保持同步了…