初识flask——数据库(2015.6.13)

来源:互联网 发布:百度推广软件 编辑:程序博客网 时间:2024/06/05 03:17

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

一、数据库的配置

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

1.配置(config.py)

import osbasedir = 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 Flaskfrom flask.ext.sqlalchemy import SQLAlchemyapp = 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 apifrom config import SQLALCHEMY_DATABASE_URIfrom config import SQLALCHEMY_MIGRATE_REPOfrom app import dbimport os.pathdb.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 impfrom migrate.versioning import apifrom app import dbfrom config import SQLALCHEMY_DATABASE_URIfrom config import SQLALCHEMY_MIGRATE_REPOmigration = 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 ' + migrationprint '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 apifrom config import SQLALCHEMY_DATABASE_URIfrom config import SQLALCHEMY_MIGRATE_REPOapi.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 apifrom config import SQLALCHEMY_DATABASE_URIfrom config import SQLALCHEMY_MIGRATE_REPOv = 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 dbROLE_USER = 0ROLE_ADMIN = 1class 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
原创粉丝点击