Flask框架二

一 flask-wtf表单处理

1. 为什么使用Flask-WTF?

request对象公开了所有客户端发送的请求信息。特别是request.form可以访问POST请求提交的表单数据。
尽管Flask的request对象提供的支持足以处理web表单,但依然有许多任务会变得单调且重复。
表单的HTML代码生成和验证提交的表单数据就是两个很好的例子。
优势:
Flask-WTF扩展使得处理web表单能获得更愉快的体验。该扩展是一个封装了与框架无关的WTForms包的Flask集成。

2. 什么是表单处理?

在网页中,为了和用户进行信息交互总是不得不出现一些表单。 flask设计了WTForm表单库来使flask可以更加简便地管理操作表单数据。
WTForm中最重要的几个概念如下

  • Form类,开发者自定义的表单必须继承自Form类或者其子类。
    Form类最主要的功能是通过其所包含的Field类提供对表单内数据的快捷访问方式。

  • 各种Field类,即字段。一般而言每个Field类都对应一个input的HTML标签。
    比如WTForm自带的一些Field类比如BooleanField就对应input type=“checkbox”>,
    SubmitField就对应input type=“submit”>等等。

  • Validator类。这个类用于验证用户输入的数据的合法性。
    比如Length验证器可以用于验证输入数据的长度,FileAllowed验证上传文件的类型

另外,flask为了防范csfr(cross-site request forgery)攻击,默认在使用flask-wtf之前要求app一定要设置过secret_key。最简单地可以通过app.config[‘SECRET_KEY’] = 'xxxx’来配置。

3. 常见的Field类

在这里插入图片描述

4.Validator是验证函数:

Validator是验证函数,把一个字段绑定某个验证函数之后,flask会在接收表单中的数据之前对数据做一个验证
如果验证成功才会接收数据。验证函数Validator如下,具体的validator可能需要的参数不太一样,这里只给出一些常用的
*基本上每一个validator都有message参数,指出当输入数据不符合validator要求时显示什么信息。

在这里插入图片描述

应用

上述提及了表单类型(StringField、 PasswordField、 SubmitField、 FileField )
用来验证的表单有(DataRequired、Length、 Email、 Regexp、 EqualTo)

详解如下:
在创建一个新的项目的时候,通常会有一些行业内通俗的模块与包的名字,比如static(放置静态文件:css样式,js样式等)、templatems(放置html文件)等
而整个项目中除了主函数(run.py)外,还会有一些其他文件,forms.py 就是放置 flask_wtf 表单处理的文件,关于表单处理的要求,会被写在这个文件下,当然还会有其它的文件,下面会有提及

首先,要做的就是安装 flask_wtf 这个库

pip install flask-WTF

注意:这里在安装的时候是 -WTF ,并不是 _wtf ,但是在应用的时候,却是后者

导入一些常用的表单类型,相当于input标签中type的作用

from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField, FileField

导入一些常用的验证表单,用来确保表单内容是否合法

from wtforms.validators import DataRequired, Length, Email, Regexp, EqualTo

这里写一个用户登陆和注册时的案例,flask_wtf的作用就是用来限制登陆和注册时的信息

from flask_wtf import FlaskForm
# 确定表单的类型, 相当于input标签中type的作用
from wtforms import StringField, PasswordField, SubmitField, FileField
# 确保表单内容是否合法;
from wtforms.validators import DataRequired, Length, Email, Regexp, EqualTo


# Regexp == regular experssion (用于编写正则表达式的)
class LoginForm(FlaskForm):
    user = StringField(
        label="用户名/手机/邮箱",
        validators=[
            DataRequired(message="用户名不能为空"),
            Length(5, 12),
        ]
    )
    passwd = PasswordField(
        label="密码",
        validators=[
            Length(6)
        ]
    )
    submit = SubmitField(
        label="登录"

    )


class RegisterForm(FlaskForm):
    user = StringField(
        label="用户名/手机/邮箱",
        validators=[
            Length(5, 12),
        ]
    )
    email = StringField(
        label="邮箱",
        validators=[
            Email("邮箱格式不正确!")
        ]
    )
    phone = StringField(
        label="电话",
        validators=[
            Regexp(r'1\d{10}', message="手机格式不正确!")
        ]
    )
    passwd = PasswordField(
        label="密码",
        validators=[
            Length(6)
        ]
    )

    repasswd =  PasswordField(
        label="确认密码",
        validators=[
          EqualTo('passwd', "两次密码不一致!")
        ]

    )

    submit = SubmitField(
        label="注册"

    )

上面的代码,需要注意的一点就是:

lable:(是用来对要填写内容的提示)
validators:(是用来对要填写内容的限制)

有时候在用户注册的时候,会被要求上传图像,这里就有不同的地方了

face = FileField(
        label="上传头像",
        validators=[
            FileAllowed(['png', 'jpg'], message="文件非图片")
        ]
    )

validators 中的 FileAllowed 是从from flask_wtf.file import FileAllowed这里导出的

三 flask_bootstrap网页编写

flask_bootstrap 是用来编写html文件的基模版
其中bootstrap下面有 base.html 这样的基模版,当然,你也可以自己编写模版

1. 如何在flask中使用Boostrap?

要想在程序中集成Bootstrap,显然要对模板做所有必要的改动。不过,更简单的方法是使用一个名为Flask-Bootstrap 的Flask 扩展,简化集成的过程。安装:

pip install flask_bootstrap
2. Flask 扩展一般都在创建程序实例时初始化,下面是Flask_Bootstrap的初始化方法:
from flask_bootstrap import  Bootstrap

app = Flask(__name__)
bootstrap = Bootstrap(app)

初始化Flask-Bootstrap 之后,就可以在程序中使用一个包含所有Bootstrap 文件的基模板。这个模板利用Jinja2 的模板继承机制,让程序扩展一个具有基本页面结构的基模板,其中就有用来引入Bootstrap 的元素。

3. 如何引用bootatrap的基模板?
{%extends "bootstrap/base.html"%}

{%block title %}Flask{% endblock %}

这两个块分别表示页面中的导航条和主体内容。在这个模板中,navbar 块使用Bootstrap 组件定义了一个简单的导航条。content 块中有个div> 容器,其中包含一个页面头部

4. Flask-Bootstrap定义的其他可用块:

参考链接: https://pythonhosted.org/Flask-Bootstrap/basic-usage.html#available-blocks

在这里插入图片描述

5.如何继承原有内容:

上表中的很多块都是Flask-Bootstrap 自用的,如果直接重定义可能会导致一些问题。例如,Bootstrap 所需的文件在styles 和scripts 块中声明。如果程序需要向已经有内容的块中添加新内容,必须使用Jinja2 提供的super() 函数。例如,如果要在衍生模板中添加新的JavaScript 文件,需要这么定义scripts 块:

{% block scripts %}
{{ super() }}
<script type="text/javascript" src="my-script.js"></script>
{% endblock %}

四 flask_sqlalchemy

flask_sqlalchemy为 Flask 提供了一个 SQLAlchemy 扩展,用来处理数据库的操作

常见情况下对于只有一个 Flask 应用,所有需要做的事情就是创建 Flask 应用,选择加载配置接着创建 SQLAlchemy 对象时候把 Flask 应用传递给它作为参数,一旦创建,这个对象就包含 sqlalchemy 和 sqlalchemy.orm 中的所有函数和助手。此外它还提供一个名为 Model 的类,用于作为声明模型时的 delarative 基类

# 关于数据库操作的文件
from flask_sqlalchemy import  SQLAlchemy
from flask import  Flask
from sqlalchemy import desc
app = Flask(__name__)

#Flask-SQLAlchemy 中存在的配置值
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:redhat@localhost/User'
# SQLAlchemy 将会追踪对象的修改并且发送信号。
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
db = SQLAlchemy(app)

配置键说明:
在这里插入图片描述
注意:Python2 中的 MySQLdb 。mysql://username:password@server/db
Python3 中的 pymysql ,mysql+pymysql://username:password@server/db
这样才是完整连接 URI 格式,才会连接上Python3中使用的数据库

1.简单示例
通常下,Flask-SQLAlchemy 的行为就像一个来自 declarative 扩展配置正确的 declarative 基类;你的所有模型的基类叫做 db.Model。它存储在你必须创建的 SQLAlchemy 实例上

class Student(db.Model):
    __tablename__ = "students"
    #db.SMALLINT代表存储的数据类型,primary_key(主键),数据是唯一的;
    id = db.Column(db.SMALLINT, primary_key=True)
    username = db.Column(db.String(50))
    email = db.Column(db.SMALLINT)
    
	def __repr__(self):
        return '<User %r>' % self.username

1)默认情况下创建一个表,表名为类名; 如果指定了__tablename__, 那么表名为指定的名称
2)用 Column 来定义一列。列名就是赋值给那个变量的名称。如果想要在表中使用不同的名称,可以提供一个想要的列名的字符串作为可选第一个参数
3)列的类型是 Column 的第一个参数。可以直接提供它们或进一步规定(比如提供一个长度)。下面的类型是最常用的:
在这里插入图片描述
sqlalchemy支持的字段限制:
在这里插入图片描述
2.一对多关系
一对多的简单示例:

class Person(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(50))
    addresses = db.relationship('Address', backref='person')
                               

class Address(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    email = db.Column(db.String(50))
    person_id = db.Column(db.Integer, db.ForeignKey('person.id'))

其中:
1). 一对一端需要写反向引用:关系使用 relationship() 函数表示
2). 多对一端需要写外键:必须用类 sqlalchemy.schema.ForeignKey 来单独声明

另外注意:

db.drop_all()
    # 1. 创建定义的表结构
    db.create_all()
    # 2. 删除定义的表结构
    # db.drop_all()

3.数据库的增删改查
运用上面提到的点,创建了一个数据库(User),然后再在库上建立数据

from datetime import datetime
import  time
import pymysql
# 关于数据库操作的文件
from flask_sqlalchemy import  SQLAlchemy
from flask import  Flask
from sqlalchemy import desc
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:redhat@localhost/User'
# SQLAlchemy 将会追踪对象的修改并且发送信号。
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
db = SQLAlchemy(app)

class User(db.Model):
    # autoincrement=True自增
    id = db.Column(db.Integer, autoincrement=True, primary_key=True)
    # unique=True, name的值不能重复,是唯一的;
    name = db.Column(db.String(50), unique=True)
    # 长度为100,是因为网站密码一般会加密;
    passwd = db.Column(db.String(100))
    # 指定用户注册/创建的时间,
    # default, 指定默认值, datetime.now()获取当前时间;
    # 用户注册时间为当前时间;
    add_time = db.Column(db.DateTime, default=datetime.now())
    # 用户的角色id,不能随便写, 必须要关联其他的数据库表(role) --- 外键
    role_id = db.Column(db.INTEGER, db.ForeignKey('role.id'))

    def __repr__(self):
        return '<User:%s>' %(self.name)

# 用户角色表
class Role(db.Model):
    # autoincrement=True自增
    id = db.Column(db.Integer, autoincrement=True, primary_key=True)
    #  unique=True, name的值不能重复, 是唯一的;
    name = db.Column(db.String(50), unique=True)
    #  Role表中的users属性与User表关联, 并且User这个表中可以由role这个对象属性;
    users = db.relationship('User',backref='role')

    # 对象的字符串显示, 方便查询时使用
    def __repr__(self):
        return  "<Role:%s>" %(self.name)

if __name__ == '__main__':
    #创建定义的表结构
    db.create_all()

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
4.增加数据
在查询数据之前我们必须先插入数据。您的所有模型都应该有一个构造函数,如果您忘记了,请确保加上一个。只有您自己使用这些构造函数而 SQLAlchemy 在内部不会使用它, 所以如何定义这些构造函数完全取决您。
向数据库插入数据分为三个步骤:

1.	创建 Python 对象
2.	把它添加到会话
3.	提交会话

这里的会话不是 Flask 的会话,而是 Flask-SQLAlchemy 的会话。它本质上是一个 数据库事务的加强版本它是这样工作的:

1)创建用户角色:

 	role1 = Role(name="超级会员")
    role2 = Role(name="会员")

    db.session.add(role1)
    db.session.add(role2)

    db.session.commit()

在这里插入图片描述

特别强调:

在创建之前,要先创建中文编码格式的库,否则中文无法显示

CREATE DATABASE User CHARACTER SET utf8 COLLATE utf8_general_ci;

2)添加100个用户,其中50个为超级会员, 50个为会员

 	for i in range(50):
        u = User(name='westos%s' %(i), passwd='westos', role_id=1)
        db.session.add(u)
    db.session.commit()

    for i in range(50):
        u = User(name='redhat%s' % (i), passwd='redhat', role_id=2)
        db.session.add(u)
    db.session.commit()

在这里插入图片描述
在这里插入图片描述
3)查询数据
Flask-SQLAlchemy 在您的 Model 类上提供了 query 属性。当您访问它时,您会得到一个新的所有记录的查询对象。在使用 all() 或者 first() 发起查询之前可以使用方法 filter() 来过滤记录。

查询所有数据

 print(Role.query.all())
 print(User.query.all())

在这里插入图片描述
根据条件查询数据(筛选数据(filter_by)); slect * from table where xxx=xxx;

	print(User.query.filter_by(role_id=1).all())
	print(User.query.filter_by(role_id=2).all())

在这里插入图片描述
筛选数据方法2(filter)通过这种方式可以查看原生的sql语句

    user = User.query.filter(User.role_id==1)
    print(user)

在这里插入图片描述
4)对于找到的内容进行更新

	u = User.query.filter_by(name='westos0').first()
    print(u)
    u.passwd = '123456'
    db.session.add(u)
    db.session.commit()

在这里插入图片描述
5)对于查询的信息进行显示限制;

    users = User.query.filter_by(role_id=1).limit(5).all()
    print(users, len(users), end='\n')

在这里插入图片描述
6)对于查询的信息进行排序输出(默认情况由小到大进行排序), 如果想要由大到小: desc(User.add_time)

	users = User.query.filter_by(role_id=1).order_by(desc(User.add_time)).all()
    print(users)

在这里插入图片描述
7)多个过滤函数加一个显示函数

users = User.query.filter_by(role_id=1).order_by(desc(User.add_time)).limit(5).all()
    print(users)
    #offset指定偏移量,limit指定输出数量,类似于切片操作;
    #1 2 3 4 5 6 7 8 9
    #limit(5): 1 2 3 4 5
    #limit(5).offset(2): 3 4 5 6 7
    users = User.query.filter_by(role_id=1).order_by(desc(User.add_time)).limit(5).offset(2).all()
    print(users)
    #切片操作li[2:7]
    users = User.query.filter_by(role_id=1).order_by(desc(User.add_time)).slice(2, 7).all()
    print(users)

    count = User.query.filter_by(role_id=1).order_by(desc(User.add_time)).slice(2, 7).count()
    print(count)

在这里插入图片描述
8)分页:第一个参数代表显示第几页的数据, 第二个参数代表每页显示多少条数据

users = User.query.paginate(1, 5)
    print(users.items)
    users = User.query.paginate(2, 5)
    print(users.items)

在这里插入图片描述
9)反向引用的使用

	u = User.query.filter_by(name='westos0').first()
    print(u.name, u.passwd, u.add_time, u.role_id, u.role, u.role.id, u.role.name)

在这里插入图片描述
删除数据
删除数据与增加数据是十分类似的,使用 delete() 代替 add()

	user=User.query.filter_by(name='redhat0').first()
    db.session.delete(user)
    db.session.commit()

进入user表中查看会发现redhat0被删除

五 查询过滤器总结

在这里插入图片描述

六 执行函数总结

在这里插入图片描述

七 flask_migrate与flask_script

1.flask_migrate

Flask-Migrate是用于处理SQLAlchemy 数据库迁移的扩展工具。当Model出现变更的时候,通过migrate去管理数据库变更
一般分为三步(init、migrate、upgrade)

2.flask_script

Flask_script扩展提供向Flask插入外部脚本的功能,包括运行一个开发用的服务器,一个定制的Python shell,设置数据库的脚本,cronjobs,及其他运行在web应用之外的命令行任务;使得脚本和系统分开;Flask_script和Flask本身的工作方式类似,只需定义和添加从命令行中被Manager实例调用的命令

3.结合的简单使用

需求:现在,在 Role 数据表中需要添加一个新的属性(grace:级别),需要该怎么做,总不能将数据库删了重新建吧。这里就需要用到这两个库了,做数据库的扩展
可以将代码写在 manage 文件下,与 models 文件同级
manage文件就是存放关于数据库扩展的文件
manage.py:

from flask_migrate import  Migrate, MigrateCommand
from flask_script import  Shell, Manager
from models import app, db, User, Role

#用来管理命令的对象, Manager用来跟踪所有名林不过并处理他们如何从命令行调用;
manager = Manager(app)
migrate = Migrate(app, db)

# 添加一条数据库管理的命令
manager.add_command('db', MigrateCommand)

#实现添加用户的命令
if __name__ == "__main__":
    #准备
    manager.run()

在models文件中填写需要添加的属性
models.py:

class Role(db.Model):
    # autoincrement=True自增
    id = db.Column(db.Integer, autoincrement=True, primary_key=True)
    #unique=True, name的值不能重复,是唯一的;
    name = db.Column(db.String(50), unique=True)
    #Role表中的users属性与User表关联,并且User这个表中可以由role这个对象属性
    grace=db.Column(db.SmallInteger)
    users = db.relationship('User',backref='role')

执行manager文件,可看到位置参数
在这里插入图片描述
执行db用来对models中建立的数据库操作

(li) [kiosk@foundation74 详解flask]$ python manage.py db
usage: Perform database migrations

Perform database migrations

positional arguments:
  {init,revision,migrate,edit,merge,upgrade,downgrade,show,history,heads,branches,current,stamp}
    init                Creates a new migration repository
    revision            Create a new revision file.
    migrate             Alias for 'revision --autogenerate'
    edit                Edit current revision.
    merge               Merge two revisions together. Creates a new migration
                        file
    upgrade             Upgrade to a later version
    downgrade           Revert to a previous version
    show                Show the revision denoted by the given symbol.
    history             List changeset scripts in chronological order.
    heads               Show current available heads in the script directory
    branches            Show current branch points
    current             Display the current revision for each database.
    stamp               'stamp' the revision table with the given revision;
                        don't run any migrations

optional arguments:
  -?, --help            show this help message and exit
1.下来就是操作的三部曲

1)init:初始化数据,创建迁移仓库

python manage.py db init

在这里插入图片描述
在这里插入图片描述
创建了一个 migrations 目录,其中 versions 就记录着数据库的变迁
上述在models文件中,给Role数据表添加了一个 grace 属性

2)migrate:增加属性

python manage.py db migrate -m 'Role中添加属性grace'

-m可以指定操作名称
在这里插入图片描述
在这里插入图片描述
3)upgrade:数据库更新此次变化

python manage.py db upgrade

在这里插入图片描述
另外:此库可以返回原先的操作

python manage.py db history

在这里插入图片描述
从历史状态可以看到,对原先的数据库(base),做了更改
退回base状态:

python manage.py db downgrade base

在这里插入图片描述

2.自定义一些操作

使用装饰器来装饰你的函数
1)manager.command

@manager.command
def showUser():
    """显示所有的用户"""
    users = User.query.all()
    print(users[:5])			#太多了,只显示前5个

在这里插入图片描述
可以发现多了一个参数显示所有的用户
执行python manage.py showUser便可以查看前5个用户

2)manager.option
同 command 不同的点在于,此方法可以传递参数
比如说添加一个角色:

@manager.option('-n', '--name', help="角色名称")
def add_role(name):
    try:
        role1 = Role(name=name)
        db.session.add(role1)
        db.session.commit()
    except Exception:
        print("创建用户角色失败!")
    else:
        print("创建用户角色%s成功!" %(name))

第一个为缩写,第二个为全称

python manage.py add_role -n 黄金会员

在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值