赞
踩
SQLAlchemy 是 Python 下非常好的 ORM 框架,支持使用 MySQL、PostgreSQL、SQLite 等主流数据库。Flask-SQLAlchemy 基于 SQLAlchemy 对 Flask 进行了适配,使其在 Flask 下的使用变得简单。
在建立模型之前,需要对客户需求进行分析。
假设现在需要实现一个简单的文章发布系统,用户可以在其中发布文章,管理员用户可管理(增、删、改、查)所有文章。此处可以将以上需求分解为“用户模块”与“文章模块”,然后为各个模板设计相应的模型。
如果需要实现基本的登录功能,则用户模型需要拥有“用户名”“密码”这些属性。用户还可以作为管理员,为了区分普通用户和管理员,用户模型还需要拥有“是否为管理员”属性。另外,如果需要创建文章,便需要使用“id”属性将用户模型与文章模型进行关联。
这里使用的是 SQLite 数据库,可视化工具为 sqlitestudio。
表 1 用户模型结构
模型属性 | Python 中数据类型 | 数据表中字段类型 | 说明 |
---|---|---|---|
id | int | INTEGER | 用于指向用户的唯一编号 |
username | str | VARCHAR | 用户名 |
password | str | VARCHAR | 密码 |
is_admin | bool | BOOLEAN | 是否为管理员 |
表2 文章模型结构
模型属性 | Python 中数据类型 | 数据表中字段类型 | 说明 |
---|---|---|---|
id | int | INTEGER | 用于指向文章的唯一编号 |
title | str | VARCHAR | 文章标题 |
content | str | VARCHAR | 文章正文内容 |
初始化 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()
输入命令 python app.py shell
进入交互界面,用命令 db.create_all()
创建数据库 data.sqlite
。
通常情况下数据库的操作主要通过 SQL 语句进行,而 SQLAlchemy 提供了将数据映射到对象中的操作方式。这样的方式使得对数据的操作变得简单,使用者无须学习 SQL 语法即可完成数据操作。
增加数据(交互式 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()
如果需要在 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>
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()
删除数据的操作是建立在查询数据基础之上的,在获取到模型对象后,将模型对象加入数据操作队列,执行提交即可进行改动。不同之处在于,删除时使用 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()
交互式 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()
# 从第 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)
在网站使用流程中,文章由用户创建,即每一篇文章都会对应一个作者;可以根据文章找到对应的用户,也可以根据特定的用户查询到与之对应的文章。 要实现上述效果,仅需为这两个模型建立外键关联。 在文章模型代码中添加外键(作者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
数据分页显示是一个很常见的功能。例如之前所设计的文章模型,当文章数量达到一定程度(例如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)
<!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>
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。