flask基础
Flask基础
Flask诞生于2010年,是Armin ronacher(人名)用 Python 语言基于 Werkzeug 工具箱编写的轻量级Web开发框架。
Flask 本身相当于一个内核,其他几乎所有的功能都要用到扩展(邮件扩展Flask-Mail,用户认证Flask-Login,数据库Flask-SQLAlchemy),都需要用第三方的扩展来实现。比如可以用 Flask 扩展加入ORM、窗体验证工具,文件上传、身份验证等。Flask 没有默认使用的数据库,你可以选择 MySQL,也可以用 NoSQL。
其 WSGI 工具箱采用 Werkzeug(路由模块),模板引擎则使用 Jinja2。这两个也是 Flask 框架的核心。
官网: https://flask.palletsprojects.com/en/1.1.x/
官方文档: [http://docs.jinkan.org/docs/flask/](http://docs.jinkan.org/docs/flask/)
**Flask常用第三方扩展包:**
- Flask-SQLalchemy:操作数据库,ORM;
- Flask-script:终端脚本工具,脚手架;
- Flask-migrate:管理迁移数据库;
- Flask-Session:Session存储方式指定;
- Flask-WTF:表单;
- Flask-Mail:邮件;
- Flask-Bable:提供国际化和本地化支持,翻译;
- Flask-Login:认证用户状态;
- Flask-OpenID:认证, OAuth;
- Flask-RESTful:开发REST API的工具;
- Flask JSON-RPC: 开发rpc远程服务[过程]调用
- Flask-Bootstrap:集成前端Twitter Bootstrap框架
- Flask-Moment:本地化日期和时间
- Flask-Admin:简单而可扩展的管理接口的框架
可以通过 https://pypi.org/search/?c=Framework+%3A%3A+Flask 查看更多flask官方推荐的扩展
虚拟环境
# 创建虚拟环境flask
mkvirtualenv flask -p python3
# 安装flask
pip install flask==0.12.5
# 创建项目
1,进入虚拟环境
workon flask
2,进入目录创建文件夹(项目)
mkdir
3,指定虚拟环境解释器
第一个程序main.py
from flask import Flask # 导入Flask类
app = Flask(__name__)
class Config(): # 项目配置
DEBUG = True # 开启调试模式
app.config.from_object(Config) # 加载项目配置
路由
# flask的路由是通过给视图添加装饰器的方式进行编写的。当然也可以分离到另一个文件中。
# flask的视图函数,flask中默认允许通过return返回html格式数据给客户端。
# 基本使用
不限定路由参数数据类型
# 路由传递参数 [没有限定数据类型]
限定路由参数数据类型
# 通过路由转换器限定路由参数的类型 werkzeug.routing.py
# 系统提供的一些数据类型
DEFAULT_CONVERTERS = {
"default": UnicodeConverter,
"string": UnicodeConverter,
"any": AnyConverter,
"path": PathConverter,
"int": IntegerConverter,
"float": FloatConverter,
"uuid": UUIDConverter,
}
系统提供的路由参数转换器
自定义路由参数转换器
from werkzeug.routing import BaseConverter # 导入转换器基类
# 方式一
class MobileCinverter(BaseConverter):
def __init__(self,map):
self.regex = '1[3-9]\d{9}' # 匹配规则
super().__init__(map) # 总路由类
app.url_map.converters['mobile'] = MobileCinverter # mobile就是自定义参数类型
限定路由请求方法
请求
from flask import Flask,request
app = Flask(__name__)
class Config():
DEBUG = True
app.config.from_object( Config )
钩子
from flask import Flask,make_response,request
app = Flask(__name__)
class Config():
DEBUG = True
app.config.from_object( Config )
响应
# Response(response="内容", status="http响应状态码",headers=自定义响应头,mimetype="数据格式")
# 状态码的响应
1,响应html文本
from flask import make_response
2, 返回JSON数据
from flask import Flask, request, jsonify
# jsonify 就是json里面的jsonify
3, 返回图片
from flask import Flask,request,make_response,Response,jsonify
app = Flask(__name__)
4, 重定向
4.1 外网跳转
from flask import redirect
4.2 内网跳转
from flask import url_for
4.2.1 带参数跳转
# 路由传递参数
http会话控制
cookie
"""
Cookie是由服务器端生成,发送给客户端浏览器,浏览器会将Cookie的key/value保存,下次请求同一网站时就发送该Cookie给服务器(前提是浏览器设置为启用cookie)。Cookie的key/value可以由服务器端自己定义
"""
from flask import Flask,make_response,request
app = Flask(__name__)
class Config():
DEBUG = True
app.config.from_object( Config )
session
"""
session相关配置项文档:
`https://dormousehole.readthedocs.io/en/latest/config.html?highlight=session_cookie_path`
flask中的session需要加密,所以使用session之前必须配置SECRET_KEY选项,否则报错.
session的有效期默认是会话期,会话结束了,session就废弃了。
"""
from flask import Flask, make_response, request,session
app = Flask(__name__)
class Config():
SECRET_KEY = "kjdas/.的>发4.4'!" # 盐必须加
DEBUG = True
app.config.from_object( Config )
session储存空间
flask-session
# 允许设置session到指定存储的空间中
# 安装
pip install flask-Session
redis
# 配置
from flask import Flask,session
from flask_redis import FlaskRedis
from flask_session import Session
app = Flask(__name__)
redis = FlaskRedis()
session_store = Session()
class Config(object):
DEBUG = True # 开启调试模式
SECRET_KEY = "*(%#4sxcz(^(#$#8423" # 密钥
SESSION_TYPE="redis" # session存储方式为redis
SESSION_REDIS = redis # session保存数据到redis时启用的链接对象
SESSION_PERMANENT = False # 为True,则关闭浏览器session就失效
SESSION_USE_SIGNER = False # 是否对发送到浏览器上session的cookie值进行加密
SESSION_KEY_PREFIX = "session:" # 保存到redis的session数的名称前缀
REDIS_URL = "redis://localhost:6379/1" # redis的链接配置
app.config.from_object(Config)
redis.init_app(app)
session_store.init_app(app)
# 使用
SQLAlchemy
from flask import Flask,session
from flask_session import Session
from flask_sqlalchemy import SQLAlchemy
session_store = Session()
db = SQLAlchemy()
app = Flask(__name__)
class Config(object):
DEBUG = True
# 动态追踪修改设置,如未设置只会提示警告
SQLALCHEMY_TRACK_MODIFICATIONS = True
# 查询时会显示原始SQL语句
SQLALCHEMY_ECHO = True
# 密钥
SECRET_KEY = "*(%#4sxcz(^(#$#8423"
# 数据库链接配置 = 数据库名称://登录账号:登录密码@数据库主机IP:数据库访问端口/数据库名称?charset=编码类型
SQLALCHEMY_DATABASE_URI = "mysql://root:1@127.0.0.1:3306/flask_test?charset=utf8mb4"
# 数据库保存session
SESSION_TYPE = 'sqlalchemy' # session类型为sqlalchemy
SESSION_SQLALCHEMY = db # SQLAlchemy对象
SESSION_SQLALCHEMY_TABLE = 'tb_session' # session要保存的表名称
SESSION_PERMANENT = True # 如果设置为True,则关闭浏览器session就失效。
SESSION_USE_SIGNER = False # 是否对发送到浏览器上session的cookie值进行加密
SESSION_KEY_PREFIX = 'session:' # 保存到session中的值的前缀
db.init_app(app)
app.config.from_object( Config )
session_store.init_app(app)
# 视图
异常捕获
主动抛出HTTP异常
abort(500)
捕获异常
context 执行上下文
在程序中可以理解为在代码执行到某一行时,根据之前代码所做的操作以及下文即将要执行的逻辑,可以决定在当前时刻下可以使用到的变量,或者可以完成的事情。
Flask中有两种上下文,请求上下文(request context)和应用上下文(application context)。
请求上下文:保存了客户端和服务器交互的数据,一般来自于客户端。
应用上下文:flask 应用程序运行过程中,保存的一些配置信息,比如路由列表,程序名、数据库连接、应用信息等
请求上下文(request context)
# request
- 封装了HTTP请求的内容,针对的是http请求。举例:user = request.args.get('user'),获取的是get请求的参数。
# session
- 用来记录请求会话中的信息,针对的是用户信息。举例:session['name'] = user.id,可以记录用户信息。还可以通过session.get('name')获取用户信息。
应用上下文(application context)
# current_app
- current_app.name # 获取当前app的名称
- current_app.config # 获取当前项目的所有配置信息
- current_app.url_map # 获取当前项目的所有路由信息
# g变量(只能在视图当中进行)
- g.name = "root" # 设置全局变量
- obj = g.name # 获取全局变量
Flask-Script 扩展
# 作用:可以让我们通过终端来控制flask项目的运行,类似于django的manage.py
# 安装:pip3 install flask-script
基本使用
from flask import Flask,g
app = Flask(__name__)
class Config():
DEBUG = True
app.config.from_object( Config )
from flask_script import Manager
manage = Manager(app)
# 视图
Flask-Script 为当前应用程序添加脚本命令
from flask import Flask
app = Flask(__name__)
class Config():
DEBUG = True
app.config.from_object( Config )
from flask_script import Manager,Command,Option
manage = Manager(app) # 注册运行app的命令
import os
class BluePrintCommand(Command): # Command 命令基类
option_list = [
Option('--name','-n',help='蓝图')
]
def run(self,name=None):
if name is None:
print('蓝图不能为空')
if not os.path.isdir(name):
os.mkdir(name)
open("%s/views.py" % name, "w")
open("%s/models.py" % name, "w")
with open("%s/urls.py" % name, "w") as f:
f.write("""from . import views
urlpatterns = [
]""")
manage.add_command('blue',BluePrintCommand) # 注册子应用命令blue
# 视图
Jinja2模板引擎
渲染模版函数
- Flask提供的 render_template 函数封装了该模板引擎
- render_template 函数的第一个参数是模板的文件名,后面的参数都是键值对,表示模板中变量对应的真实值。
1 万能点
# (索引,key,属性,方法(不加括号,只能进行无参数方法),类,对象)
2 if 语句
{% if 条件 %}
{% else if 条件 %}
{% else %}
{% endif %}
3 for 语句
{for i in lst} # 如果lst为空,或者后台没有给lst数据,那么就展示empty下面的内容
<h1>i</h1>
{% empty %}
<span>哥,啥也木有啊</span>
{% endfor %}
### loop 循环信息对象
loop.index # 当前循环次数,从1开始
loop.index0 # 当前循环次数,从0开始
loop.first # 当前循环是不是第一次循环(布尔值)
loop.last # 当前循环是不是最后一次循环(布尔值)
4 过滤器
# html,语法:{{ value|filter_name:参数}}
{{ value|upper}} # value英文变大写
{{ value|safe }} # 若果是标签格式,具有标签效果
{{ value|reverse}} # value英文变大写
{{ value|truncate(4) }} # 从第四个字符截断...
{{ value|default:"默认值"}} # 当value没有传值时,拿默认值填充
{{ value|length}} # value的长度
{{ value|filesizeformat}} # 数字可转换为MB单位
{{ value|slice:"0:4"}} # value切片
{{ value|date:"Y-m-d H:i:s" }} # value时间格式化
{{ value|cut:' ' }} # 移除(字符)空格
{{ value|join:'-' }} # 字符串拼接
4.1 自定义过滤器
# 自定义过滤器
5 模板继承
# 模板(母版.html页面)
划分子板可能要添加内容的区域
{% block content%}
要添加内容的区域
{% endblock %}
# 继承模板
{% extends '母版.html页面'%}
{% block content%}
子板要修改的内容
{% endblock %}
# 总结:
{% block css%} 等同样适用
csrf 攻击
from flask import Flask,render_template
app = Flask(__name__,template_folder='templates')# 应用使用视图,需要告诉Flask去哪找templates模板
class Config():
DEBUG = False
SECRET_KEY = 'ASLKFM.,//;,.FS;DKMF' # 用于加密生成的 csrf_token 的值
app.config.from_object( Config )
from flask.ext.wtf import CSRFProtect
CSRFProtect(app) # csrf 防护体系作用于app
# 视图
数据库操作
flask默认提供模型操作,但是并没有提供ORM,所以一般开发的时候我们会采用flask-SQLAlchemy模块来实现ORM操作。
SQLAlchemy是一个关系型数据库框架,它提供了高层的 ORM 和底层的原生数据库的操作。flask-sqlalchemy 是一个简化了 SQLAlchemy 操作的flask扩展。
中文文档: https://www.osgeo.cn/sqlalchemy/index.html
# 安装
安装 flask-sqlalchemy【清华源】
pip install flask-sqlalchemy -i https://pypi.tuna.tsinghua.edu.cn/simple
如果连接的是 mysql 数据库,需要安装 mysqldb 驱动
sudo dpkg --configure -a
apt-get install libmysqlclient-dev python3-dev
pip install flask-mysqldb -i https://pypi.tuna.tsinghua.edu.cn/simple
# 配置
class Config(object):
# 调试模式
DEBUG = True
# 显示多字节
# 动态追踪修改设置,如未设置只会提示警告
SQLALCHEMY_TRACK_MODIFICATIONS = True
# 查询时会显示原始SQL语句
SQLALCHEMY_ECHO = True
# 数据库链接配置 = 数据库名称://登录账号:登录密码@数据库主机IP:数据库访问端口/数据库名称?charset=编码类型
SQLALCHEMY_DATABASE_URI = "mysql://root:1@127.0.0.1:3306/flask_test?charset=utf8mb4"
app.config.from_object( Config )
# 创建模型类
class Student(db.Model):
__tablename__ = "tb_student"
id = db.Column(db.Integer, primary_key=True,comment="主键ID")
name = db.Column(db.String(250), comment="姓名")
age = db.Column(db.Integer, comment="年龄")
sex = db.Column(db.Boolean, default=False, comment="性别")
money = db.Column(db.DECIMAL(8,2), nullable=True, comment="钱包")
def __repr__(self):
return self.name
# 注册表
with app.app_context():
db.create_all()
单表基本操作
"""执行原生SQL语句,返回结果不是模型对象, 是列表和元祖"""
# 查询多条
# ret = db.session.execute("select id,name,age,IF(sex,'男','女') from tb_student").fetchall()
# print(ret)
# # 查询单条
# ret = db.session.execute("select * from tb_student where id = 3").fetchone()
# print(ret)
增
# 添加一条数据
student1 = Student(name="小明", sex=True, age=17, email="123456@qq.com", money=100)
db.session.add(student1)
db.session.commit()
# 添加一条数据
st1 = Student(name='wang',email='wang@163.com',age=22)
st2 = Student(name='zhang',email='zhang@189.com',age=22)
st3 = Student(name='chen',email='chen@126.com',age=22)
db.session.add_all([st1,st2,st3])
db.session.commit()
删
# 方法1
student = Student.query.first()
db.session.delete(student)
db.session.commit()
# 方法2【事务中使用,就是乐观锁】
ret = Student.query.filter(Student.name=='sun').delete()
db.session.commit()
改
# 方法1
student = Student.query.first()
student.name = 'dong'
db.session.commit()
# 方法2【事务中使用,就是乐观锁】
ret = Student.query.filter(Student.name == 'liu').update({'money': 1000})
db.session.commit()
# 方法3【批量操作, 实现类似django里面F函数的效果】
ret = Student.query.filter(Student.age == 22).update({Student.money: Student.money+'200'})
db.session.commit()
查
# filter
# 单条件查找
student = Student.query.first(Student.age == 18).first()
student = Student.query.first(Student.age >= 18).first()
# 多条件查找
from sqlalchemy import and_, or_ , not_, in_
student = Student.query.first(and_(Student.age > 18,Student.name=='liu')).all()
student = Student.query.first(or_(Student.age > 18,Student.name=='liu')).all()
student = Student.query.first(not_(Student.name=='liu')).all()
student = Student.query.first(Student.age.in_([22,18])).all()
# 模糊查询
student = Student.query.first(Student.name.like('%xiao%')).all() # 包含 contains("xiao")
student = Student.query.first(Student.name.like('xiao%')).all() # 以..开头 startwiths("xiao")
student = Student.query.first(Student.name.like('%xiao')).all() # 以..结尾 startwiths("xiao")
student = Student.query.first(Student.name.like('_')).all() # 值长度为1个字符的
# filter_by
student = Student.query.first(Student.age=18).first()
# order_by
student = Student.query.order_by(Student.age.asc()).all() # 正序
student = Student.query.order_by(Student.age.desc()).all() # 倒序
obj = Student.query.filter(or_(Student.name == '周鹏飞' ,Student.age>= 20)).
order_by(db.desc(Student.age)).all() # 查找结果后再排序
# 聚合查询
ret = Student.query.filter(Student.age > 18).count() # 统计数量
ret = Student.query.order_by(Student.age.asc()).limit(1).all()
# 对学生的钱包进行从大到小排名,第3-第5名的学生
student_list = Student.query.order_by(Student.money.desc()).offset(2).limit(3).all()