参考教程:http://www.pythondoc.com/flask-mega-tutorial/database.html#id8
准备:
pip install sqlalchemy-migrate
我们的目录:
config.py
import os
basedir=os.path.abspath(os.path.dirname(__file__))
SQLALCHEMY_DATABASE_URI='sqlite:///'+os.path.join(basedir,'app.db')#数据库文件的路径
SQLALCHEMY_MIGRATE_REPO=os.path.join(basedir,'db_repository')#数据文件夹
os.path.abspath()是获取绝对路径(带文件名的路径),参考文章
SQLALCHEMY_DATABASE_URI 是 Flask-SQLAlchemy 扩展需要的。这是我们数据库文件的路径。
SQLALCHEMY_MIGRATE_REPO 是文件夹,我们将会把 SQLAlchemy-migrate 数据文件存储在这里。db_repositorty
__init__.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app=Flask(__name__)
app.config.from_object('config')
db=SQLAlchemy(app)#创建了db对象,这是我们的数据库对象
from app import models
no module named "flask_ext"
所需要的库已安装的前提下仍然包没有flask.ext 模块:
解决办法:更改引入的方式
from flask_sqlalchemy import SQLAlchemy
models.py
我们要创建两个表相联系
from app import db
class User(db.Model):#继承db.Model类
id=db.Column(db.Integer,primary_key=True)
nickname=db.Column(db.String(64),index=True,unique=True)
email=db.Column(db.String(120),index=True,unique=True)
posts=db.relationship('Post',backref='author',lazy='dynamic')
def __repr__(self):#如何打印这个类的对象
return '<User %r>'%(self.nickname)
class Post(db.Model):
id=db.Column(db.Integer,primary_key=True)
body=db.Column(db.String(140))
timestamp=db.Column(db.DateTime)
#author=db.Column(db.String(140))
user_id=db.Column(db.Integer,db.ForeignKey('user.id'))
def __repr__(self):
return '<Post %r>'%(self.body)
引入数据库对象,我们有了两张表,User和Post,下面介绍一下:
User:
id:整型、主键
nickname、email:字符串,创建索引,非重复值。
posts:关联信息
author:是一个对象,所以后面是author=u来传递参数
Post:
use_id:外键
db.relationship参考:https://blog.csdn.net/bestallen/article/details/52601457
db_create.py
#创建数据库
from migrate.versioning import api
from config import SQLALCHEMY_DATABASE_URI
from config import SQLALCHEMY_MIGRATE_REPO
from app import db
import os.path
db.create_all()#创建数据库
if not os.path.exists(SQLALCHEMY_MIGRATE_REPO):
api.create(SQLALCHEMY_MIGRATE_REPO,'database repository')
api.version_control(SQLALCHEMY_DATABASE_URI,SQLALCHEMY_MIGRATE_REPO)
else:
api.version_control(SQLALCHEMY_DATABASE_URI,SQLALCHEMY_MIGRATE_REPO,api.version_control(SQLALCHEMY_MIGRATE_REPO))
创建数据库,这是利用migrate.versioning的api创建的.py文件,运行文件会自动创建数据库文件夹
在运行上述命令之后你会发现一个新的 app.db 文件。这是一个空的 sqlite 数据库,创建一开始就支持迁移。同样你还将有一个 db_repository 文件夹,里面还有一些文件,这是 SQLAlchemy-migrate 存储它的数据文件的地方。请注意,我们不会再生的存储库,如果它已经存在。这将使我们重新创建数据库,同时保留现有的存储库,如果我们需要。
db_migrate.py
#数据库迁移
import imp
from migrate.versioning import api
from app import db
from config import SQLALCHEMY_DATABASE_URI
from config import SQLALCHEMY_MIGRATE_REPO
v = api.db_version(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO)
migration = SQLALCHEMY_MIGRATE_REPO + ('/versions/%03d_migration.py' % (v+1))#数据库的路径
tmp_module = imp.new_module('old_model')
old_model = api.create_model(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO)
exec(old_model, tmp_module.__dict__)
script = api.make_update_script_for_model(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO, tmp_module.meta, db.metadata)
open(migration, "wt").write(script)
api.upgrade(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO)
v = api.db_version(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO)#获取当前数据库版本
print('New migration saved as ' + migration)
print('Current database version: ' + str(v))
脚本看起来很复杂,其实际上做的并不多。SQLAlchemy-migrate 迁移的方式就是比较数据库(在本例中从 app.db 中获取)与我们模型的结构(从文件 app/models.py 获取)。两者间的不同将会被记录成一个迁移脚本存放在迁移仓库中。迁移脚本知道如何去迁移或撤销它,所以它始终是可能用于升级或降级一个数据库。
然而在使用上面的脚本自动地完成迁移的时候也不是没有问题的,我见过有时候它很难识别新老格式的变化。为了让 SQLAlchemy-migrate 容易地识别出变化,我绝不会重命名存在的字段,我仅限于增加或者删除模型或者字段,或者改变已存在字段的类型。当然我一直会检查生成的迁移脚本,确保它是正确。
毋庸置疑你不应该在没有备份下去尝试迁移数据库。当然也不能在生产环境下直接运行迁移脚本,必须在开发环境下确保迁移运转正常。
db_upgrade.py
from migrate.versioning import api
from config import SQLALCHEMY_DATABASE_URI
from config import SQLALCHEMY_MIGRATE_REPO
api.upgrade(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO)
v = api.db_version(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO)
print('Current database version: ' + str(v))
数据库的升级
db_downgrade.py
#!flask/bin/python
#数据库的版本回退
from migrate.versioning import api
from config import SQLALCHEMY_DATABASE_URI
from config import SQLALCHEMY_MIGRATE_REPO
v = api.db_version(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO)
api.downgrade(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO, v - 1)
v = api.db_version(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO)
print('Current database version: ' + str(v))
数据库版本回退
编程时间
我们花了很多时间定义我们的数据库,但是我们仍没有看到它是如何工作的。因为我们的应用程序中还没有关于数据库的代码,让我们先在 Python 解释器上试用下我们全新的数据库。
让我们先启动 Python。在 Linux 或者 OS X 上:
flask/bin/python
或者在 Windows 上:
flask\Scripts\python
一旦启动 Python,在 Python 提示符中输入如下语句:
>>> from app import db, models
>>>
这将会把我们的数据库和模型载入内存中。
首先创建一个新用户:
>>> u = models.User(nickname='john', email='john@email.com')
>>> db.session.add(u)
>>> db.session.commit()
>>>
在会话的上下文中完成对数据库的更改。多个的更改可以在一个会话中累积,当所有的更改已经提交,你可以发出一个 db.session.commit(),这能原子地写入更改。如果在会话中出现错误的时候, db.session.rollback() 可以是数据库回到会话开始的状态。如果即没有 commit 也没有 rollback 发生,系统默认情况下会回滚会话。会话保证数据库将永远保持一致的状态。
让我们添加另一个用户:
>>> u = models.User(nickname='susan', email='susan@email.com')
>>> db.session.add(u)
>>> db.session.commit()
>>>
现在我们可以查询用户:
>>> users = models.User.query.all()
>>> users
[<User u'john'>, <User u'susan'>]
>>> for u in users:
... print(u.id,u.nickname)
...
1 john
2 susan
>>>
对于查询用户,我们使用 query 成员,这是对所有模型类都是可用的。
这是另外一种查询。如果你知道用户的 id ,我们能够找到这个用户的数据像下面这样:
>>> u = models.User.query.get(1)
>>> u
<User u'john'>
>>>
现在让我们提交一篇 blog:
>>> import datetime
>>> u = models.User.query.get(1)
>>> p = models.Post(body='my first post!', timestamp=datetime.datetime.utcnow(), author=u)
>>> db.session.add(p)
>>> db.session.commit()
这里我们设置我们的 timestamp 为 UTC 时区。所有存储在数据库的时间戳都会是 UTC。我们有来自世界上不同地方的用户因此需要有个统一的时间单位。在后面的教程中会以当地的时间呈现这些时间在用户面前。
你可能注意到了我们并没有设置 user_id 字段。相反我们在 author 字段上存储了一个 User 对象。ORM 层将会知道怎么完成 user_id 字段。
让我们多做一些查询:
# get all posts from a user
>>> u = models.User.query.get(1)
>>> u
<User u'john'>
>>> posts = u.posts.all()
>>> posts
[<Post u'my first post!'>]
# obtain author of each post
>>> for p in posts:
... print(p.id,p.author.nickname,p.body)
...
1 john my first post!
# a user that has no posts
>>> u = models.User.query.get(2)
>>> u
<User u'susan'>
>>> u.posts.all()
[]
# get all users in reverse alphabetical order
>>> models.User.query.order_by('nickname desc').all()
[<User u'susan'>, <User u'john'>]
>>>
Flask-SQLAlchemy 文档可能会提供更多有帮助的信息。
在结束之前,需要清除一下刚才创建的数据,以便在下一章中会有一个干净的数据库:
>>> users = models.User.query.all()
>>> for u in users:
... db.session.delete(u)
...
>>> posts = models.Post.query.all()
>>> for p in posts:
... db.session.delete(p)
...
>>> db.session.commit()
>>>