Flask 入门系列教程(五)

简介: Flask 入门系列教程(五)

既然是应用程序,那么数据库就是必不可少的一部分。数据库按照一定规则保存程序数据,程序再发起查询取回所需的数据。Web 程序最常用基于关系模型的数据库,这种数据库也称为 SQL 数据库,因为它们使用结构化查询语言。不过最近几年文档数据库和键值对数据库成了流行的替代选择,这两种数据库合称 NoSQL数据库,比如 redis 等等。

Flask 中的数据库框架

每一种语言,都有对应的比较完善的数据库框架,这些框架可以帮助我们更加方便的进行数据库操作,从而屏蔽掉相关的具体 SQL 语句,也可以防止 SQL 注入等安全隐患。Python 当然不例外,可以通过 ORM 来把底层 SQL 转换成 Python 对象,这样一来,我们甚至不需要了解 SQL,只通过 Python 代码就可以完成数据库操作。

而在 Flask 当中,就有这么一个插件,可以非常方便的操作数据库:Flask-SQLAlchemy

Flask-SQLAlchemy

Flask-SQLAlchemy 是一个 Flask 扩展,简化了在 Flask 程序中使用 SQLAlchemy 的操作。

SQLAlchemy 是一个很强大的关系型数据库框架,支持多种数据库后台。SQLAlchemy 提

供了高层 ORM,也提供了使用数据库原生 SQL 的低层功能。和其他大多数扩展一样,Flask-SQLAlchemy 也使用 pip 安装:

pip install flask-sqlalchemy

在 Flask-SQLAlchemy 中,数据库使用 URL 指定。最流行的数据库引擎采用的数据库 URL

格式如下所示

数据库引擎 URL
MySQL mysql://username:password@hostname/database
Postgres postgresql://username:password@hostname/database
SQLite(Unix) sqlite:////absolute/path/to/database
SQLite(Windows) sqlite:///c:/absolute/path/to/database

这里的 URL 必须是保存在 Flask 对象 SQLALCHEMY_DATABASE_URI 键中,配置对象中还有一个很有用的选项,即 SQLALCHEMY_COMMIT_ON_TEARDOWN 键,将其设为 True 时,每次请求结束后都会自动提交数据库中的变动。

下面就是配置数据库的代码

from flask_sqlalchemy import SQLAlchemy
basedir = os.path.abspath(os.path.dirname(__file__))
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + os.path.join(basedir, 'data.sqlite')
app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True
db = SQLAlchemy(app)

db 对象是 SQLAlchemy 类的实例,表示程序使用的数据库,同时还获得了 Flask-SQLAlchemy

提供的所有功能。

定义模型

模型这个术语表示程序使用的持久化实体。在 ORM 中,模型一般是一个 Python 类,类中的属性对应数据库表中的列。

Flask-SQLAlchemy 创建的数据库实例为模型提供了一个基类以及一系列辅助类和辅助函数,可用于定义模型的结构。

下面我们定义一个 User 模型

class Role(db.Model):
    __tablename__ = 'roles'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), unique=True)
class User(db.Model):
    __tablename__ = 'users'
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(64), unique=True, index=True)

在这里,类变量 __tablename__ 用于定义表名,表中列的属性由 db.Column 来定义

下面是一些常用的列类型


下面是一些常用的列选项


表关系

在我们当前的数据模型下,角色与用户是一对多的关系,一个角色可以属于多个用户,而一个用户只可以是一个角色。下面我们修改下上面定义的两个模型

class Role(db.Model):
    __tablename__ = 'roles'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), unique=True)
    users = db.relationship('User', backref='role')
class User(db.Model):
    __tablename__ = 'users'
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(64), unique=True, index=True)
    role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))

db.relationship() 中的 backref 参数向 User 模型中添加一个 role 属性,从而定义反向关

系。这一属性可替代 role_id 访问 Role 模型,此时获取的是模型对象,而不是外键的值。

添加到 User 模型中的 role_id 列被定义为外键,就是这个外键建立起了关系。传递 db.ForeignKey() 的参数 'roles.id' 表明,这列的值是 roles 表中行的 id 值。

数据库操作

下面我们看下如何进行数据库的相关操作,我们在 Python shell 中实际操作下

创建数据库

要注意,我们这里是使用的是最新的 flask 版本(1.1.2),所以是自带了 shell 命令的,直接执行 flask shell 命令

Zhouluobo:HelloFlask edisonvera$ flask shell
/usr/local/lib/python3.6/site-packages/flask_sqlalchemy/__init__.py:834: FSADeprecationWarning: SQLALCHEMY_TRACK_MODIFICATIONS adds significant overhead and will be disabled by default in the future.  Set it to True or False to suppress this warning.
  'SQLALCHEMY_TRACK_MODIFICATIONS adds significant overhead and '
Python 3.6.4 (default, Jan  6 2018, 11:49:38) 
[GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.42.1)] on darwin
App: app [production]
Instance: /Users/edisonvera/Develop_zw/FlaskCode/FlaskCode/HelloFlask/instance
>>>

可以看到我们已经进入了一个 shell 的操作界面,在该界面,我们执行数据库创建命令 db.create_all()

>>> from app import db
>>> db.create_all()
>>>

这样,我们在当前的目录下就生成了一个 data.sqlite 的数据库文件,并且有两个数据表

如果我们要删除当前的数据库,可以使用 db.drop_all()

在视图函数中操作数据库

下面我们就开始在视图函数中进行数据库的操作,这才是最为重要的。

我们先把在登录页面的用户保存到数据库表当中

@app.route('/login/', methods=['GET', 'POST'])
def login():
    form = LoginForm()
    if form.validate_on_submit():
        username = form.username.data
        session['username'] = username
        user = User(username=username)
        db.session.add(user)
        db.session.commit()
        flash("Login Successful!")
        return redirect(url_for('index'))
    return render_template('login.html', form=form)

这样,我们在登录页面输入用户名和密码之后,我们的用户就会被保存到数据库当中了。


下面我们就可以修改 index 函数,查看 session 中的用户名,如果不存在则打印当前为陌生人

@app.route('/')
def index():
    user = session.get('username')
    isUser = User.query.filter_by(username=user).first()
    if isUser is None:
        session['known'] = False
    else:
        session['known'] = True
    return render_template('index.html', user=user, known=session.get('known', False))

当然还需要修改模板

{% extends "base.html" %}
{% block title %}My Web - Index{% endblock %}
{% block page_content %}
{% for message in get_flashed_messages() %}
 <div class="alert alert-warning">
     <button type="button" class="close" data-dismiss="alert">&times;</button>
     {{ message }}
 </div>
{% endfor %}
<div class="page-header">
 <h1>Hello, {% if user %}{{ user }}{% else %}Stranger{% endif %}!</h1>
 {% if not known %}
 <p>你是个陌生人哦!</p>
 {% else %}
 <p>很高兴再次遇见你!</p>
 {% endif %}
</div>
{% endblock %}

可以看到如下效果


常用过滤器与执行函数

从上面的视图函数中我们看到,使用了 filter_by,那么我们再看下其他的过滤器


filter_by() 等过滤器在 query 对象上调用,返回一个更精确的 query 对象。多个过滤器可以一起调用,直到获得所需结果。

下面我们再来看下执行函数


在查询上应用指定的过滤器后,通过调用 all() 执行查询,以列表的形式返回结果。除了all() 之外,还有其他方法能触发查询执行。

数据库迁

在开发程序的过程中,我们会发现有时需要修改数据库模型,而且修改之后还需要更新数据库。

仅当数据库表不存在时,Flask-SQLAlchemy 才会根据模型进行创建。因此,更新表的唯一方式就是先删除旧表,不过这样做会丢失数据库中的所有数据。

更新表的更好方法是使用数据库迁移框架,源码版本控制工具可以跟踪源码文件的变化,

类似地,数据库迁移框架能跟踪数据库模式的变化,然后增量式的把变化应用到数据库中。

SQLAlchemy 的主力开发人员编写了一个迁移框架,称为 Alembic(https://alembic.readthedocs.org/en/latest/index.html)。除了直接使用 Alembic 之外,Flask 程序还可使用 Flask-Migrate(http://flask-migrate.readthedocs.org/en/latest/)扩展。

首先我们先安装 Flask-Migrate

pip install flask-migrate

接下来配置 migrate

from flask_migrate import Migrate
migrate = Migrate(app, db)

使用 init 来创建迁移仓库

flask db init

Flask-Migrate 提供了一个命令集,使用 db 作为命名集名称,它提供的命令都以 flask db 开头。我们可以在命令行中输入 flask--help 查看所有可

用的命令和说明。

迁移环境只需要创建一次,这会在我们的项目根目录下创建一个 migrations 文件夹,其中包含了自动生成的配置文件和迁移版本文件夹。

如下图


下面我们就可以生成迁移脚本和更新数据库了

生成迁移脚本

flask db migrate -m "need update"

更新数据库

flask db upgrade

当然了,还有更多的数据库高级进阶操作,我们就留到后面的内容中慢慢学习吧

这部分完整代码,可以检出5a

总结

本节我们学习了数据库相关的内容,从 SQLAlchemy 到 flask_SQLAlchemy,以及如何在视图函数中使用,还有更加方便的迁移数据库等等知识。


最后的最后,如果觉得文章给了你一些启发或者帮助,还请帮忙点个赞,给辛苦码字的我一点小小鼓励,谢谢!!

相关文章
|
5天前
|
安全 网络安全 数据安全/隐私保护
Flask 入门系列教程(六)
Flask 入门系列教程(六)
|
5天前
|
关系型数据库 数据库连接 数据库
Flask应用基础入门总结
Flask应用基础入门总结
45 0
|
2天前
|
数据库连接 Python
Flask 框架入门与实践:构建你的第一个 Web 应用
【5月更文挑战第18天】本文介绍了使用 Flask 框架构建第一个 Web 应用的步骤。首先通过 `pip install Flask` 安装框架,然后编写基本的 Python 代码创建应用,包括定义路由和响应。示例展示如何显示 &quot;Hello, World!&quot;,并扩展到显示用户信息的功能。利用模板(如 `index.html`)可使页面更丰富。随着学习深入,可以利用 Flask 的更多特性,如表单处理和数据库连接,来构建更复杂的 Web 应用。本文旨在激发读者对 Flask 和 Web 开发的兴趣,鼓励不断探索和实践。
15 7
|
5天前
|
存储 JSON 数据格式
Flask 3 保姆级教程(一):快速上手
Flask 3 保姆级教程(一):快速上手
|
5天前
|
人工智能 前端开发 算法
Python 潮流周刊#18:Flask、Streamlit、Polars 的学习教程
Python 潮流周刊#18:Flask、Streamlit、Polars 的学习教程
42 4
|
5天前
|
安全 数据安全/隐私保护 Python
Flask 入门系列教程(四)
Flask 入门系列教程(四)
|
5天前
|
存储 前端开发 JavaScript
Flask 入门系列教程(三)
Flask 入门系列教程(三)
|
5天前
|
Web App开发 前端开发 JavaScript
Flask 入门系列教程(一)
Flask 入门系列教程(一)
103 1
|
存储 Python 文件存储
Flask入门request session cookie(二)
1 HTTP方法分类 1 GET 浏览器告知服务器:只获取页面上的信息并发给我。这是最常用的方法。 2 HEAD 浏览器告诉服务器:欲获取信息,但是只关心消息头 。
|
5天前
|
API 数据库 数据安全/隐私保护
Flask框架在Python面试中的应用与实战
【4月更文挑战第18天】Django REST framework (DRF) 是用于构建Web API的强力工具,尤其适合Django应用。本文深入讨论DRF面试常见问题,包括视图、序列化、路由、权限控制、分页过滤排序及错误处理。同时,强调了易错点如序列化器验证、权限认证配置、API版本管理、性能优化和响应格式统一,并提供实战代码示例。了解这些知识点有助于在Python面试中展现优秀的Web服务开发能力。
29 1

相关实验场景

更多