day053 Flask_模板,数据库

当前看来Flask要比Django灵活简单许多,但是要学好,学精还是要多看,多练。

今天主要学的内容有:

  • Flask特有的变量和函数
  • WTF
  • 数据库的配置
  • 模型类
  • 数据库的增删改
  • 数据库的查询

Flask特有的变量和函数

  • 在模板中可以调用一些请求过程中生成的特有的变量和函数
  • 它们分别是:
    • config对象:存储应用的配置信息的。可以直接用‘.’调用某个数据
    • request对象:存储请求客户端的信息。可以用‘.’直接调用某个数据
    • g 变量:是临时请求过程中可以临时生成临时使用的全局变量,能够在一次请求中在各个函数之间传递值
    • url_for 方法:返回视图函数的url.传入函数名,调用这个函数的url,也可以传参数
    • get_flashed_messages 方法:消费存储的闪现数据。先在视图函数里进行数据的闪现操作(使用flash方法),然后在模板中一次性的消费掉
    • session 对象:存储用户数据。先在视图函数中设置,再在模板中使用。
 {#1:config#}
{{ config.DEBUG }}<br>
{{ config.root_path }}<br>
<hr>

{#2:request#}
{{ request.url }}<br>
{{ request.args }}<br>
<hr>

{#3:g变量#}
{#如果想访问,需要提前在一个请求中的任意一个函数中先设置#}
{{ g.name }}
<hr>

{#4:session#}
{#如果想要访问session中的值,需要先在函数中给session赋值#}
{{ session['name'] }}
<hr>

{#5:url_for#}
<a href="{{ url_for('demo_url_for',user_id='666') }}">链接地址</a>
<hr>

{#5:get_flashed_messages#}
{# 需要配合flash方法一起使用。先在函数里调用flash(‘需要闪现的数据’)调用一次,存储一次,然后在模板里使用
get_flashed_messages一次性调用完,注意flash存储的数据只能被get_flashed_massages消费一次#}
{% for message in get_flashed_messages() %}
    {{ message }}
{% endfor %} 

结果:

这里写图片描述

WTF(理解)

  • 一般的表单编写是前端在html文件中编写,如:
<form method="post">
    <label>用户名:</label><input type="text" name="username" placeholder="请输入用户名"><br>
    <label>密码:</label><input type="password" name="password" placeholder="请输入密码"><br>
    <label>确认密码:</label><input type="password" name="password2" placeholder="请再次输入密码"><br>
    <input type="submit" value="提交"><br>
    {% for message in get_flashed_messages() %}
        {{ message }}
    {% endfor %}
</form>
  • 在视图表单中获取表单数据
from flask import Flask,render_template,request

app.secret_key = 'heima'

@app.route('/', methods=['GET', 'POST'])
def hello_world():

    # 1. 判断请求方式是post
    if request.method == 'POST':

        # 2. 获取参数, 并效验参数完整性, 如果有问题就进行flash
        username = request.form.get('username')
        password = request.form.get('password')
        password2 = request.form.get('password2')
        if not all([username, password, password2]):
            flash('params error')

        # 3. 效验密码
        elif password != password2:
            flash('password error')

        # 4. 没有问题就返回'success'
        else:
            print username
            return 'success'

    return render_template('wtf.html')
  • 使用 flask-WTFT拓展,可以在视图函数中定义表单类,在html文件中实例化得到
  • 好处是:
    • html中会有更少的代码
    • 在获取表单的post请求时,只需要使用validate_on_submit()一步验证即可,而普通的验证需要很多步。

html文件中代码

<form method="post">
    {#设置csrf_token#}
    {{ form.csrf_token() }}
    {{ form.username.label }}{{ form.username }}<br>
    {{ form.password.label }}{{ form.password }}<br>
    {{ form.password2.label }}{{ form.password2 }}<br>
    {{ form.input }}<br>
</form>

视图函数文件

#coding=utf-8
from flask import Flask, render_template, request, flash

#导入wtf扩展的表单类
from flask_wtf import FlaskForm

#导入自定义表单需要的字段
from wtforms import SubmitField,StringField,PasswordField

#导入wtf扩展提供的表单验证器
from wtforms.validators import DataRequired,EqualTo

# 解决编码问题
import sys
reload(sys)
sys.setdefaultencoding("utf-8")

app = Flask(__name__)
app.config['SECRET_KEY']='heima'

#自定义表单类,文本字段、密码字段、提交按钮
# 需要自定义一个表单类
class RegisterForm(FlaskForm):
    username = StringField('用户名:', validators=[DataRequired()], render_kw={'placeholder': '请输入用户名'})
    password = PasswordField('密码:', validators=[DataRequired()])
    password2 = PasswordField('确认密码:', validators=[DataRequired(), EqualTo('password', '密码输入不一致')])
    input = SubmitField('提交')

#定义根路由视图函数,生成表单对象,获取表单数据,进行表单数据验证
@app.route('/form', methods=['GET', 'POST'])
def form():
    register_form = RegisterForm()

    if request.method == 'POST':
        # 调用validate_on_submit方法, 可以一次性执行完所有的验证函数的逻辑
        if register_form.validate_on_submit():
            # 进入这里就表示所有的逻辑都验证成功
            username = request.form.get('username')
            password = request.form.get('password')
            password2 = request.form.get('password2')
            print username
            return 'success'

        else:
            #message = register_form.errors.get('password2')[0]
            #flash(message)
            flash('参数有误')

    return render_template('wtf.html', form=register_form)

数据库的配置

  • 在Flask框架中使用的数据库,既有关系型数据库-MySQL,也有非关系数据库,redis,mongoDB

Flask-SQLAlchemy扩展

  • SQLALchemy实际上是对数据库的抽象,类似于Django的ORM,通过创建类和对象对数据库进行操作
  • Flask-sqlalchemy是一个简化了SQLALchemy操作的flask拓展

数据库配置步骤

  1. 安装flask_sqlalchemy
    pip install flask-sqlalchemy
  2. 连接的是MySQL,需要安装Mysqldb
    pip install flask-mysqldb
  3. 更改app的config参数,关联app和mysql数据库
    app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:[email protected]:3306/test'
    app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
  4. 导入flask_sqlalchemy 包的SQLAlchemy类
    from flask_sqlalchemy import SQLAlchemy
  5. 将创建的app与SQLAlchemy关联起来
    db = SQLAlchemy(app)
  6. 在终端登录mysql数据库,创建一个新的数据库 test
    create database test charset=utf8

模型类

  • 用定义类的方式创建数据库表结构

常用的SQLAlchemy字段类型

这里写图片描述

常用的SQLAlchemy列选项

这里写图片描述

常用的SQLAlchemy关系选项

这里写图片描述

  • 需求:创建一个角色表 roles,有字段id和name,创建一个用户表users,有字段id,name,和role_id,roles表和users表是一对多的关联关系
# user表
class Users(db.Model):
    # 定义表名
    __tablename__ = 'users'
    # 定义字段
    id = db.Column(db.Integer, primary_key =True)
    name = db.Column(db.String(16), unique =True )
    role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))
    # user 想创建一个与Roles表的关联,这个属性需要在另一个表中用backref创建

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

# roles表
class Roles(db.Model):
    # 定义表名
    __tablename__ = 'roles'
    # 定义字段
    id = db.Column(db.Integer, primary_key = True)
    name = db.Column(db.String(16), unique = True)

    # 在1的一方,写关联
    # backref=“roles”表示创建了一个给Users表使用的属性roles
    users = db.relationship('Users', backref='role')

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

数据库的增删改

  • 在Flask-SQLAlchemy中,增,删,改操作,均有数据路会话(session)管理。
    • 会话用db.session表示。在准备把数据写入到数据库之前,要先将数据添加到会话中(db.session.add()),再调用db.session.commit()方法提交会话。
db.session.add(role) # 将role添加到session中
db.session.add_all([user1, user2]) # 添加多个user到session中
db.session.commit() # 提交数据库的修改(增,删,改),一旦执行此操作,数据就会真正的写到数据库中
db.session。rollback() # 数据库回滚操作,可以回滚到上次conmmit之后的一步操作
db.session.delete(user) # 删除数据库,需要跟上commit命令
  • 执行步骤
  • 需求:
    • 增加2条roles表数据:role1 :1 admin; role2:2 user
    • 增加2条users表数据: user1:1 zs 1; user2: 2 ls 2
    • 将user2的role_id改为1
    • 查询user1对应的角色
    • 查询role1对应的用户
    • 删除user1
In [1]: from day03 import *

# 在roles表中添加2个角色 admin,user
In [3]: role1 = Roles(name = 'admin')
In [4]: db.session.add(role)
In [5]: db.session.commit()
In [6]: role2 = Roles(name = 'user')
In [7]: db.session.add(role2)
In [8]: db.session.commit()

# 在users表中添加两个用户 zs,ls
In [9]: user1 = Users(name = 'zs', role_id = role1.id)
In [10]: user2 = Users(name = 'ls', role_id = role2.id)
In [11]: db.session.add_all([user1, user2])
In [12]: db.session.commit()

# 将user2的role_id改为1
In [13]: user2.role_id = role1.id
In [14]: db.session.commit()

# 查看user1的角色的名字
In [16]: user1.role.name
Out[16]: u'admin'

# 查看role1的用户有哪些
In [18]: role.users
Out[20]: [<Users:zs 1>, <Users:ls 2>]

# 删除user1
In [21]: db.session.delete(user1)
In [22]: db.session.commit()

数据库的查询

  • 数据库的查询是对已有数据进行有条件的查找返回查询结果或者对查询的结果进行计算,处理后返回结果的过程

常用的SQLAlchemy查询过滤器

这里写图片描述

常用的SQLAlchemy查询执行器

这里写图片描述

  • 需求:

    1. 查询所有用户数据
    2. 查询有多少个用户
    3. 查询第1个用户
    4. 查询id为4的用户[3种方式]
    5. 查询名字结尾字符为g的所有数据[开始/包含]
    6. 查询名字不等于wang的所有数据[2种方式]
    7. 查询名字和邮箱都以 li 开头的所有数据[2种方式]
    8. 查询password是 123456 或者 emailitheima.com 结尾的所有数据
    9. 查询id为 [1, 3, 5, 7, 9] 的用户列表
    10. 查询name为liu的角色数据
    11. 查询所有用户数据,并以邮箱排序
    12. 查询第2页的数据, 每页只显示3条数据
  • 首先将数据准备好并且导入到数据库

1. 查询所有用户数据
# all()返回查询到的所有对象
User.query.all()

2. 查询有多少个用户
User.query.count()

3. 查询第1个用户
User.query.first()

4. 查询id为4的用户[3种方式]
# filter_by直接用属性名,比较用=, filter用类名.属性名,比较用==
# filter_by用于查询简单的列名,不支持比较运算符
# filter比filter_by的功能更强大,支持比较运算符,支持or_、in_等语法。
User.query.get(4)
User.query.filter_by(id=4).first()  #属性 =
User.query.filter(User.id==4).first() #对象名.属性 ==
User.query.filter_by(id=4).first()  #属性 =


5. 查询名字结尾字符为g的所有数据[开始/包含]
User.query.filter(User.name.endswith('g')).all() 
# filter 
# 可以再输入的时候使用tab来提示或不全代码 
# endswith: 需要使用括号来出传入数据

6. 查询名字不等于wang的所有数据[2种方式]
User.query.filter(User.name!='wang').all()
In [11]: from sqlalchemy import not_
In [12]: User.query.filter(not_(User.name=='wang')).all()


7. 查询名字和邮箱都以 li 开头的所有数据[2种方式]
In [13]: from sqlalchemy import and_
In [14]: User.query.filter(and_(User.name.startswith('li'),User.email.startswith('li'))).all()
User.query.filter(User.name.startswith('li'),User.email.startswith('li')).all()

8. 查询password是 `123456` 或者 `email` 以 `itheima.com` 结尾的所有数据
User.query.filter(or_(User.password=='123456', User.email.endswith('itheima.com'))).all()

9. 查询id为 [1, 3, 5, 7, 9] 的用户列表
User.query.filter(User.id.in_([1, 3, 5, 7, 9])).all()

10. 查询name为liu的角色数据
User.query.filter(User.name=='liu').first().role

11. 查询所有用户数据,并以邮箱排序
User.query.order_by(User.email).all()

12. 查询第2页的数据, 每页只显示3条数据
help(User.query.paginate)
# paginate 三个参数: 查询的页码, 分页的个数, 查询出错是否需要返回错误
result = User.query.paginate(2, 3, False)
# 获取查询的结果. items
result.items
# 获取总页数
result.pages
# 获取当前页面
result.page

猜你喜欢

转载自blog.csdn.net/michael_cool/article/details/79674332