《我用Python写网站02》数据库管理

原文链接
上一篇:我用Python写网站《一》
欢迎来我的论坛讨论Python搭建博客网站的问题和经验。www.ahoh.club
本系列所有文章都会同步到这里,如果不想关注博主,就来这里阅读吧!

通过本文,可以掌握:

  1. Flask插件的配置方法
  2. Flask-SQLAlchemy插件的使用
  3. 数据库操作
  4. Flask-Migrate控制数据库版本
  5. Flask Shell的简单使用

使用Flask-SQLAlchemy插件管理数据库

写在前面

原计划在本文中详细介绍使用Flask开发网站所需要的项目布局,也就是不同的代码在项目中怎么存放,这也有助于我继续后面的讲解。但是,由于上一篇介绍的内容太少,直接讲解项目结构会引起刚入门童鞋水土不服,所以转而介绍如何在Flask应用中使用数据库插件。

这也符合我写本系列的理念,以解决问题为导向,不求甚解,等代码比较乱之后,再系统的修改整个项目的框架,比较容易接收,效果也可能会更好。

学习本文之前,请一定要先安装Mysql

1. 使用Flask-SQLAlchemy插件

Flask是一个非常轻量(简单、功能少)的框架,它通过各种插件提供丰富的功能,Flask-SQLAlchemy就是万千插件中非常亮眼的一个。

说起Flask-SQLAlchemy,就不得不说说SQLAlchemy。细心的童鞋可能已经发现了,在网络上存在两个包,一个叫sqlalchemy,另一个就是flask-sqlalchemy。它们两个的关系非常简单,sqlalchemy是针对Python的对象关系映射(ORM)框架,而flask-sqlalchemy就是在sqlalchemy的基础上进行了封装,使它在Flask上应用更容易。

再简单介绍一下ORM框架,ORMObject-Relational-Mapping)特指对象和关系之间的映射。其中关系就是数据库中的表,对象就是指面向对象中的对象(类),映射就是指把表和对象扯上关系。

正常情况下我们操作数据库都是用SQL语句,使用了Flask-SQLAlchemy之后就可以直接操作对象,不需要写任何SQL代码。
例如,使用SQL查询所有用户,代码如下:

select * from t_user;

使用sqlalchemy只需要:

User.query.all()

二者产生的结果完全相同,所以,选择Flask-SQLAlchemy没商量。

废话不多说,立即开始。
首先,进入上一篇已经建立好的ahoh文件夹,然后激活Python虚拟环境:

~$ cd ahoh
~/ahoh$ . venv/bin/activate

在使用Flask-SQLAlchemy之前,需要先安装对应的包,以及Mysql驱动程序pymysql

(venv)~/ahoh$ pip install pymysql
(venv)~/ahoh$ pip install flask-sqlalchemy

安装完成后,在~/ahoh/app.py文件中引入Flask-SQLAlchemy对应的类:

from flask_sqlalchemy import SQLAlchemy

然后在 app=Flask(__name__)语句后面添加配置对应的参数,并创建SQLAlchemy对象:

app.config.from_mapping(
    SQLALCHEMY_DATABASE_URI='mysql+pymysql://root:123456@localhost/ahoh?charset=utf8',
    SQLALCHEMY_TRACK_MODIFICATIONS=True
)

db= SQLAlchemy(app)

SQLALCHEMY_DATABASE_URI变量的配置,就是为了向SQLAlchemy指明你使用的数据库类型、驱动、数据库用户名、密码、IP和数据库名,具体如下图:

SQLALCHEMY_DATABASE_URI的意义
然后,不要忘了,在Mysql中创建对应的数据库,这里使用的是ahoh,创建数据库命令如下:

create database ahoh;

到这里,Flask-SQLAlchemy插件的配置工作已经完成了,但是,现在还不能测试。

既然是对象关系映射(ORM)框架,必然还要提供对象,然后才能映射到关系表。

SQLAlchemy 对象

所谓SQLAlchemy对象,无非就是一个特殊的类,这里就直接在app.py文件的末尾,追加User类:

class User(db.Model):
    __tablename__ = 't_users'  # 对应的数据库表名
    id = db.Column(db.Integer, primary_key=True, autoincrement=True) # 自增主键
    username = db.Column(db.String(80), unique=True, nullable=False)
    email = db.Column(db.String(120), unique=True)
    password = db.Column(db.String(127), nullable=False)

这个类中的每一个属性,都对应数据库中表的一列,应该还是比较容易理解的,db.Integerdb.String是最常用的两个类型,SQLAlchemy还有很多其他类型的数据,后面后逐步扩展我们的代码。

为了保证大家都跟的上,下面贴出app.py的代码:

# ~/ahoh/app.py
from flask import Flask, render_template, request
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)

app.config.from_mapping(
    SQLALCHEMY_DATABASE_URI='mysql+pymysql://root:123456@localhost/ahoh?charset=utf8',
    SQLALCHEMY_TRACK_MODIFICATIONS=True
)

db = SQLAlchemy(app)


@app.route('/')
def index():
    return '你好, Flask'

... ... # 代码过长,此处省略其他视图函数
class User(db.Model):
    __tablename__ = 't_users'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    username = db.Column(db.String(80), unique=True, nullable=False)
    email = db.Column(db.String(120), unique=True)
    password = db.Column(db.String(127), nullable=False)

OK,到了这里,所有的sqlalchemy工作就算做完了,下面开始测试工作。

下面就用Flask Shell完成数据库中表的创建工作,测试代码正确性。

Flask Shell创建数据表

首先使用Ctrl+C停下正在运行的Flask服务,然后在命令行中输入:

(venv)~/ahoh$ flask shell  # 启动Flask Shell
Python 3.8.10 (default, Nov 26 2021, 20:14:08) 
[GCC 9.3.0] on linux
App: app [production]
Instance: /home/wei/ahoh/instance
>>>                      # 出现命令提示符表示成功启动 

Flask ShellPython可交互编程环境差不多,我们不做深究,直接开始。

Shell中输入以下代码:

>>> from app import db   # 引入db变量
>>> db.create_all()      # 创建所有的表

以上指令,就会创建所有继承了db.Model的类对应的表了,如果在输入db.create_all()后没有任何输出(没有报错信息),大概率就是成功了。

然后,新开一个终端,进入Mysql查看ahoh数据库中是否真的创建了表:

mysql> use ahoh;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> show tables;
+----------------+
| Tables_in_ahoh |
+----------------+
| t_users        |
+----------------+
1 row in set (0.00 sec)

mysql>

还可以使用 DESC指令查看表的结构:

mysql> desc t_users;
+----------+--------------+------+-----+---------+----------------+
| Field    | Type         | Null | Key | Default | Extra          |
+----------+--------------+------+-----+---------+----------------+
| id       | int          | NO   | PRI | NULL    | auto_increment |
| username | varchar(80)  | NO   | UNI | NULL    |                |
| email    | varchar(120) | YES  | UNI | NULL    |                |
| password | varchar(127) | NO   |     | NULL    |                |
+----------+--------------+------+-----+---------+----------------+
4 rows in set (0.00 sec)

mysql>

建表工作这里就完成了,下面测试数据表的增删改查。

回到Flask Shell,输入以下指令,向t_users表中插入数据:

>>> from app import User               # 引入User类
>>> u = User(username='xiaoming',email='123@123.com',password='123456') # 创建User实例
>>> db.session.add(u)                 # 向数据库添加新数据
>>> db.session.commit()               # 提交

如果执行以上指令之后,没有报错信息,就厉害大发了。

赶快回到Mysql查看一下t_users表里面到底有没有数据,使用以下指令:

mysql> select * from t_users;   # 查询表中所有数据
+----+----------+-------------+----------+
| id | username | email       | password |
+----+----------+-------------+----------+
|  1 | xiaoming | 123@123.com | 123456   |
+----+----------+-------------+----------+
1 row in set (0.00 sec)

输出和我一样就证明没有问题了!

提醒:密码明文存储是非常愚蠢的行为,这里仅供展示使用,后面会使用加密手段
这也是为什么密码列预留空间很大的原因,你发现了吗

只有一条数据肯定不像话,多加几条:

>>> u1 = User(username='aaa',password='bbb',email="123@qwe.com")
>>> u2 = User(username='eee',password='bbb',email="qwe@qwe.com")
>>> db.session.add(u1)
>>> db.session.add(u2)
>>> db.session.commit()

然后测试删、改功能:

# 删除测试
>>> u = User.query.filter_by(username='aaa').first() # 查询
>>> u.username
'aaa'
>>> db.session.delete(u) # 删除
>>> db.session.commit()
# 修改测试
>>> u = User.query.filter_by(username='xiaoming').first()
>>> u.username
'xiaoming'
>>> u.username='老天爷'
>>> db.session.add(u)
>>> db.session.commit()

Flask-Migrate数据库版本控制

现在数据库和Flask-SQLAlchemy插件都配置好了,新问题又来了。

我现在对数据表不满意,因为没有年龄age字段,而且我希望最终建立的数据库有很多表,和现在差距肯定非常大。

所以我需要不断的修改db.Model的子类,如何在每次修改对象类后,将改动同步到数据库呢?

这就需要Flask-Migrate插件了,首先,老规矩,安装插件:

(venv) ~/ahoh$ pip install flask-migrate

接下来就是配置Flask-Migrate插件,非常简单,先在app.py文件头部导入:

from flask_migrate import Migrate

然后在db=SQLAlchemy(app)后创建migrate实例:

migrate = Migrate(app, db)

这样就配置完成了。

Flask-Migrate的使用也很方便,包括三条命令

首先就是初始化命令:flask db init
在首次安装Flask-Migrate插件后,需要执行一次,后面就不需要了。
我们先初始化:

(venv) ~/ahoh$ flask db init
  Creating directory /home/wei/ahoh/migrations ...  done
  Creating directory /home/wei/ahoh/migrations/versions ...  done
  Generating /home/wei/ahoh/migrations/script.py.mako ...  done
  Generating /home/wei/ahoh/migrations/env.py ...  done
  Generating /home/wei/ahoh/migrations/alembic.ini ...  done
  Generating /home/wei/ahoh/migrations/README ...  done
  Please edit configuration/connection/logging settings in '/home/wei/ahoh/migrations/alembic.ini' before
  proceeding.

如果你的输出和我一样,就算成功了。

注意:这些命令都是直接在命令行执行的,并不是在Flask Shell下,别搞错了哦!

接下来迁移命令:flask db migrate

(venv) ~/ahoh$ flask db migrate
INFO  [alembic.runtime.migration] Context impl MySQLImpl.
INFO  [alembic.runtime.migration] Will assume non-transactional DDL.
INFO  [alembic.env] No changes in schema detected.

最后是升级命令: flask db upgrade

(venv) ~/ahoh$ flask db upgrade
INFO  [alembic.runtime.migration] Context impl MySQLImpl.
INFO  [alembic.runtime.migration] Will assume non-transactional DDL.

到此为止,Flask-Migrate的前期准备工作就完成了,接下来就可以修改数据库了。

修改数据库,首先要修改表对应的类,这里我就在User类中添加一个age属性:

age = db.Column(db.Integer)

然后在命令行中输入命令flask db migrate

(venv) ~/ahoh$ flask db migrate
INFO  [alembic.runtime.migration] Context impl MySQLImpl.
INFO  [alembic.runtime.migration] Will assume non-transactional DDL.
INFO  [alembic.autogenerate.compare] Detected added column 't_users.age'
  Generating /home/wei/ahoh/migrations/versions/835faba58af3_.py ...  done

最后,执行升级命令flask db upgrade

(venv) ~/ahoh$ flask db upgrade
INFO  [alembic.runtime.migration] Context impl MySQLImpl.
INFO  [alembic.runtime.migration] Will assume non-transactional DDL.
INFO  [alembic.runtime.migration] Running upgrade  -> 835faba58af3, empty message

如果和我一样没有什么错,就算是成功了,下面就去Mysql中查看下:

mysql> desc t_users;
+----------+--------------+------+-----+---------+----------------+
| Field    | Type         | Null | Key | Default | Extra          |
+----------+--------------+------+-----+---------+----------------+
| id       | int          | NO   | PRI | NULL    | auto_increment |
| username | varchar(80)  | NO   | UNI | NULL    |                |
| email    | varchar(120) | YES  | UNI | NULL    |                |
| password | varchar(127) | NO   |     | NULL    |                |
| age      | int          | YES  |     | NULL    |                |
+----------+--------------+------+-----+---------+----------------+
5 rows in set (0.00 sec)

可以看到,age列已经成功添加到表里了!

本文讲的内容在命令行中操作比较多,可能很多童鞋会出现各种各样的错误,无法完全跟上。

我之前也是这样,不过后面会经常使用到Flask-SALAlchemyFlask-Migrate插件,这里没有理解没关系。

后面用的多了自然就会了!

写在最后

本文主要介绍了在Flask应用中使用ORM对象关系映射框架插件Flask-SQLAlchemy
通过Flask-SQLAlchemy我们可以用对象化的方式操作数据库,而不需要写SQL指令。
此外,我们还使用了Flask-Migrate插件管理数据库的版本,在正文中,我们演示了如何使用指令升级数据库版本。
其实,数据库版本不仅能升级(upgrade),还可以降级(downgrade)有兴趣的童鞋,可以留言哦。也可以到我的论坛,发表帖子或者留言,博主会在收到信息后立刻回复的!

下一篇:注册与登录

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

@魏大大

我们都没有打赏的习惯

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值