分类 Flask 下的文章

01-Flask之基本流程


一、Flask简介

Flask是一个基于python实现的web开发"微"框架。
Flask和Django一样,也是一个基于MVC设计模式的web框架。

官方文档: http://flask.pocoo.org/docs/0.12/
中文文档: http://docs.jinkan.org/docs/flask/

Flask依赖三个库: Jinja2模板引擎、Werkzeug WSGI工具集、Itsdangerous基于Django的签名模块



02-Flask之session&模板&模型


一、session之持久化存储

flask中这些插件几乎并没有干扰到之前的任何逻辑,使用起来非常的方便,就类似于中间件。

flask中session默认存储在内存中;
django中做了持久化,存储在数据库(可以修改到redis中);
flask中没有对默认session进行任何处理;
flask-session 可以实现session的数据持久化;
redis(缓存在磁盘上的时候,管理磁盘文件使用lru, 最近最少使用);
<!--more-->
- flask-session安装
    pip install flask-session

- 需要安装redis
    pip install redis
    
- flask-session的配置(初始化完成后,使用和之前session使用一致)
    # app/__init__.py文件中
    from flask_session import Session
    app.config['SECRET_KEY'] = '123qdqwe123113' # 秘钥
    app.config['SESSION_TYPE'] = 'redis'    # 配置
    sess = Session()    # 实例化session对象
    sess.init_app(app)  # session对象初始化
    
    # 简化操作: sess = Session(app)

- redis连接问题(需要启动)
    redis-server
    
- redis查看值
    # 进入到redis命令行
    redis-cli
    
    # 查看所有的
    keys *
    
    # 获取对应的值
    get xxxx(key)
    
    # 获取时间(session的生命周期,默认31天)
    ttl xxx(key)
    
    # 删除对应的值
    del xxx(key)
    
    # 删除当前所有的
    flushdb
    
- session其他设置(flask-session同样适用)
    PERMANENT_SESSION_LIFETIME 设置超时时间
        app.config['PERMANENT_SESSION_LIFETIME'] = 60
    SESSION_COOKIE_NAME 设置会话cookie的名称
        app.config['SESSION_COOKIE_NAME'] = 'flask'

备注: 如果没有安装redis-server是启动不了的。安装操作: sudo apt install redis-server

二、模板

  • 模板概念
- 模板是呈现给用户的界面

- 在MVT中充当T的角色,实现了VT的解耦

- 模板处理分两个过程
    加载
    渲染
    
- 模板代码包含两部分
    静态HTML
    动态插入的代码
  • Jinja2
- Flask中使用的是Jinja2模板引擎

- Jinja2由Flask作者开发
    现代化设计和友好的python模板语言
    模仿Django的模板引擎
    
- Jinja2官方文档
    http://jinja.pocoo.org/docs/2.10/
    
- 优点
    速度快,被广泛使用
    HTML设计和后端python分离
    减少python复杂度
    非常灵活、快速、安全
    提供了控制,继承等高级功能
  • 模板语法
- 模板语法分两种
    变量
    标签
    
- 模板中的变量 {{ var }}
    视图传递给模板的数据
    前面定义的数据
    变量不存在,默认忽略
    
- 模板中的标签 {% tag %}
    控制逻辑
    使用外部表达式
    创建变量
    宏定义
  • 结构标签 block
语法:
    {% block xxx %}
    {% endblock %}
    
例如:
    {% block extcss %}
    {% endblock %}
    
用途:
    父模板挖坑,子模板填坑(块操作)
  • 静态资源的加载
# 方式一: 直接写
<link rel="stylesheet" href="/static/css/main.css">

# 方式二: 通过反向解析
<link rel="stylesheet" href={{ url_for('static',filename='css/main.css') }}>
  • 结构标签 extends
语法:
    # 模板继承
    {% extends 'xxx' %}
    # 继承后需要保留块中的内容
    {{ super() }}
    
例如:
    {% extends 'base_main.html' %}
    {% block extcss %}
        # 保留父模板中 extcss块 中内容
        {{ super() }}
        # 新添加内容
        <link rel="stylesheet" href={{ url_for('static',filename='css/index.css') }}>
    {% endblock %}
    
用途: 
    模板继承
    挖坑继承体现的是化整为零的操作
  • 结构标签 include
语法:
    {% include 'xxx.html' %}
    
例如:
    {% include 'index_content.html' %}
    
用途:
    包含,将其他html包含进来,体现了由零到一的概念

可以将区块代码抽离到新文件;可以将重复小模块抽取,反复使用。

  • 宏定义 marco
语法:
    {% macro fn(arg) %}
    {% endmacro %}
    
例如(不带参数):
    # 定义
    {% macro say() %}
        <h3>今天高温预警,40℃。</h3>
    {% endmacro %}
    # 调用
    {{ say() }}
    
例如(带参数):
    # 定义
    {% macro create_item(id,name) %}
        <P>
            <i>{{ id }}</i>
            <span>{{ name }}</span>
        </P>
    {% endmacro %}
    # 调用
    {{ create_item(student.id,student.name) }}
    
例如(宏定义可导入from):
    {# appmacro.html文件 #}
    {% macro create_user(name) %}
        <h3>用户: {{ name }}</h3>
    {% endmacro %}
    
    {# 导入 #}
    {% from 'appmacro.html' import create_user %}
    
    {# 调用#}
    {{ create_user('风吹裤裆凉飕飕') }}
    
用途:
    宏定义,可以在模板中定义函数,在其他地方调用

备注: 可以专门创建一个页面来写宏定义,需要就引入即可。

  • 条件控制 if
语法:
    {% if 条件 %}
        代码块
    {% elif 条件 %}
        代码块
    ...
    {% else %}
        代码块
    {% endif %}
例如:
    {% if name and name == 'admin'  %}
        <h1>This is admin console</h1>
    {% elif name %}
        <h1>Welcome {{ name }}!</h1>
    {% else %}
        <h1>Please login</h1>
    {% endif %}
  • 循环控制 for
语法:
    {% for item in items %}
        {{ item }}
    {% endfor %}
    
    {% for item in items %}
        {{ item }}
    {% else %}
        # items为空时调用
    {% endfor %}
    
例如:
    {% for student in students %}
        {% if loop.first %}
            <p style="color: red;">{{ loop.index }}-{{ student.name }}</p>
        {% endif %}

        <p style="color: blue;">{{ loop.index }}-{{ student.name }}</p>

        {% if loop.last %}
            <p style="color: purple;">{{ loop.index }}-{{ student.name }}</p>
        {% endif %}
    {% else %}
        <p>没有数据了</p>
    {% endfor %}
    
其他(loop循环信息):
    loop.index 循环迭代计数(从1开始)
    loop.index0 循环迭代计数(从0开始)
    loop.revindex 循环迭代倒序计数(从len开始,到1结束)
    loop.revindex0 循环迭代倒序计数(从len-1开始,到0结束)
    loop.first 是否为循环的第一个元素
    loop.last 是否为循环的最后一个元素
    loop.length 循环序列中元素的个数
  • 过滤器
语法:
    {{ 变量 | 过滤器 | 过滤器 }}

例如:
    {# 当变量未定义时,显示默认字符串,可以缩写为d #}
    <p>{{ name | default('No name') }}</p>
 
    {# 单词首字母大写 #}
    <p>{{ 'hello' | capitalize }}</p>
 
    {# 单词全小写 #}
    <p>{{ 'XML' | lower }}</p>
 
    {# 去除字符串前后的空白字符 #}
    <p>{{ '  hello  ' | trim }}</p>
 
    {# 字符串反转,返回"olleh" #}
    <p>{{ 'hello' | reverse }}</p>
 
    {# 格式化输出,返回"Number is 2" #}
    <p>{{ '%s is %d' | format("Number", 2) }}</p>
 
    {# 关闭HTML自动转义 #}
    <p>{{ '<em>name</em>' | safe }}</p>
    
    {# 四舍五入取整,返回13.0 #}
    <p>{{ 12.8888 | round }}</p>
 
    {# 向下截取到小数点后2位,返回12.88 #}
    <p>{{ 12.8888 | round(2, 'floor') }}</p>
 
    {# 绝对值,返回12 #}
    <p>{{ -12 | abs }}</p>

    {# 取第一个元素 #}
    <p>{{ [1,2,3,4,5] | first }}</p>
 
    {# 取最后一个元素 #}
    <p>{{ [1,2,3,4,5] | last }}</p>
 
    {# 返回列表长度,可以写为count #}
    <p>{{ [1,2,3,4,5] | length }}</p>
 
    {# 列表求和 #}
    <p>{{ [1,2,3,4,5] | sum }}</p>
 
    {# 列表排序,默认为升序 #}
    <p>{{ [3,2,1,5,4] | sort }}</p>
 
    {# 合并为字符串,返回"1 | 2 | 3 | 4 | 5" #}
    <p>{{ [1,2,3,4,5] | join(' | ') }}</p>
    
其他: 
    default 默认值
    capitalize 首字母大写
    lower 全小写
    upper 全大写
    trim 去除空格
    reverse 反转
    format 格式化输出
    safe 关闭转义(已审查,没有安全隐患)
    striptags 将值中标签去掉
    round 四舍五入(截取)
    abs 绝对值
    first 第一个元素
    last 最后一个元素
    length 列表长度
    sum 列表求和
    sort 列表排序(升序)
    join 合并字符串

三、模型基本操作

  • 模型概念
- Flask默认并没有提供任何数据库操作API
- 我们可以选择任何适合自己项目的数据库来使用
- Flask数据库操作,可以使用原生SQL语句,也可以使用ORM(SQLAlchemy,MongoEngine)
- 原生SQL缺点
    代码利用率低,条件复杂代码语句越长,有很多相似语句;
    一些SQL是在业务逻辑中拼出来的,修改需要了解业务逻辑,直接写SQL容易忽视SQL问题;
  • 对象关系映射 ORM
用于实现面向对象编程语言里不同类型系统的数据之间的转换。
将对象的操作转换为原生SQL。
- 易用性,可以有效减少重复SQL
- 性能损耗少
- 设计灵活,可以轻松实现复杂查询
- 移植性好

python的ORM(SQLAlchemy)

  • python中的SQLAlchemy安装
# 其实是安装了SQLAlchemy, flask-sqlalchemy
pip install flask-sqlalchemy

# flask-sqlalchemy 官网
http://flask-sqlalchemy.pocoo.org/2.3/
  • flask-sqlalchemy初始化
- app/models.py文件中
    from flask_sqlalchemy import SQLAlchemy
    # 实例化对象,但还需要在__init__.py进行初始化
    db = SQLAlchemy()

- app/__init.py__文件中
    from app.models import db
    # 数据库连接配置(SQLite相对简单)
    app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///sqlite3.db'
    
    # 初始化
    db.init_app(app)

启动项目时报出警告,如果不需要可以将对应配置SQLALCHEMY_TRACK_MODIFICATIONS为False即可,以减少对象追踪修改的系统开销。

  • 定义模型
class Student(db.Model):
    # 如果想要改表名
    __tablename__ = 'Worker'
    s_id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    s_name = db.Column(db.String(20))
    s_age = db.Column(db.Integer)

flask模型中,主键需要自己定义,否则会报错(每个模型对应一个表单,每个表单都需要一个主键)!

  • 创建表单
db.create_all()
  • 删除表单
db.drop_all()
  • 插入数据
stu = Student()
stu.s_name = '%d-测试' % random.randrange(10000)
stu.s_age = random.randrange(1,100)

db.session.add(stu)
db.session.commit()
  • 查询数据
# 获取对应表单中所有数据
tudents = Student.query.all()

五、模型之数据库

  • 数据库连接
dialect+driver://username:password@host:port/database
    driver 数据库的驱动
    username 数据库用户名
    password 数据库密码
    host 数据主机
    port 数据库端口号
    database 连接数据库名

SQLite数据库连接不需要额外驱动,也不需要用户名和密码

  • 连接数据库指定配置
# 即上述内容
app.config['SQLALCHEMY_DATABASE_URI'] = DB_URI
# 禁止对象追踪修改
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False  
  • 连接MySQL
- 系统中安装有MySQL

- MySQL连接驱动
    pip install pymysql
    
- MySQL中创建对应的数据库
    create database HelloFlask charset=utf8;
    
- 连接数据库配置
    app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:123456@localhost:3306/HelloFlask'
    
- 其他操作都是一样(就是数据库不同而已)

六、项目拆分

- 扩展的 ext.py
    
- 配置的 settings.py

项目拆分
规划项目结构