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

文章目录

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

写在前边

这个篇文章是基于前三章 内容的,基础的建议 专栏从头看起

笔者学习该书的环境是:

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

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

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

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

扩展了解

数据库管理系统(DMS)

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

使用 SQLAlchemy操作数据库

安装Flask-SQLAlchemy

bash 复制代码
pip3 install flask-sqlalchemy

初始操作

py 复制代码
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:数据库配置

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创建数据库模型:

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

bash 复制代码
flask shell

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

bash 复制代码
>>> from app import db
>>> db.create_all()

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

bash 复制代码
>>> db.drop_all()
>>> db.create_all()
扩展了解

数据库迁移工具 Alembic

代码实现

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

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.')

终端执行

bash 复制代码
flask initdb

重新创建

bash 复制代码
flask initdb --drop

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

app.py

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)
增(添加)
bash 复制代码
>>> 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的记录

bash 复制代码
>>> movie = Movie.query.get(1)
>>> db.session.delete(movie)
>>> db.session.delete()
>>> db.session.commit()
改(修改)

id2的修改

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

通用的调用方法

bash 复制代码
<模型类>.query.<过滤方法(可选)>.<查询方法>
bash 复制代码
>>> 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中的

py 复制代码
@app.route("/")
def index():
    return render_template("index.html",name=name,movies=movies)

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

修改 index.html name修改为 user.name

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>
生成虚拟数据

借助faker快速生成虚拟数据

生成虚拟数据的命令函数
py 复制代码
"""注意需要在终端执行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("创建虚拟数据 成功")

执行

py 复制代码
flask forge

最终 修改俩文件

app.py

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

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>
相关推荐
雨夜之寂3 小时前
第一章-第三节-Java开发环境配置
java·后端
路在脚下@4 小时前
C++ 知识体系
c++·1024程序员节
疯狂的沙粒4 小时前
前端开发【工具函数】基于dayjs 封装的DateUtils工具函数,可以直接拿着使用
前端·javascript·vue.js·1024程序员节
郑清4 小时前
Spring AI Alibaba 10分钟快速入门
java·人工智能·后端·ai·1024程序员节·springaialibaba
枫叶丹44 小时前
破局政务数字化核心难题:金仓数据库以国产化方案引领电子证照系统升级之路
数据库·政务·1024程序员节·金仓
你的电影很有趣4 小时前
lesson76:Vue.js 核心特性详解:事件处理、计算属性与侦听器
javascript·vue·1024程序员节
belldeep4 小时前
python:怎样用 Django 开发电子商务程序
django·电子商务·1024程序员节
Neil今天也要学习4 小时前
永磁同步电机无速度算法--基于相位超前校正的LESO
算法·1024程序员节
zl9798994 小时前
SpringBoot-Web开发之数据响应
java·spring boot·后端