当前位置:   article > 正文

Flask 之 SQLAlchemy_flask-sqlalchemy

flask-sqlalchemy

SQLAlchemy 是 Python 下非常好的 ORM 框架,支持使用 MySQL、PostgreSQL、SQLite 等主流数据库。Flask-SQLAlchemy 基于 SQLAlchemy 对 Flask 进行了适配,使其在 Flask 下的使用变得简单。


1. 建立模型

在建立模型之前,需要对客户需求进行分析。

假设现在需要实现一个简单的文章发布系统,用户可以在其中发布文章,管理员用户可管理(增、删、改、查)所有文章。此处可以将以上需求分解为“用户模块”与“文章模块”,然后为各个模板设计相应的模型。

如果需要实现基本的登录功能,则用户模型需要拥有“用户名”“密码”这些属性。用户还可以作为管理员,为了区分普通用户和管理员,用户模型还需要拥有“是否为管理员”属性。另外,如果需要创建文章,便需要使用“id”属性将用户模型与文章模型进行关联。

这里使用的是 SQLite 数据库,可视化工具为 sqlitestudio。

表 1 用户模型结构

模型属性Python 中数据类型数据表中字段类型说明
idintINTEGER用于指向用户的唯一编号
usernamestrVARCHAR用户名
passwordstrVARCHAR密码
is_adminboolBOOLEAN是否为管理员

表2 文章模型结构

模型属性Python 中数据类型数据表中字段类型说明
idintINTEGER用于指向文章的唯一编号
titlestrVARCHAR文章标题
contentstrVARCHAR文章正文内容

初始化 Flask-SQLAlchemy 并且定义用户模型和文章模型

#!/usr/bin/env python
# -*- coding: UTF-8 -*-

import os
from flask import Flask, render_template
from flask_script import Manager, Shell
from flask_sqlalchemy import SQLAlchemy


app = Flask(__name__)
# 设置数据库存储位置
basedir = os.path.abspath(os.path.dirname(__file__))
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + os.path.join(basedir, 'data.sqlite')
app.config['SQLCLCHEMY_TRACK_MODIFICATIONS'] = False
# flask_sqlalchemy 初始化代码
db = SQLAlchemy()
db.init_app(app)
manager = Manager(app)

@app.route('/', methods=['post'])
def login():
    return "Hello World!"

# 定义用户模型
class UserModel(db.Model):
    __tablename__ = 'user'
    id = db.Column(db.INTEGER, primary_key=True, autoincrement=True)
    username = db.Column(db.VARCHAR, unique=True)
    password = db.Column(db.VARCHAR)
    is_admin = db.Column(db.BOOLEAN, default=False, nullable=False)

# 定义文章模型
class ArticleModel(db.Model):
    __tablename__ = 'article'
    id = db.Column(db.INTEGER, primary_key=True)
    title = db.Column(db.VARCHAR)
    content = db.Column(db.VARCHAR)

# 交互式 shell
def make_shell_context():
    return dict(app=app, db=db, UserModel=UserModel, ArticleModel=ArticleModel)
manager.add_command('shell', Shell(make_context=make_shell_context))


if __name__ == "__main__":
    manager.run()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46

输入命令 python app.py shell 进入交互界面,用命令 db.create_all()创建数据库 data.sqlite


2. 数据操作

通常情况下数据库的操作主要通过 SQL 语句进行,而 SQLAlchemy 提供了将数据映射到对象中的操作方式。这样的方式使得对数据的操作变得简单,使用者无须学习 SQL 语法即可完成数据操作。

2.1 增加数据

增加数据(交互式 shell)

# 创建用户对象
In [1]: user_1 = UserModel(
   ...: username='admin',
   ...: password='123456',
   ...: is_admin=True)
In [2]: user_2 = UserModel(
   ...: username='user',
   ...: password='123456',
   ...: is_admin=False)

# 将用户对象添加到数据操作队列
In [3]: db.session.add(user_1)

In [4]: db.session.add(user_2)

In [5]: db.session.commit()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

2.2 查询数据

如果需要在 Python 中获取相应的用户数据,则需要通过模型类查询来实现。如果要实现用户登录,便只需要将用户输入数据与数据库中查询到的用户数据进行比较,正确则登录成功,反之登录失败。

模型类查询代码(交互式 shell)

# 获取所有用户对象
In [1]: users = UserModel.query.all()

In [2]: print(users)
[<UserModel 1>, <UserModel 2>]

# 获取所有符合条件的用户对象
In [3]: users = UserModel.query.filter_by(is_admin=True).all()

In [4]: print(users)
[<UserModel 1>]

# 获取所有符合条件的用户对象的数据
In [5]: num = UserModel.query.filter_by(is_admin=True).count()

In [6]: print(num)
1

# 获取一个符合条件的用户对象
In [7]: user = UserModel.query.filter(UserModel.id > 1).first()

In [8]: print(user)
<UserModel 2>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

2.3 修改数据

In [1]: user = UserModel.query.get(2)

In [2]: user.password = 'admin'

In [3]: user.is_admin = True

In [4]: db.session.add(user)

In [5]: db.session.commit()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

2.4 删除数据

删除数据的操作是建立在查询数据基础之上的,在获取到模型对象后,将模型对象加入数据操作队列,执行提交即可进行改动。不同之处在于,删除时使用 delete() 方法进行操作。

In [10]: user1 = UserModel.query.get(1)

In [11]: user2 = UserModel.query.get(2)

In [12]: db.session.delete(user1)

In [13]: db.session.delete(user2)

In [14]: db.session.commit()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

3. 高级查询

交互式 shell

# 快速添加5 个测试用的文章模型
for i in range(5):
    article = ArticleModel(title=' 文章_%d' % i, content='This is article_%d.' % i)

db.session.add(article)

article = ArticleModel(title=' 测试文章1', content='Hello World!')

db.session.add(article)

article = ArticleModel(title=' 测试文章2', content='Hello Flask!')

db.session.add(article)

db.session.commit()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
# 从第 3  个对象(索引从 0  开始)开始,获取所有数据
articles = ArticleModel.query.offset(2).all()print(articles)# 获取前 2  个对象
articles = ArticleModel.query.limit(2).all()print(articles)# 从第 2  个对象开始,获取 3  个对象
articles = ArticleModel.query.offset(1).limit(3).all()print(articles)# 获取所有文章对象,并根据 id 对所有文章进行降序排列
articles = ArticleModel.query.order_by(ArticleModel.id.desc()).all()print(articles)# 获取所有文章对象,并根据 id 对所有文章进行升序排列(默认)
articles = ArticleModel.query.order_by(ArticleModel.id.asc()).all()print(articles)# 获取文章内容中包含“Hello ”的所有文章
articles = ArticleModel.query.filter(ArticleModel.content.contains('Hello')).all()print(articles)# 引入 and_ 、or_ 操作
from sqlalchemy import and_, or_
# 获取文章内容中包含“article”,或文章标题中包含“测试”的所有文章
articles = ArticleModel.query.filter(or_(
           ArticleModel.content.contains('article'),
           ArticleModel.title.contains(' 测试'),)).all()print(articles)# 获取id > 3 ,且文章内容中包含“article”的所有文章
articles = ArticleModel.query.filter(and_(
           ArticleModel.id > 3,
           ArticleModel.content.contains('article'),)).all()print(articles)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

4. 模型关联

在网站使用流程中,文章由用户创建,即每一篇文章都会对应一个作者;可以根据文章找到对应的用户,也可以根据特定的用户查询到与之对应的文章。 要实现上述效果,仅需为这两个模型建立外键关联。 在文章模型代码中添加外键(作者id),以及反向关联属性(在用户模型中定义)。

# 定义用户模型
class UserModel(db.Model):
    __tablename__ = 'user'
    id = db.Column(db.INTEGER, primary_key=True, autoincrement=True)
    username = db.Column(db.VARCHAR, unique=True)
    password = db.Column(db.VARCHAR)
    is_admin = db.Column(db.BOOLEAN, default=False, nullable=False)
    # 建立一对多映射关系(uselist=True)
    # 为了便于IDE 识别变量类型,此处声明articles 类型为list
    articles: list = db.relationship('ArticleModel', backref='author', uselist=True)

# 定义文章模型
class ArticleModel(db.Model):
    __tablename__ = 'article'
    id = db.Column(db.INTEGER, primary_key=True)
    title = db.Column(db.VARCHAR)
    content = db.Column(db.VARCHAR)
    # 根据用户 id 与文章模型进行外键关联
    # author_id 不作为主键,为了保证效率,需要为字段建立索引(index=True)
    author_id = db.Column(db.INTEGER, db.ForeignKey('user.id'), index=True)
    # 声明 author 属性类型,以便 IDE 进行识别
    author: UserModel
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

5. 数据分页显示

数据分页显示是一个很常见的功能。例如之前所设计的文章模型,当文章数量达到一定程度(例如10篇)时,便不再适合在单个页面中展示,这时便需要用到数据分页显示功能,使每一页加载部分文章数据。 当然,像这种常见需求,Flask-SQLAlchemy与Flask-Bootstrap都已经实现好了,只要引入相应功能并使用即可。

@app.route('/paginator')
def paginator():
    # 每页显示 3 篇文章
    pagination = ArticleModel.query.paginate(per_page=3)
    return render_template('paginator1.html', pagination=pagination)
  • 1
  • 2
  • 3
  • 4
  • 5
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>数据分页显示</title>
    {% import 'pagination.html' as pagi %}
</head>
<body>
    <div class="container">
        {% for item in pagination.items %}
        <h1>{{ item.title }}</h1><p>{{ item.content | safe }}</p>
        {% endfor %}
        {#  根据pagination(分页)对象渲染分页按钮 #}
        {{ pagi.render_pagination(pagination) }}
    </div></body>
</html>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/神奇cpp/article/detail/788271
推荐阅读
相关标签
  

闽ICP备14008679号