SQLAlchemy 是下一代的 Python Object Relational 映射器,有了这个东西,我们就可以更少的接触数据库的底层了,我现在基本上都在使用Flask,而Flask 里面也有SQLAlchemy的封装:flaskext.sqlalchemy ,使得我们在开发Flask应用的时候更方便的操作数据库,这里就来记录一个最通用的程序数据库设计中使用Flask SQLAlchemy的示例。

整个程序代码如下(感觉我这里看着不方便,就把下面的代码保存到任何一个现代的IDE或者程序编辑器里面都应该是可以看得很清楚的,我这里是因为Textile会把空行当作代码的结束,所以只能全部写到一起了):

#!/usr/bin/env python
# encoding: utf-8
"""
models.py
Created by Pan Tao on 2011-09-02.
Copyright (c) 2011 CosTony.Com. All rights reserved.
"""
from flask import Flask
from flaskext.sqlalchemy import SQLAlchemy
from datetime import datetime
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/models.db'
app.config['SQLALCHEMY_BINDS'] = {
'user' : 'sqlite:////tmp/user_db.db',
'appmeta' : 'sqlite:////tmp/appmeta.db'
}
db = SQLAlchemy(app)
tags = db.Table('tags',
db.Column('tag_id', db.Integer, db.ForeignKey('tag.id')),
db.Column('post_id', db.Integer, db.ForeignKey('post.id'))
)
class Role(db.Model):
id = db.Column(db.Integer, primary_key = True)
name = db.Column(db.String(20), unique = True)
def __init__(self, name):
self.name = name
def __repr__(self):
return '<Role %r>' % self.name
class User(db.Model):
__bind_key__ = 'user'
id = db.Column(db.Integer, primary_key = True)
username = db.Column(db.String(80), unique = True)
email = db.Column(db.String(120), unique = True)
role_id = db.Column(db.Integer, db.ForeignKey('role.id'))
role = db.relationship('Role',
backref = db.backref('users', lazy='dynamic'))
def __init__(self, username, email, role):
self.username = username
self.email = email
self.role = role
def __repr__(self):
return '<User %r>' % self.username
class Post(db.Model):
id = db.Column(db.Integer, primary_key = True)
title = db.Column(db.String(80))
body = db.Column(db.Text)
pub_date = db.Column(db.DateTime)
author_id = db.Column(db.Integer, db.ForeignKey('user.id'),info={'bind_key': 'user'})
author = db.relationship('User',
backref=db.backref('posts', lazy='dynamic'))
category_id = db.Column(db.Integer, db.ForeignKey('category.id'))
category = db.relationship('Category',
backref=db.backref('posts', lazy='dynamic'))
tags = db.relationship('Tag', secondary=tags,
backref = db.backref('posts', lazy='dynamic'))
def __init__(self, title, body, category, tags, author, pub_date = None):
self.title = title
self.body = body
if pub_date is None:
pub_date = datetime.utcnow()
self.pub_date = pub_date
self.category = category
self.tags = tags
self.author = author
def __repr__(self):
return '<Post %r>' % self.title
class Category(db.Model):
id = db.Column(db.Integer, primary_key = True)
name = db.Column(db.String(50))
def __init__(self, name):
self.name = name
def __repr__(self):
return '<Category %r>' % self.name
class Tag(db.Model):
id = db.Column(db.Integer, primary_key = True)
name = db.Column(db.String(20), unique = True)
def __init__(self,name):
self.name = name
def __repr__(self):
return '<Tag %r>' % self.name
def init_db():
db.drop_all()
db.create_all()

最开始,我们把需要使用的一些模块都导入进来,在这里,我导入了Flask, flaskext.sqlalchemy 中的 SQLAlchemy(注意这个和原生的 SQLAlchemy有一点点不一样的),然后 datetime 中导入 datetime(这个其实不导入也没有关系,只需要把 Post 类中的创建时间的属性删除掉就行了。

然后我创建了一个Flask实例(这个在Flask SQLAlchemy中是必须的,需要我们在创建 FlaskSQLAlchemy 的时候不指定 Flask app,那我们也必须在之后使用 Flask SQLAlchemy 实例之前,初始化它的Flask app。

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/models.db'
app.config['SQLALCHEMY_BINDS'] = {
'user' : 'sqlite:////tmp/user_db.db',
'appmeta' : 'sqlite:////tmp/appmeta.db'
}

上面这一段代码中,我对 Flask app 进行的配置,配置项为下面两个:

  1. SQLALCHEMY_DATABASE_URI : 这个是标准的 SQLAlchemy 数据库地址字符串,我在这里使用的是 SQLite 数据来测试(对于这个Python内置的数据库用起来还真方便)
  2. SQLALCHEMY_BINDS :在这个设置里面,我设置了两个属性,一个是用来保存程序中 user 数据的数据库,我把 user 表单独于其它表放在另外一个数据库中了,这个其实在很小的程序里没有啥用,我这里只是为了尽可能把Flask SQLAlchemy的入门教程讲明白哈。appmeta 被保存在另一个数据库中,另外,当我们初始化数据库之后,还会再创建一个 models 数据库,这个是把其它未指定的列都放在这个数据库里面的。

接着我就来始定义我这个程序里面需要的几个类了:

  • Role :用户组
  • User :用户类
  • Post :文章类
  • Category :文件分类的类
  • Tag :标签

上面这些类的关系如下面这样的:

  • Role -> User :一对多
  • User -> Post :一对多
  • Category -> Post : 一对多
  • Tag -> Post : 多对多

在一对多的实例中,比如Role -> User中,User中有一个 role_id 属性来保存这个用户所属的用户组的ID,然后有一个关系申明,这样可以让Role 对象 role 通过 role.users访问到这个用户组下面所有的用户数据。

而对于多对多的情况,如 Tag -> Post,我在最开始创建了一个表:tags,这个表用来保存Tag 与 Post 之间的关联关系,然后需要在Post类中申明一个 secondary 属性,表示关系是保存在那个表里面的。

最后就是在User类里面有一个不一样的地方,就是有一个 __bind_key__ = 'user' 这个属性,这里其实就是申明这个类的数据要使用 key 为 ”user“ 的数据库,这样的话,我们就需要在与 User 这个类有关联的类中,显示的申明 User 类的’bind_key’为’user‘。

最后面的那一个 init_db() 函数是用来初始化数据库的,如果未修改我代码里面的配置,那么在系统的 /tmp 目录下将会生成下面这些文件:

/tmp
/appmeta.db
/user_db.db
/models.db

大体上就这样的吧,反正自己以后再来看这个我还能看懂,所以就这样了吧^

标签: none

评论已关闭