首页 > 数据库 >【Flask使用】第6篇:Flask数据库和表单验证。0基础md文档集合(附代码,可自取)

【Flask使用】第6篇:Flask数据库和表单验证。0基础md文档集合(附代码,可自取)

时间:2023-11-27 19:32:00浏览次数:48  
标签:md name author Flask db 表单 User 查询 id

本文的主要内容:flask视图&路由、虚拟环境安装、路由各种定义、状态保持、cookie、session、模板基本使用、过滤器&自定义过滤器、模板代码复用:宏、继承/包含、模板中特有变量和函数、Flask-WTF 表单、CSRF、数据库操作、ORM、Flask-SQLAlchemy、增删改查操作、案例、蓝图、单元测试

全套笔记和代码自取地址: 请移步这里

感兴趣的小伙伴可以自取哦,欢迎大家点赞转发~


共 4 章,42 子模块


数据库

  • Flask-SQLAlchemy 安装及连接
  • 使用数据库
  • 综合案例演练
  • 数据库迁移

学习目标

  • 能够理解 ORM 工作原理以及其优缺点
  • 能够写出在 Flask 中连接 MySQL 的配置项格式(IP,端口,数据库)
  • 能够使用 SQLAlchemy 定义出关系为一对多模型类
  • 能够使用 SQLAlchemy 的相关函数创建表及删除表
  • 能够写出的指定模型数据对数据库的增删改代码
  • 能够写出模型数据按照条件查询的功能逻辑
  • 能够写出模型数据按照指定数量分页的功能逻辑
  • 能够写出模型数据按照指定条件排序的功能逻辑
  • 能够按照课件步骤实现综合图书管理的相关案例
  • 能够使用 Flask-Migrate 扩展对数据库进行迁移

数据库基本操作

  • 在Flask-SQLAlchemy中,插入、修改、删除操作,均由数据库会话管理。

    • 会话用 db.session 表示。在准备把数据写入数据库前,要先将数据添加到会话中然后调用 commit() 方法提交会话。
  • 在 Flask-SQLAlchemy 中,查询操作是通过 query 对象操作数据。

    • 最基本的查询是返回表中所有数据,可以通过过滤器进行更精确的数据库查询。

在视图函数中定义模型类

from flask import Flask
from flask_sqlalchemy import SQLAlchemy


app = Flask(__name__)

  
  
#设置连接数据库的URL
  
  
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:[email protected]:3306/test'

app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
  
  
#查询时会显示原始SQL语句
  
  
app.config['SQLALCHEMY_ECHO'] = True
db = SQLAlchemy(app)

class Role(db.Model):
    # 定义表名
    __tablename__ = 'roles'
    # 定义列对象
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), unique=True)
    us = db.relationship('User', backref='role')

    #repr()方法显示一个可读字符串
    def __repr__(self):
        return 'Role:%s'% self.name

class User(db.Model):
    __tablename__ = 'users'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), unique=True, index=True)
    email = db.Column(db.String(64),unique=True)
    password = db.Column(db.String(64))
    role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))

    def __repr__(self):
        return 'User:%s'%self.name
if __name__ == '__main__':
    app.run(debug=True)

模型之前的关联

一对多
class Role(db.Model):
    ...
    #关键代码
    us = db.relationship('User', backref='role', lazy='dynamic')
    ...

class User(db.Model):
    ...
    role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))
  • 其中realtionship描述了Role和User的关系。在此文中,第一个参数为对应参照的类"User"

  • 第二个参数backref为类User申明新属性的方法

  • 第三个参数lazy决定了什么时候SQLALchemy从数据库中加载数据

    • 如果设置为子查询方式(subquery),则会在加载完Role对象后,就立即加载与其关联的对象,这样会让总查询数量减少,但如果返回的条目数量很多,就会比较慢

      • 设置为 subquery 的话,role.users 返回所有数据列表
    • 另外,也可以设置为动态方式(dynamic),这样关联对象会在被使用的时候再进行加载,并且在返回前进行过滤,如果返回的对象数很多,或者未来会变得很多,那最好采用这种方式

      • 设置为 dynamic 的话,role.users 返回查询对象,并没有做真正的查询,可以利用查询对象做其他逻辑,比如:先排序再返回结果
多对多
registrations = db.Table('registrations',  
    db.Column('student_id', db.Integer, db.ForeignKey('students.id')),  
    db.Column('course_id', db.Integer, db.ForeignKey('courses.id'))  
)  
class Course(db.Model):
    ...
class Student(db.Model):
    ...
    courses = db.relationship('Course',secondary=registrations,  
                                    backref='students',  
                                    lazy='dynamic')

常用的SQLAlchemy查询过滤器

过滤器 说明
filter() 把过滤器添加到原查询上,返回一个新查询
filter_by() 把等值过滤器添加到原查询上,返回一个新查询
limit 使用指定的值限定原查询返回的结果
offset() 偏移原查询返回的结果,返回一个新查询
order_by() 根据指定条件对原查询结果进行排序,返回一个新查询
group_by() 根据指定条件对原查询结果进行分组,返回一个新查询

常用的SQLAlchemy查询执行器

方法 说明
all() 以列表形式返回查询的所有结果
first() 返回查询的第一个结果,如果未查到,返回None
first_or_404() 返回查询的第一个结果,如果未查到,返回404
get() 返回指定主键对应的行,如不存在,返回None
get_or_404() 返回指定主键对应的行,如不存在,返回404
count() 返回查询结果的数量
paginate() 返回一个Paginate对象,它包含指定范围内的结果

创建表:

db.create_all()

删除表

db.drop_all()

插入一条数据

ro1 = Role(name='admin')
db.session.add(ro1)
db.session.commit()
  
  
#再次插入一条数据
  
  
ro2 = Role(name='user')
db.session.add(ro2)
db.session.commit()

一次插入多条数据

us1 = User(name='wang',email='[email protected]',password='123456',role_id=ro1.id)
us2 = User(name='zhang',email='[email protected]',password='201512',role_id=ro2.id)
us3 = User(name='chen',email='[email protected]',password='987654',role_id=ro2.id)
us4 = User(name='zhou',email='[email protected]',password='456789',role_id=ro1.id)
us5 = User(name='tang',email='[email protected]',password='158104',role_id=ro2.id)
us6 = User(name='wu',email='[email protected]',password='5623514',role_id=ro2.id)
us7 = User(name='qian',email='[email protected]',password='1543567',role_id=ro1.id)
us8 = User(name='liu',email='[email protected]',password='867322',role_id=ro1.id)
us9 = User(name='li',email='[email protected]',password='4526342',role_id=ro2.id)
us10 = User(name='sun',email='[email protected]',password='235523',role_id=ro2.id)
db.session.add_all([us1,us2,us3,us4,us5,us6,us7,us8,us9,us10])
db.session.commit()


"""
查询所有用户数据
查询有多少个用户
查询第1个用户
查询id为4的用户[3种方式]
查询名字结尾字符为g的所有数据[开始/包含]
查询名字不等于wang的所有数据[2种方式]
查询名字和邮箱都以 li 开头的所有数据[2种方式]
查询password是 `123456` 或者 `email` 以 `itheima.com` 结尾的所有数据
查询id为 [1, 3, 5, 7, 9] 的用户列表
查询name为liu的角色数据
查询所有用户数据,并以邮箱排序
每页3个,查询第2页的数据
"""

查询:filter_by精确查询

返回名字等于wang的所有人

User.query.filter_by(name='wang').all()

过滤名字

first()返回查询到的第一个对象

User.query.first()

all()返回查询到的所有对象

User.query.all()

查询所有对象

filter模糊查询,返回名字结尾字符为g的所有数据。

User.query.filter(User.name.endswith('g')).all()

模糊查询

get():参数为主键,如果主键不存在没有返回内容

User.query.get()

逻辑非,返回名字不等于wang的所有数据

User.query.filter(User.name!='wang').all()

逻辑非

not_ 相当于取反

from sqlalchemy import not_
User.query.filter(not_(User.name=='chen')).all()

取反

逻辑与,需要导入and,返回and()条件满足的所有数据

from sqlalchemy import and_
User.query.filter(and_(User.name!='wang',User.email.endswith('163.com'))).all()

逻辑与

逻辑或,需要导入or_

from sqlalchemy import or_
User.query.filter(or_(User.name!='wang',User.email.endswith('163.com'))).all()

逻辑或

查询数据后删除

user = User.query.first()
db.session.delete(user)
db.session.commit()
User.query.all()

更新数据

user = User.query.first()
user.name = 'dong'
db.session.commit()
User.query.first()

更新数据

关联查询示例:

角色和用户的关系是一对多的关系,一个角色可以有多个用户,一个用户只能属于一个角色。

  • 查询角色的所有用户
  
  
#查询roles表id为1的角色
  
  
ro1 = Role.query.get(1)
  
  
#查询该角色的所有用户
  
  
ro1.us.all()

查询角色的所有用户

  • 查询用户所属角色
  
  
#查询users表id为3的用户
  
  
us1 = User.query.get(3)
  
  
#查询用户属于什么角色
  
  
us1.role

查询用户所属角色

综合案例-图书管理

  • WTF表单
  • 数据库操作
  • 一对多关系演练

定义模型

模型表示程序使用的数据实体,在Flask-SQLAlchemy中,模型一般是Python类,继承自db.Model,db是SQLAlchemy类的实例,代表程序使用的数据库。

类中的属性对应数据库表中的列。id为主键,是由Flask-SQLAlchemy管理。db.Column类构造函数的第一个参数是数据库列和模型属性类型。

注:如果没有在创建数据库的时候指定编码的话,向数据库中插入中文后,会报错,那么需要修改数据库的编码集:

alter database 数据库名 CHARACTER SET utf8

如下示例:定义了两个模型类,作者和书名。

  
  
#coding=utf-8
  
  
from flask import Flask,render_template,redirect,url_for
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)

  
  
#设置连接数据
  
  
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:[email protected]:3306/test2'

app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True

  
  
#实例化SQLAlchemy对象
  
  
db = SQLAlchemy(app)

  
  
#定义模型类-作者
  
  
class Author(db.Model):
    __tablename__ = 'author'
    id = db.Column(db.Integer,primary_key=True)
    name = db.Column(db.String(32),unique=True
    au_book = db.relationship('Book',backref='author')
    def __repr__(self):
        return 'Author:%s' %self.name

  
  
#定义模型类-书名
  
  
class Book(db.Model):
    __tablename__ = 'books'
    id = db.Column(db.Integer,primary_key=True)
    name = db.Column(db.String(32))
    au_book = db.Column(db.Integer,db.ForeignKey('author.id'))
    def __str__(self):
        return 'Book:%s,%s'%(self.info,self.lead)

创建表

if __name__ == '__main__':
    db.drop_all()
    db.create_all()
    app.run(debug=True)
  • 查看创建结果
show tables;

创建表

查看author表结构

desc author;

author表结构

查看books表结构

desc books;

books表结构

添加测试数据

  
  
#生成数据
  
  
au1 = Author(name='老王')
au2 = Author(name='老尹')
au3 = Author(name='老刘')
  
  
# 把数据提交给用户会话
  
  
db.session.add_all([au1, au2, au3])
  
  
# 提交会话
  
  
db.session.commit()
bk1 = Book(name='老王回忆录', author_id=au1.id)
bk2 = Book(name='我读书少,你别骗我', author_id=au1.id)
bk3 = Book(name='如何才能让自己更骚', author_id=au2.id)
bk4 = Book(name='怎样征服美丽少女', author_id=au3.id)
bk5 = Book(name='如何征服英俊少男', author_id=au3.id)
  
  
# 把数据提交给用户会话
  
  
db.session.add_all([bk1, bk2, bk3, bk4, bk5])
  
  
# 提交会话
  
  
db.session.commit()

生成数据后,查看数据:

生成数据

数据显示&表单添加

数据显示

  • 定义路由函数,并将 Author 和 Book 的所有结果传到模板
@app.route('/',methods=['GET','POST'])
def index():
    author = Author.query.all()
    book = Book.query.all()
    return render_template('index.html',author=author,book=book)
  • 模版关键代码
<ul>
    {% for x in author %}
    <li>{{ x }}</li>
    {% endfor %}
</ul>
<hr>
<ul>
    {% for x in book %}
    <li>{{ x }}</li>
    {% endfor %}
</ul>
  • 效果图

表单添加

  • 定义表单类
from flask_wtf import FlaskForm
from wtforms.validators import DataRequired
from wtforms import StringField,SubmitField
  
  
#创建表单类,用来添加信息
  
  
class Append(FlaskForm):
    au_info = StringField(validators=[DataRequired()])
    bk_info = StringField(validators=[DataRequired()])
    submit = SubmitField(u'添加')
  • 传入至模版中
  
  
#创建表单对象
  
  
@app.route('/',methods=['GET','POST'])
def index():
    author = Author.query.all()
    book = Book.query.all()
    form = Append()
    return render_template('index.html',author=author,book=book,form=form)
  • 模板中代码
<form method="post">
    {{ form.csrf_token }}
    <p>作者:{{ form.au_info }}</p>
    <p>书名:{{ form.bk_info }}</p>
    <p>{{ form.submit }}</p>
</form>
  • 效果图

表单验证

@app.route('/', methods=['get', 'post'])
def index():
    append_form = Append()

    if request.method == 'POST':
        if append_form.validate_on_submit():
            author_name = append_form.au_info.data
            book_name = append_form.bk_info.data
            # 判断数据是否存在
            author = Author.query.filter_by(name=author_name).first()
            if not author:
                try:
                    # 先添加作者
                    author = Author(name=author_name)
                    db.session.add(author)
                    db.session.commit()
                    # 再添加书籍
                    book = Book(name=book_name, author_id=author.id)
                    db.session.add(book)
                    db.session.commit()
                except Exception as e:
                    db.session.rollback()
                    print e
                    flash("数据添加错误")
            else:
                book_names = [book.name for book in author.books]
                if book_name in book_names:
                    flash('该作者已存在相同的书名')
                else:
                    try:
                        book = Book(name=book_name, author_id=author.id)
                        db.session.add(book)
                        db.session.commit()
                    except Exception as e:
                        db.session.rollback()
                        print e
                        flash('数据添加错误')
        else:
            flash('数据输入有问题')

    authors = Author.query.all()
    books = Book.query.all()
    return render_template('test2.html', authors=authors, books=books, append_form=append_form)
  • 重新编写html文件展示列表书籍
<h2>书籍列表</h2>
<ul>
{% for author in authors %}
    <li>
        {{ author.name }}
        <ul>
            {% for book in author.books %}
                <li>{{ book.name }}
            {% else %}
                    <li>无书籍</li>
            {% endfor %}
        </ul>

    </li>
{% endfor %}
</ul>
  • 在form标签下添加 flash 消息的显示
{% for message in get_flashed_messages() %}
{{ message }}
{% endfor %}

删除数据

  • 定义删除author和book的路由
  
  
# 删除作者
  
  
@app.route('/delete_author/<int:author_id>')
def delete_author(author_id):
    author = Author.query.get(author_id)
    if not author:
        flash('数据不存在')
    else:
        try:
            Book.query.filter_by(author_id=author_id).delete()
            db.session.delete(author)
            db.session.commit()
        except Exception as e:
            db.session.rollback()
            print e
            flash('操作数据库失败')

    return redirect(url_for('index'))


  
  
# 删除书籍
  
  
@app.route('/delete_book/<int:book_id>')
def delete_book(book_id):
    book = Book.query.get(book_id)
    if not book:
        flash('数据不存在')
    else:
        try:
            db.session.delete(book)
            db.session.commit()
        except Exception as e:
            db.session.rollback()
            print e
            flash('操作数据库失败')

    return redirect(url_for('index'))
  • 在模版中添加删除的 a 标签链接
<h2>书籍列表</h2>
<ul>
{% for author in authors %}
    <li>
        {{ author.name }} <a rel="nofollow" href="/delete_author/{{ author.id }}">删除</a>
        <ul>
            {% for book in author.books %}
                <li>{{ book.name }} <a rel="nofollow" href="/delete_book/{{ book.id }}">删除</a></li>
            {% else %}
                    <li>无书籍</li>
            {% endfor %}
        </ul>

    </li>
{% endfor %}
</ul>

未完待续, 同学们请等待下一期

感兴趣的小伙伴可以自取哦,欢迎大家点赞转发~

标签:md,name,author,Flask,db,表单,User,查询,id
From: https://blog.51cto.com/u_13578013/8587792

相关文章

  • Flask SocketIO 实现动态绘图
    Flask-SocketIO是基于Flask的一个扩展,用于简化在Flask应用中集成WebSocket功能。WebSocket是一种在客户端和服务器之间实现实时双向通信的协议,常用于实现实时性要求较高的应用,如聊天应用、实时通知等,使得开发者可以更轻松地构建实时性要求较高的应用。通过定义事件处理函......
  • 【Python进阶】第6篇:Python的死锁和IP地址详解。总结md文档集合(已分享,附代码)
    本文从14大模块展示了python高级用的应用。分别有Linux命令,多任务编程、网络编程、Http协议和静态Web编程、html+css、JavaScript、jQuery、MySql数据库的各种用法、python的闭包和装饰器、mini-web框架、正则表达式等相关文章的详细讲述。全套笔记和代码自取地址:请移步这里感......
  • MDM介绍:1. 如何有效管理苹果设备
    由于macOS和iOS的显著优点,苹果设备越来越多的被企业、政府和教育等机构使用,那么如何有效的解决管理过程中遇到的一些问题呢?比如,如何将不同的应用安装到有需要的用户电脑,如何确保设备的使用符合制定的策略,如何防止机密信息的泄露,如何进行远程控制等等,诸如此类的问题在实际......
  • 助力企业实现更简单的数据库管理,ATOMDB 与 TDengine 完成兼容性互认
    为加速数字化转型进程,当下越来越多的企业开始进行新一轮数据架构改造升级。在此过程中,全平台数据库管理客户端提供了一个集中管理和操作数据库的工具,提高了数据库管理的效率和便利性,减少了人工操作的复杂性和错误率,让企业可以轻松地管理和维护数据库,执行各种数据库操作,并监控和优化......
  • 打造有效安全闭环,天翼云MDR来了!
    随着网络攻-防对抗形势愈演愈烈,传统的安全防护模式已难以应对频率暴增、昼夜不停的网络安全攻-击,提升组织安全防护能力势在必行。事实上,一些单位在网络安全建设工作中经验不足,在安全组件/设备采购方面大量投入,部署后却缺乏专人运营。这导致在安全事件发生时,组织不能及时发现并进行......
  • nohup ./ReverseProxy_linux_amd64 &
    IDEA安装JRebel插件实现热部署(无激活码,需要一台服务器)JRebel是一款JAVA虚拟机插件,它使得JAVA程序员能在不进行重部署的情况下,即时看到代码的改变对一个应用程序带来的影响。JRebel是一款JVM插件,它使得Java代码修改后不用重启系统,立即生效。1.IDEA搜索并安装Jrebel插件 安装......
  • MD5加密算法
    MD5MD5是一种不可逆的加密算法。可以产生出一个128位(16字节)的散列值(hashvalue),用于确保信息传输完整一致md5的特性压缩性:任意长度的数据,算出的MD5值长度都是固定的。容易计算:从原数据计算出MD5值很容易。抗修改性:对原数据进行任何改动,哪怕只修改1个字节,所得到的MD5值都......
  • Flask 实现Token认证机制
    在Flask框架中,实现Token认证机制并不是一件复杂的事情。除了使用官方提供的flask_httpauth模块或者第三方模块flask-jwt,我们还可以考虑自己实现一个简易版的Token认证工具。自定义Token认证机制的本质是生成一个令牌(Token),并在用户每次请求时验证这个令牌的有效性。整个过程可以分......
  • Flask Session 登录认证模块
    Flask框架提供了强大的Session模块组件,为Web应用实现用户注册与登录系统提供了方便的机制。结合Flask-WTF表单组件,我们能够轻松地设计出用户友好且具备美观界面的注册和登录页面,使这一功能能够直接应用到我们的项目中。本文将深入探讨如何通过Flask和Flask-WTF构建一个......
  • flask学习03-RESTful风格用户注册及登录接口开发
    一、注册接口classRegister(Resource):defpost(self):data=request.get_json()#request.json()获取到请求的参数,得到一个字典对象#print(f'请求入参:{data}')username=data.get("username")password=data.get("password")......