初识flask——数据库(2015.6.13)

这章数据库的内容比较多(一个一个代码敲下来的啊),主要涉及数据库的配置,博客的数据库结构设计以及数据库的操作。
和django不一样的地方是flask的数据库管理使用的是Flask-SQLAlchemy扩展,而django使用的是内置的数据库系统,更新到1.7之后也自带了migration系统还蛮方便的。

一、数据库的配置

包括配置,建立数据库,迁移,升级和降级三个部分。

1.配置(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')

小型的应用我们使用sqlite数据库。SQLALCHEMY_DATABASE_URI 是 Flask-SQLAlchemy 扩展需要的。这是我们数据库文件的路径。 SQLALCHEMY_MIGRATE_REPO 是文件夹,我们将会把 SQLAlchemy-migrate 数据文件存储在这里。

2.初始化数据库(app/__init__.py中添加)

from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.config.from_object('config')
db = SQLAlchemy(app)

from app import views, models

创建了一个 db 对象,这是我们的数据库,接着导入一个新的模块,叫做 models。我们在models中编写代码来描述博客系统中的对象在数据库中的存储形式。这些内容在后面再写,接下来是数据库的创建,管理和维护。
在models编写完成并且格式无误之后,便可以应用models来创建数据库了,SQLAlchemy-migrate 包自带命令行和 APIs,这些 APIs 以一种将来允许容易升级的方式来创建数据库。然而在命令行中输入代码不太方便,在这里我们编写几个脚本来进行相关的操作。

3.创建数据库(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(SQLALCHEMY_MIGRATE_REPO))

代码中我们导入了SQLAlchemy提供的api,初始化时创建的db对象,以及数据库和迁移文件的存储路径。
后面一堆的意思是我想是先创建一个数据库,然后如果不存在数据库的存储文件夹,就创建一个,并且将它和数据库绑定起来,如果有一个就直接绑定(大约是这个意思吧(:з」∠)
注意:存储库是不会再生的,如果它已经存在。这将使我们重新创建数据库,同时保留现有的存储库,如果我们需要。

4.第一次迁移(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
migration = SQLALCHEMY_MIGRATE_REPO + '/versions/%03d_migration.py' % (api.db_version(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO) + 1)

tmp_module = imp.new_module('old_model')
old_model = api.create_model(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO)
exec old_model in 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)
print 'New migration saved as ' + migration
print 'Current database version: ' + str(api.db_version(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO))

在这段代码中,导入了一些配置文件,定义了迁移文件的存储位置,migration,中间那段代码应该是把新旧数据模型作对比的然而并不太懂。两者间的不同将会被记录成一个迁移脚本存放在迁移仓库中。迁移脚本知道如何去迁移或撤销它,所以它始终是可能用于升级或降级一个数据库。

5.数据库升级和回退(db_upgrade.py,db_downgrade.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)
print 'Current database version: ' + str(api.db_version(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO))

可以看出api直接提供了一个upgrade方法来完成这项操作。
回退同理:

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)
print 'Current database version: ' + str(api.db_version(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO))

这个脚本运行一次将会使数据库回退一个版本。

关于数据库的操作主要就是这些,接下来我们将数据库和我们有关于博客的数据模型结合起来,没错 ,就是前面提到的models.。

二、数据模型设计及实例操作

1.数据模型定义(models.py)

from app import db

ROLE_USER = 0
ROLE_ADMIN = 1

class User(db.Model):
    id = db.Column(db.Integer, primary_key = True)
    nickname = db.Column(db.String(64), unique = True)
    email = db.Column(db.String(120), unique = True)
    role = db.Column(db.SmallInteger, default = ROLE_USER)
    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)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'))

    def __repr__(self):
        return '<Post %r>' % (self.body)

在这里我们定义了UserPost两个类,代表用户和博文两个对象。
其中用户对象有id,nickname,email,role几个基本字段,而posts是和Post对象有关联的字段,它是被构建成一个db.relationship字段。这并不是一个实际的数据库字段,对于一个一对多(一个用户会有多篇博文)的关系,db.relationship字段通常是定义在“一”这一边。在这种关系下,我们得到一个 user.posts 成员。
而在后面的Post类中,Post对象有id,body,timestamp,user_id几个属性,其中user_id是一个外键,它链接到User的id字段,用来表示Post的作者。和User中的posts是相对应的。

2.数据库操作

我们已经按照数据模型的内容把数据库创建完成了,但是这个数据库现在还是空的没有任何内容,下面我们来操作一些实例。
在数据库文件的同级目录下打开python console,再导入数据库和我们在数据模型中定义好的模块。

>>> from app import db
>>> from app.models import User, Post, ROLE_USER, ROLE_ADMIN
①创建一个新用户
>>> u1 = User(nickname='john', email='john@email.com', role=ROLE_USER)
>>> db.session.add(u1)
>>> db.session.commit()

第一句实例化一个用户对象,后面两句表示在会话中添加这个用户对象和提交(感觉和git有点像)。
在会话的上下文中完成对数据库的更改。多个的更改可以在一个会话中累积,当所有的更改已经提交,你可以发出一个 db.session.commit(),这能原子地写入更改。如果在会话中出现错误的时候, db.session.rollback() 可以是数据库回到会话开始的状态。如果即没有 commit 也没有 rollback 发生,系统默认情况下会回滚会话。会话保证数据库将永远保持一致的状态。

②查询
>>> users = User.query.all()
>>> print users
 [<User u'john'>, <User u'susan'>]

>>> for u in users:
    ...     print u.id,u.nickname
    ...
    1 john
    2 susan

对于查询用户,我们使用 query 成员,这是对所有模型类都是可用的。
根据字段查询可以像这样:

>>> u = User.query.get(1)
>>> print u
 <User u'john'>
③提交一篇blog
>>> import datetime
>>> u = User.query.get(1)
>>> p = Post(body='my first post!', timestamp=datetime.datetime.utcnow(), author=u)
>>> db.session.add(p)
>>> db.session.commit()

你可能注意到了我们并没有设置 user_id 字段。相反我们在 author 字段上存储了一个 User 对象。ORM 层将会知道怎么完成 user_id 字段。

④删除数据
>>> users = User.query.all()
>>> for u in users:
...     db.session.delete(u)
...
>>> posts = Post.query.all()
>>> for p in posts:
...     db.session.delete(p)
...
>>> db.session.commit()

这里写图片描述
这里写图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值