完整教程:Flask入门教程——李辉 第5章: 数据库 关键知识梳理

第5章: 数据库 关键知识梳理

写在前边

这个篇文章是基于前三章 内容的,基础的建议 专栏从头看起
笔者学习该书的环境是:

  • 系统:Fedora Linux 42 (Workstation Edition)
  • IDE: vscode
  • Python:3.13.X
  • Conda: conda 25.7.0
  • pip: pip 25.2
  • 第三方库 : 最新

Flask作为PythonWeb的后端框架,也需要履行后端的核心职责之一——与数据库进行交互

Flask-SQLAlchemyFlask的第三方扩展,用来简化FlaskSQLAlchemy的操作

SQLite 是一个软件库,实现了自给自足的、无服务器的、零配置的、事务性的 SQL 数据库引擎

扩展了解

数据库管理系统(DMS)

关系数据库管理系统(RDMS)

使用 SQLAlchemy操作数据库

安装Flask-SQLAlchemy

pip3 install flask-sqlalchemy

初始操作

from flask import Flask
from flask_sqlalchemy import SQLAlchemy # 导入扩展类
app = Flask(__name__)
# 初始化扩展 传入程序实例
db = SQLAlchemy(app)

配置连接数据库

  • 配置数据库连接地址 => SQLALCHEMY_DATABASE_URI
  • 对模型修改的检测(可选) => SQLALCHEMY_TRACK_MODIFICATIONS

app_db_connect.py:数据库配置

import os
from flask import Flask
from flask_sqlalchemy import SQLAlchemy # 导入扩展类
app = Flask(__name__)
# 添加数据库URl 为当前路径下的data.db sqlite 文件
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + os.path.join(app.root_path,'data.db')
# 关闭对模型修改的监控
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
# 初始化扩展 传入程序实例
db = SQLAlchemy(app)
扩展了解

Flask-SQLAlchemy文档的配置

Flask文档配置

DB Browser for SQLite 一款 连接SQLite的工具
DB Browser for SQLite 下载

创建数据库模型

借助SQLAIchemy你可以通过定义Python类来表示数据库里的一张表(类属性表示表中的字段/列),通过对这个类进行各种操作来代替SQL语句。这个类我们称之为模型类,类中的属性我们将称之为字段

模型类编写核心:

  1. 模型类要继承db.Model
  2. 字段要实例化db.Column 传入的参数为 字段的类型
  3. 字段约束配置传入额外参数如primary_key`

app_create_db_model.py创建数据库模型:

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
import os
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] ='sqlite:////' + os.path.join(app.root_path,'data.db')
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
class User(db.Model):
"""生成User表
:param db: 数据库模型
"""
id = db.Column(db.Integer,primary_key=True)
name  = db.Column(db.String(20))
class Movie(db.Model):
"""生成电影数据
:param db: 数据库模型
"""
id = db.Column(db.Integer,primary_key=True)
title = db.Column(db.String(60))
year = db.Column(db.String(4))
常用字段类型
字段类说明
Integer整型
String(size)字符串,size 为最大长度,比如 db.String(20)
Text长文本
DateTime时间日期,Python datetime 对象
Float浮点数
Boolean布尔值
常用字段约束配置
约束选项说明
primary_key=True设置为主键
unique=True唯一约束(列值不可重复)
index=True创建索引(提升查询效率)
nullable=False非空约束(默认允许NULL)
default=值默认值(支持函数如datetime.now

创建数据库表

声明:如下代码块中带有>>>的是在flask shell中执行,否则就在终端对话框中执行

命令实现

注意app.pyapp_create_db_model.py

flask shell

注意:这里在vscode IDE终端 中可以补全

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

注意:需要重新生成数据库文件或表模式

>>> db.drop_all()
>>> db.create_all()
扩展了解

数据库迁移工具 Alembic

代码实现

app_initdb.py使用时将其修改为app.py

"""注意需要在终端执行flask initdb命令来创建数据库文件"""
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
import click
import os
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] ='sqlite:////' + os.path.join(app.root_path,'data.db')
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
@app.cli.command()
@click.option('--drop',is_flag=True, help="Create after drop.")
def initdb(drop):
"""Initialize the database."""
if drop:
db.drop_all()
db.create_all()
click.echo('Initialized the database.')

终端执行

flask initdb

重新创建

flask initdb --drop

对数据库表进行(增、删、改、查)

app.py

# coding = utf-8
from flask import Flask,render_template
from flask_sqlalchemy import SQLAlchemy
import click
import os
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] ='sqlite:///' + os.path.join(app.root_path,'data.db')
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
class User(db.Model):
"""生成User表
:param db: 数据库模型
"""
id = db.Column(db.Integer,primary_key=True)
name  = db.Column(db.String(20))
class Movie(db.Model):
"""生成电影数据
:param db: 电影数据模型
"""
id = db.Column(db.Integer,primary_key=True)
title = db.Column(db.String(60))
year = db.Column(db.String(4))
@app.cli.command()
@click.option('--drop',is_flag=True, help="Create after drop.")
def initdb(drop):
"""初始化数据库表"""
if drop:
db.drop_all()
db.create_all()
click.echo('Initialized the database.')
@app.route("/")
def index():
user =  User.query.first()
movies = Movie.query.all()
return render_template("index.html",user=user,movies=movies)
app.run("127.0.0.1",5000,False)
增(添加)
>>> from app import User,Movie
>>> user = User(name="开心-开心急了")
>>> m1 = Movie(title="Leon",year="1994")
>>> m2 = Movie(title="Mahjong",year="1996")
>>> db.session.add(user)
>>> db.session.add(m1)
>>> db.session.add(m2)
>>> db.session.commit()

注意

  1. 在实例化模型时SQLAlchemy会自动处理id字段。
  2. db.session.commit() 才会真的提交db.session.add(user) 是添加到缓存里(这不是有点像gitee吗)
删(除)

删除id为1的记录

>>> movie = Movie.query.get(1)
>>> db.session.delete(movie)
>>> db.session.delete()
>>> db.session.commit()
改(修改)

id2的修改

>>> movie = Movie.query.get(2)
>>> movie.title = 'WALL-E'
>>> movie.year = '2008'
>>> db.session.commit()
查(读取/查找)

通用的调用方法

<模型类>.query.<过滤方法(可选)>.<查询方法>
>>> from app import Movie
>>> movie = Movie.query.first()  # 获取 Movie 模型的第一个记录(返回模型类实例)
>>> movie.title  # 对返回的模型类实例调用属性即可获取记录的各字段数据
'Leon'
>>> movie.year
'1994'
>>> Movie.query.all()  # 获取 Movie 模型的所有记录,返回包含多个模型类实例的列表
[<Movie 1>, <Movie 2>]
  >>> Movie.query.count()  # 获取 Movie 模型所有记录的数量
  2
  >>> Movie.query.get(1)  # 获取主键(id)值为 1 的记录
  <Movie 1>
    >>> Movie.query.filter_by(title='Mahjong').first()  # 获取 title 字段值为 Mahjong 的记录
    <Movie 2>
      >>> Movie.query.filter(Movie.title=='Mahjong').first()  # 等同于上面的查询,但使用不同的过滤方法
      <Movie 2>
常用的过滤方法
过滤方法说明
filter()使用指定的规则过滤记录,返回新产生的查询对象
filter_by()使用指定规则过滤记录(以关键字表达式的形式),返回新产生的查询对象
order_by()根据指定条件对记录进行排序,返回新产生的查询对象
group_by()根据指定条件对记录进行分组,返回新产生的查询对象
常用的查找方法
查询方法说明
all()返回包含所有查询记录的列表
first()返回查询的第一条记录,如果未找到,则返回 None
get(id)传入主键值作为参数,返回指定主键值的记录,如果未找到,则返回 None
count()返回查询结果的数量
first_or_404()返回查询的第一条记录,如果未找到,则返回 404 错误响应
get_or_404(id)传入主键值作为参数,返回指定主键值的记录,如果未找到,则返回 404 错误响应
paginate()返回一个 Pagination 对象,可以对记录进行分页处理
扩展

更多数据库操作方法(Query API)

程序操作数据库

首页读取 数据库数据

修改app.py中的

@app.route("/")
def index():
return render_template("index.html",name=name,movies=movies)

修改结果对数据库表进行增、删、改、查app.py

修改 index.htmlname修改为 user.name

<!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
          <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>{{ user.name }}'s Watchlist</title>
            <link rel="icon" href="{{ url_for('static',filename='dicos.ico')}}">
              <link rel="stylesheet" href="{{url_for( 'static', filename='style.css') }}" type="text/css">
            </head>
            <body>
              <h2>
                  <img src="{{ url_for('static',filename='images/avatar.png')}}" alt="Avatar" class="avatar">
                  {{ user.name }}'s Watchlist
                </h2>
                {# 使用 length 过滤器获取 movies 变量的长度 #}
                  <ul class="movie-list">
                  {% for movie in movies %} {# 迭代movies 变量 #}
                  <li>
                    {{ movie.title }} - {{ movie.year }}
                    {# 等同于 movie['title'] #}
                    {% endfor %} {# 不要忘记endfor 来结束for语句 #}
                  </li>
                </ul>
                  <img src="{{ url_for('static',filename='images/totoro.gif')}}" alt="totoro" class="totoro">
                  <footer>
                    <small>
                    &copy; 2018 <a href="http://helloflask.com/tutorial">HelloFlask</a>
                    </small>
                  </footer>
                </body>
              </html>
生成虚拟数据

借助faker快速生成虚拟数据

生成虚拟数据的命令函数
"""注意需要在终端执行flask forge命令来创建数据库文件"""
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
import click
import os
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] ='sqlite:////' + os.path.join(app.root_path,'data.db')
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
class User(db.Model):
"""生成User表
:param db: 数据库模型
"""
id = db.Column(db.Integer,primary_key=True)
name  = db.Column(db.String(20))
class Movie(db.Model):
"""生成电影数据
:param db: 电影数据模型
"""
id = db.Column(db.Integer,primary_key=True)
title = db.Column(db.String(60))
year = db.Column(db.String(4))
@app.cli.command()
def forge():
"""创建虚拟 数据"""
name = "开心开心-急了"
movies = [
{'title': '实现研究而且.', 'year': '1997'},
{'title': '重要出来不要不要广告.', 'year': '1987'},
{'title': '活动这些城市.', 'year': '1995'},
{'title': '历史网上你的来源选择销售没有.', 'year': '2006'},
{'title': '这样简介个人如果信息怎么类型.', 'year': '2024'},
{'title': '能够时候两个.', 'year': '2004'},
{'title': '部分有限电影不要得到应用.', 'year': '2022'},
{'title': '设备处理最后大学为了.', 'year': '1996'},
{'title': '来自谢谢决定.', 'year': '2021'},
{'title': '提供所以大家您的非常以后有关.', 'year': '2016'}
]
# 将用户添加到 会话(session)中
user = User(name=name)
db.session.add(user)
# 将电影名和电影年份 添加到 会话(session)中
for m in movies:
movie = Movie(title= m['title'],year=m['year'])
db.session.add(movie)
# 提交 会话(session) 里的修改
db.session.commit()
click.echo("创建虚拟数据 成功")

执行

flask forge

最终 修改俩文件

app.py

# coding = utf-8
from flask import Flask,render_template
from flask_sqlalchemy import SQLAlchemy
import click
import os
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] ='sqlite:///' + os.path.join(app.root_path,'data.db')
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
class User(db.Model):
"""生成User表
:param db: 数据库模型
"""
id = db.Column(db.Integer,primary_key=True)
name  = db.Column(db.String(20))
class Movie(db.Model):
"""生成电影数据
:param db: 电影数据模型
"""
id = db.Column(db.Integer,primary_key=True)
title = db.Column(db.String(60))
year = db.Column(db.String(4))
@app.cli.command()
@click.option('--drop',is_flag=True, help="Create after drop.")
def initdb(drop):
"""初始化数据库表"""
if drop:
db.drop_all()
db.create_all()
click.echo('Initialized the database.')
@app.cli.command()
def forge():
"""创建虚拟 数据"""
name = "开心开心-急了"
movies = [
{'title': '实现研究而且.', 'year': '1997'},
{'title': '重要出来不要不要广告.', 'year': '1987'},
{'title': '活动这些城市.', 'year': '1995'},
{'title': '历史网上你的来源选择销售没有.', 'year': '2006'},
{'title': '这样简介个人如果信息怎么类型.', 'year': '2024'},
{'title': '能够时候两个.', 'year': '2004'},
{'title': '部分有限电影不要得到应用.', 'year': '2022'},
{'title': '设备处理最后大学为了.', 'year': '1996'},
{'title': '来自谢谢决定.', 'year': '2021'},
{'title': '提供所以大家您的非常以后有关.', 'year': '2016'}
]
# 将用户添加到 会话(session)中
user = User(name=name)
db.session.add(user)
# 将电影名和电影年份 添加到 会话(session)中
for m in movies:
movie = Movie(title= m['title'],year=m['year'])
db.session.add(movie)
# 提交 会话(session) 里的修改
db.session.commit()
click.echo("创建虚拟数据 成功")
@app.route("/")
def index():
user =  User.query.first()
movies = Movie.query.all()
return render_template("index.html",user=user,movies=movies)
app.run("127.0.0.1",5000,False)

index.html

<!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
          <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>{{ user.name }}'s Watchlist</title>
            <link rel="icon" href="{{ url_for('static',filename='dicos.ico')}}">
              <link rel="stylesheet" href="{{url_for( 'static', filename='style.css') }}" type="text/css">
            </head>
            <body>
              <h2>
                  <img src="{{ url_for('static',filename='images/avatar.png')}}" alt="Avatar" class="avatar">
                  {{ user.name }}'s Watchlist
                </h2>
                {# 使用 length 过滤器获取 movies 变量的长度 #}
                  <ul class="movie-list">
                  {% for movie in movies %} {# 迭代movies 变量 #}
                  <li>
                    {{ movie.title }} - {{ movie.year }}
                    {# 等同于 movie['title'] #}
                    {% endfor %} {# 不要忘记endfor 来结束for语句 #}
                  </li>
                </ul>
                  <img src="{{ url_for('static',filename='images/totoro.gif')}}" alt="totoro" class="totoro">
                  <footer>
                    <small>
                    &copy; 2018 <a href="http://helloflask.com/tutorial">HelloFlask</a>
                    </small>
                  </footer>
                </body>
              </html>
posted @ 2025-11-20 22:22  gccbuaa  阅读(0)  评论(0)    收藏  举报