相关推荐recommended
python之 flask 框架(1)
作者:mmseoamin日期:2024-04-27

pycharm 查看方法的定义(类似.net 中 F12)

ctrl + 单击(对应的方法)

python之 flask 框架(1),Learning,第1张

python之 flask 框架(1),在这里插入图片描述,第2张

创建安装虚拟环境

两种方法

python之 flask 框架(1),在这里插入图片描述,第3张

python之 flask 框架(1),在这里插入图片描述,第4张

python之 flask 框架(1),在这里插入图片描述,第5张

第二种

# 先打开cmd 中断
# 查看virtual是否安装过
pip show virtualenv 
# 安装
pip install virtualenvwrapper-win
# workon 查看虚拟环境
vorkon
# 切换虚拟环境
# workon 虚拟环境 
# mkvirtualenv 创建新的虚拟环境
mkvirtualenv falsk2env
# 删除虚拟环境
#rmvirtualenv flask2env
#进入虚拟环境
workon flask2env

python之 flask 框架(1),在这里插入图片描述,第6张

python之 flask 框架(1),在这里插入图片描述,第7张

python之 flask 框架(1),在这里插入图片描述,第8张

python之 flask 框架(1),在这里插入图片描述,第9张

pip list 查看虚拟环境所有的包

pip freeze 查看自己安装的包

python之 flask 框架(1),在这里插入图片描述,第10张

创建Flask 项目

专业版pychram

python之 flask 框架(1),在这里插入图片描述,第11张

社区版 要手动创建

python之 flask 框架(1),在这里插入图片描述,第12张

python之 flask 框架(1),在这里插入图片描述,第13张

python之 flask 框架(1),在这里插入图片描述,第14张

python之 flask 框架(1),在这里插入图片描述,第15张

python之 flask 框架(1),在这里插入图片描述,第16张

from flask import Flask, render_template, jsonify
app = Flask(__name__)
# 路由可以多个对一个视图函数的
@app.route('/')
@app.route('/index/')
def index():
    # 返回值
    # 直接返回
    # return 'ZEN'
    # 模板渲染
    # return render_template('index.html',name='123')
    # 返回json对象
    # return {'name':'Ares-Wang','Sex':'男'}
    # 返回json序列化
    return jsonify({'name':'Ares-Wang','Sex':'男'})
@app.route('/')
def home():
    return 'ARES-ZEN'
if __name__ == '__main__':
    app.run(host='0.0.0.0',debug=True)

python之 flask 框架(1),在这里插入图片描述,第17张




--url_for   反向解析
    

Flask 项目拆分

python之 flask 框架(1),在这里插入图片描述,第18张

python之 flask 框架(1),在这里插入图片描述,第19张

# app.py
from APP import Create_App
app = Create_App()
if __name__ == '__main__':
    app.run(host='0.0.0.0',debug=True)
# views.py
# views.py   路径  +   视图函数
from flask import Blueprint
from .models import *
blue = Blueprint('BlueName', __name__)
@blue.route('/')
def Home():
    return 'SPlIT'
# __init__.py
# __init__.py :初始化文件、创建Flask应用
from flask import Flask
from .views import blue
def Create_App():
    # 返回Flask对象
    app = Flask(__name__)
    # print(app.config)
    # SECRET_KEY 是对称加密的密钥,存在浏览器的
    # session['xxx']='123',session 通过secret_key 把123 加密存在服务器端
    # 同时客户端cookie中存入cookieID 也是加密的 session 设置要配置secret_key
    # app.config['SECRET_KEY']='ZEN'
    # 设置session过期时间
    # app.config['PERMANENT_SESSION_LIFEATIME']=datetime.timedelta
    # 注册蓝图 可以注册多个蓝图
    app.register_blueprint(blueprint=blue)
    return app

路由参数

@app.route(‘/xxx/converter:variable_name’)

converter:参数类型

string:接受任何没有斜杠’/'的字符串 默认参数类型

int:接受整数

float:接受浮点数

path 接受路径, 可接受斜杠(’/‘)的字符串

uuid 只能接受uuid字符串,唯一码,一种生成规则 根GUID一样的

any 可以同时指定多种路径,进行限定

@app.route(‘/student//’) 与 @app.route(‘/student/string:username/’) 一样

@app.route(‘/student/int:id/’)

def get_student(id):

student= Student.query.get(id)

@app.route(‘/student/uuid:id/’)

@app.route(‘/student/float:num/’)

@app.route(‘/student/path:path/’)

@app.route(‘/student//’)

请求方法 常见POST GET

Flask 默认支持GET,不支持POST请求的

@app.route(‘/student/’)

同时支持get 、post 请求

@app.route(‘/student/’,methods=[‘GET’, ‘POST’])

python之 flask 框架(1),在这里插入图片描述,第20张

请求对象和响应对象 request response

request

服务器在接受客户端的请求后,会自动创建Request对象,有FLask框架创建,request对象不可修改

# requests 爬虫测试下面的请求对象
import requests
request = requests.get('http://127.0.0.1:5000/index/?user=123')
request = requests.post('http://127.0.0.1:5000/index/',data={'user':3456})
print(request.text)

python之 flask 框架(1),在这里插入图片描述,第21张

python之 flask 框架(1),在这里插入图片描述,第22张

from flask import Flask,request
@app.route('/index/>',methods=['GET',  'POST'])
def get_index():
    #   服务器在接受客户端的请求后,会   自动创建 Request 对象,由Flask 框架创建,request 对象不可修改,只能使用
	# 获取请求方式
	print(request.method)
	# url 完整请求地址    
	print(request.url)   		# http://127.0.0.1:5000/index/?user=123'
	# base_url   去掉get参数的url
	print(rquest.base_url)		# http://127.0.0.1:5000/index/
	# host_url   只有主机名和端口号
	print(rquest.host_url)		# http://127.0.0.1:5000/
	# remote_addr   请求的客户端地址
	print(request.remote_addr)   #IP地址
	# files 文件上传
	print(request.files)
	# 用户代理, 包括浏览器和操作系统的信息  反爬用的    类似 python-requests/2.31.0
	print(request.user_agent)
	# headers 请求头
	print(request.headers)
	# headers 请求中的cookie
	print(request.cookies)
	# 获取请求参数  get 请求,返回是字符串
	# request.args.get(key,defaultValue)   如果key,没有传参,可以赋默认值,
	print(request.args.get(key))
	# 返回是ImmutableMultiDict类型
	print(request.args)
	# 获取请求参数  post 请求
	print(request.from.get(key))
	#返回是ImmutableMultiDict类型
	print(request.from)

python之 flask 框架(1),在这里插入图片描述,第23张

ImmutableMultiDict类型

python之 flask 框架(1),在这里插入图片描述,第24张

Respone响应

# 导入模板渲染用的包
from flask import render_template, jsonify, make_response,Response
@app.route('/response/')
def  get_Response():
	# 响应的几种方式
	# 1、返回字符串(不常用)
	return 'AresZEN'
	# 2、模板渲染(前后端不分离) 在templates中创建模板 xx.html  中jinja2语法 {{}}  
	return render_template('xx.html',param1='' , param2='')
	# 3、返回json数据(前后端分离)
	return {'name':'Ares','age':30}
	# jsonify()  序列号    josn=>字符串
	return jsonify({'name':'Ares','age':30})
	# 4、自定义Response对象
	html= render_template('xx.html',param1='' , param2='')
	# 返回字符串(html格式的字符串)
	print(html,type(html))
	#  导入包make_response(返回的数据,状态码)
	res=make_response(html,200)   
	# res = Response(html)  跟上面效果一样
	res.set_cookie()  #  设置cookie
	#  上面任意一个都可以
	return res

Redirect 重定向

@blue.route('redirect')
def make_redirect():
	# 重定向的几种方式
	# return redirect('https://www.baidu.com')
	# return redirect('/路由/')   #  在程序中跳转
	# url_for():反向解析,通过视图函数名反过来找路由,    正常是通过路由找视图函数的,反向解析: 就是根据视图函数,找路由
	# url_for('蓝图名称.视图函数名')  #  注意是蓝图名称 ,不是蓝图对象   blue对象 = Blueprint('BlueName蓝图名称', __name__)
	# ret = url_for('蓝图名称.视图函数名')
	# return redirect(rect)
	# url_for 传参
	ret= url_for('蓝图名称.视图函数名',参数名=Value,参数名2=Value2)
	return redirect(rect2)

会话技术 Cookie和Session

python之 flask 框架(1),在这里插入图片描述,第25张

python之 flask 框架(1),在这里插入图片描述,第26张

设置cookie

python之 flask 框架(1),在这里插入图片描述,第27张

获取cookie

request.cookies.get(key)

删除cookie

response.delete_cookie(key)

cookie不能存中文

session

session服务器端会话技术,依赖于cookie

特点:

- 服务端的会话技术

- 所有数据存储在服务器中

- 默认存储在内存中

- 存储结构:key-value形式,键值对

- session 离不开cookie

- sessionID存储在客户端, session的值存在在服务端

python之 flask 框架(1),在这里插入图片描述,第28张

python之 flask 框架(1),在这里插入图片描述,第29张

session设置

session[‘key’]=‘value’

获取session 如果不存在,就返回 default指定的值

session.get(key,default=None)

删除session

session.pop(key) 删除某一值

session.clear() 清除所有session

python之 flask 框架(1),在这里插入图片描述,第30张

cookie VS session

cookie: ①存储在客户端(浏览器)②安全性较低③可以降低服务器压力

session:①存储在服务端(服务器)②安全性高③对服务器要求较高④仍然需要依赖cookie, 服务器生成的sessionID会返回给客户端,sessionID 存储在客户端。

模板Template

python之 flask 框架(1),在这里插入图片描述,第31张

python之 flask 框架(1),在这里插入图片描述,第32张

JinJa2 引擎的模板语法,及传参

模板语法主要分为两种:

  • 变量
  • 标签

模板中的变量 {{ 变量名 }} 变量不存在,默认忽略,不会报错

views 视图函数传递给模板的数据 return render_template(‘xxx.html’,参数1=value1,参数2=Value2)

或者

data ={ ‘age’ :20,‘name’:‘ZEN’ ,hobbys:[‘football’,‘basketball’]}

render_template(‘xxx.html’, **data)

模板中取值 {{ age }} {{name}}

{{ hobbys }} 返回是 [‘football’,‘basketball’] 的字符串 所以一般用for循环取值

循环 for

{% for hobby in hobbys %}

# segment

{% else %} #hobby 不存在了,就进入else 了。

segment

{% endfor %} 要有结束标签

使用 获取循环信息 loop

{% for hobby in hobbys %}

{{hobby}}

index:{{ loop.index }} # 从1开始的下标

index:{{ loop.index0 }} # 从0开始的下标

index:{{ loop.revindex }} # 反向下标,不包括0

index:{{ loop.revindex0 }} # 反向下标,包括0

index:{{ loop.first }} # 判断是否是第一个元素

index:{{ loop.last }} # 判断是否是最后一个元素

模板中的标签 {% tag %} 注意要有结束标签 注意要有结束标签

控制逻辑、使用外部表达式 创建变量 宏定义

{% if age >=18 %}

成年

模板继承

python之 flask 框架(1),在这里插入图片描述,第33张





    
    ParentTemplate
    

include文件



{% extends 'Base.html'%}
{% block extcss %}
    {% extends '1.html' %}
{% block content %}
{{super()}}

AresZEN

{% endblock %} {# 定义 Python函数} {% macro person(name.age) %} 姓名:{{ name }}, 年龄:{{ age }} {% endmarco %} {% block foot %} {{ person('ZEN',27) }} {% endblock %}

{% extends '1.html' %}
{% block content %}
	
	{{super()}}
	

AresZEN

{% endblock %}

python之 flask 框架(1),在这里插入图片描述,第34张

模型基础

python之 flask 框架(1),在这里插入图片描述,第35张

python之 flask 框架(1),在这里插入图片描述,第36张

安装 flask_sqlalchemy (用于ORM)

pip install flask_ sqlalchemy -i https://pypi.douban.com/simple

安装 flask_migrate (用于数据迁移 把数据库模型迁移到数据库中)

pip install flask_ migrate -i https://pypi.douban.com/simple

安装 pymysql (mysql 驱动)

pip install pymysql -i https://pypi.douban.com/simple

Flask中使用ORM

连接数据库需要指定配置

数据库模型的定义

一个数据库模型对应一个数据库中的表,所有的数据库模型都要基础ORM对象的Modle基类,即db.Model

#   models.py   模型  数据库
# 创建数据库模型
#	模型 	=》		数据库
#	类	 	=》		表结构
#	类属性 	=》		表字段
#	一个对象 =》		表的一个行数据
from .exts import db
class Account(db.Model):
	# 定义数据库的表名
	__tablename__ = "account"
	id = db.Column(db.Integer,primary_key=True, autoincrement=True)
	account = db.Column(db.String(10),unique=True,nullable=False)
	username = db.Column(db.String(30),nullable=False)
	# 定义显示信息   在模型类中,重写   __repr__   方法, 
    def __repr__(self):
        """定义之后,可以让显示对象的时候更直观"""
        return "User object : username =%s" % self.username 
# exts.py  插件管理
# 1、导入第三方插件
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
# 2、 初始化对象
db = SQLAlchemy()   # ORM
migrate = Migrate() # 数据迁移
# 3、与app对象绑定
def init_exts(app):
    db.init_app(app=app)
    migrate.init_app(app=app,db=db)
?#   __init__.py :初始化文件、创建Flask应用
import datetime
from flask import Flask
from .views import blue
from .exts import init_exts
def Create_App():
    # 返回Flask对象
    app = Flask(__name__)
    # ORM 数据库配置
    # SQLite 数据库连接不需要额外驱动,也不需要用用户名和密码  SQLite 一般是手机程序用的  本地数据库
    DB_URI='sqlite:///sqlite3.db'
    app.config['SQLALCHEMY_DATABASE_URI']=DB_URI # 配置连接数据库路径DB_URI
    app.config['SQLALCHEMY_TRACK_MODIFICATIONS']=False   # 禁用对象追踪修改
    # 初始化插件
    init_exts(app=app)
    # 注册蓝图 可以注册多个蓝图
    app.register_blueprint(blueprint=blue)
    return app```

python之 flask 框架(1),在这里插入图片描述,第37张

数据迁移 : 就是把model模型在数据库中创建表

  1. 先在cmd 或Terminal 进入项目目录(可以把选择项目 拖入到terminal)(app.py所在目录)
  2. 返回执行如下命令
    1. flask db init # 创建迁移文件夹migrates,只能执行一次
    2. flask db migrate # 生成迁移文件
    3. flask db upgrade # 执行迁移文件的升级 数据库就有表啦 如果表结构变化要执行这个 把迁移中的改动应用到数据库中
    4. flask db downgrade # 执行文件中的降级

python之 flask 框架(1),在这里插入图片描述,第38张

配置mysql 前提 要存在这个数据库

DB_URI=’mysql+pymysql://root:root@localhost:3306/数据名‘

表的CRUD操作

要在视图函数操作数据模型,从而同步数据库

#  views.py 中
# 蓝图
from flask import Blueprint,render_template,request
from .models import *
# 蓝图
blue = Blueprint('bluename',__name__)
@blue.route('/')
def index():
	return render_template('index.html')
# 表单操作:CRUD操作
@blue.route('/accountadd/',methods=['GET','POST'])
def account_add():
	# 添加一个记录   Account 是类,定义在models.py
	u = Account()
	if request.method=='GET':
		u.account = request.args.get('account')
		u.username = request.args.get('username')
	else:
		u.account = request.from.get('account')
		u.username = request.from.get('username')	
	#  views.py中没有导入 exts为啥油db对象,因为db对象在models.py 导入了。   因此 views中导入model,相当于也导入了exts
	db.session.add(u)  			# 将u对象添加到session中	
	db.session.commit()			# 同步到数据库中
	return 'success!'
@blue.route('/accountaddall/')
def account_add():
	# 添加多条记录   Account 是类,定义在models.py
	users = []
	for i in range(1,10):
		u=Account()
		u.account = 'ZEN_'+str(i)
		u.username = 'Ares_'+str(i)	
		users.append(u)	
	#  views.py中没有导入 exts为啥油db对象,因为db对象在models.py 导入了。   因此 views中导入model,相当于也导入了exts
	# db.session.add_all(对象列表)
	try:
		db.session.add_all(users)  			# 将u对象列表添加到session中	
		db.session.commit()					# 同步到数据库中   事务提交
	except Exception as e:
		db.session.rollback()				# 回滚
		db.session.flush()					# 把session中数据清理掉											
		return 'fail: '+ str(e)
	return 'success!'
@blue.route('/accountdelete/')
def account_del():
	try:
		u=Account.query.first() # 查询第一条数据
	    db.session.delete(u)
	    db.session.commit()
	 except Exception as e:
	 	db.session.rollback()
	 	db.session.flush()  
    return 'success!'
 
@blue.route('/accountupdate/')
def account_update():
	try:
		u=Account.query.first() # 查询第一条数据
		u.username='yyds'	   
	    db.session.commit()
	 except Exception as e:
	 	db.session.rollback()
	 	db.session.flush()  
    return 'success!'
#  查询数据
@blue.route('/userget/')
def user_get():
	# all(): 以列表形式返回查询的所有结果,返回列表
	# users = Account.query.all()
	# first() 返回查询的第一个结果,如果没有结果,则返回None
	# user = Account.query.first()   可以继承  过滤器
	# filter() 把过滤器添加到原查询上,返回一个新查询,可以继续   . 过滤器
	# users = Account.query.filter()   可以继承  过滤器
	# user = Account.query.filter(Account.username=='yyds')
	# filter_by() 把**等值**过滤器添加到原查询上,返回一个新查询
	
	#  filter_by() 与  filter()  区别
	
	# user = Account.query.filter_by(username='yyds')
	# count() 返回查询结果的数量
	# users = Account.query.filter()  可以继承  过滤器
	print(users.count())
	# first_or_404() 返回查询的第一个结果,如果没有结果,则终止请求,返回404错误响应
	# user = Account.query.filter_by(username='yyds').first_or_404()
	# get()  返回指定主键对应的行,如果没有对应的行,则返回None ,此处家人username是主键
	# user = Account.query.get(username='yyds')
	# get_or_404()  返回指定主键对应的行,如果没有找到指定的主键,则终止请求,返回404错误响应
	#user = Account.query.get(username='yyds')
	# limit()  取前面几条 使用指定的值限制原查询返回的结果数量,返回一个新查询  可以继承 过滤器
	# offset() 跳过前几条 偏移原查询返回的结果,返回一个新查询  ,可以继承  过滤器
	# users = Account.query.offset(3).limit(4)
	# order_by()   排序  升序
	# users = Account.query.order_by('id')
	# order_by()       排序     降序     需要到包   from sqlalchemy import desc
	# users = Account.query.order_by(desc('id'))
	
	# 逻辑运算符   and_    ,    or_     ,  not_
	users = Account.query.filter(Account.username='yyds' , Account.id < 100)    #  且    默认
	#   需要到包   from sqlalchemy import and_ , or_ , not_
	users = Account.query.filter(and_(Account.username='yyds', Account.id < 100) #  且
	
	#  查询属性
	# contains   模糊查询   类似 sql  like
	users = Account.query.filter(Account.username.contains('yd'))
	# in_()   其中只有   类似  sql  in
	users = Account.query.filter(Account.username.in_(['yyds','jjz']))
	# startswith():			以某字符串开头
	# endswith():			以某字符串结尾
	users = Account.query.filter(Account.username.startswith('yy'))
	
	# __gt__     大于
	# __ge__     大于等于
	# __lt__	 小于
	# __le__	 小于等于
	users = Account.query.filter(Account.id.__gt__(300))
    return 'success!'

分页

python之 flask 框架(1),在这里插入图片描述,第39张




    
    Title


    {% for item in Accounts %}
  • {{ item.username }}
  • {% endfor %}
@blue.route('/paginate/')
def get_info():
    page = int(request.args.get('page', 1))
    per_page = int(request.args.get('per_page', 5))
    Accounts = Account.query.paginate(
        page=page,
        per_page=per_page
    ).items
    return render_template('info.html', Accounts)

多表关联

##  model.py   一对多 案例
# models.py   模型  :和数据库相关的
from .exts import db
"""
 department :employee =》 1:N     1对多
外键要设置在 N: 多的 一个表  
"""
# 创建 department 部门表 即 Department 模型
# 模型需要继承db.Model,否则就普通的类
class Department(db.Model):
	# 表名
	__tablename__ = 'department'
	id = db.Column(db.Integer, primary_key=True, autoincrement=True)
	# 部门编号
	deptCode = db.Column(db.String(30), nullable=False)
	# 建立关联
	#		第一个参数:关联的模型名,因python语言是解释性语言,Employees, 需要需要 用  ''
	#		第二个参数:反向引用的名称,department 对象
	#				让employee去反过来得到department对象的名称    employee.department  是个department对象
	#		第三个参数: 延迟加载,懒加载,    用到的时候,才会建立关系,懒加载:为了提高性能,节约资源
	# 这里departments不是字段,不是字段 是类的属性
	employees = db.relationship('Employees', backref='department', lazy=True)
	"""
	查询员工所属的部门,反向引用department
	emp = Employee.query.get('emp_Code值')
	#  department 要跟  backref对应的值保持一致   
	#  emp.department   返回是department对象
	dept = emp.department   
	code=dept.deptCode	
	查询某部门下面的所有员工
	dept = Department.query.get('deptCode值')
	dept.employees  #  所有部门编码下的员工信息  返回是employee 对象列表
	"""
# 创建employee 员工表 即 Employee 模型
# 模型需要继承db.Model,否则就普通的类
class Employee(db.Model):
	# 表名
	__tablename__ = 'employee'
	id = db.Column(db.Integer,  autoincrement=True)
	# 员工姓名
	emp_name = db.Column(db.String(30), nullable=False)
	# 员工编号
	emp_Code = db.Column(db.String(30),nullable=False, unique=True, primary_key=True)
	# 外键 也是字段,  跟 员工表的 员工编号关联  1:N  外键也放在N的表中
	# 实现一对多关系,要在对应的表 添加 db.relationship
	department = db.Column(db.String(30),db.ForeignKey(Department.deptCode), nullable=False, unique=True)

python之 flask 框架(1),在这里插入图片描述,第40张

多对多关系表 N:M

N:M 多对多关系,还存在两个表的中间表:关联作用

python之 flask 框架(1),在这里插入图片描述,第41张

python之 flask 框架(1),在这里插入图片描述,第42张

# models.py
from .ext import db
# usermodel  和  usermodel  建立关联表
collect = db.Table(
	# 表名
	'collects',
	#  组合主键
	# 字段
	db.Column('user_id',db.Integer,db.ForeignKey('usermodel.id'),primary_key=True)
	db.Column('sysmodel_id',db.Integer,db.ForeignKey('sysmodel.id'),primary_key=True)
)
# 用户表
Class UserModel(db.Model):
	__tablename__='usermodel'
	# 字段
	id = db.Column(db.Integer,primary_key=True,autoincrement=True)
	username = db.Column(db,String(30))
	userCode = db.Column(db.String(30),)
# 系统模块
Class SysModel(db.Model):
	__tablename__:'sysmodel'
	id = db.Column(db.Integer,primary_key=True,autoincrement=True)
	name = db.Column(db.String(30))
	# 关联
	# secondary=collect:  设置中间表
	users =db.relationship('UserModel',backref='sysmodels',lazy=True,secondary=collect)
# views.py   
"""
用户表和系统模块表 追加数据略
"""
@blue.route('/addcollect/')
def add_collect():
	# 用户拥有的系统模块
	user = UserModel.query.get('key')
	sysmodel = SysModel.query.get('key')
	# user.sysmodels 是反向查询的  backref='sysmodels'
	user.sysmodels.append(sysmodel)
	db.session.commit()
	return 'success!'
@blue.route('/getcollect/')
def get_collect():
	# 查询某用户拥有的系统模块
	user = UserModel.query.get('key')
	print(user.sysmodels)  #  返回list
	# 查询系统模块拥有的用户
	sysmodel = SysModel.query.get('key')
	print(sysmodel.users) # 返回是查询集  可以继续用filter 、filter_by过滤方法
	print(list(sysmodel.usrs))  返回list
@blue.route('/deluser/')
def del_user():
	# 多对对 关联删除是级联删除,跟1对多删除不一样, 1对多, 1的一方删除数据,多的一方 对应数据外键 null
	user = UserModel.query.get('key')
	db.session.delete(user)
	db.session.commit()
	#  删除用户,对应用户在中间表collect中记录也会删除。

python之 flask 框架(1),在这里插入图片描述,第43张

插件管理 值 flask-caching

安装:

pip install flask-caching # 是连接符,不是下划线

# exts.py  插件管理
# 1、导入第三方插件
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
# 是下划线,不是连接符
from flask_caching import Cache
# 2、 初始化对象
db = SQLAlchemy()   # ORM
migrate = Migrate() # 数据迁移
cache = Cache(config = {
	'CACHE_TYPE':'simple'
})
# 3、与app对象绑定
def init_exts(app):
    db.init_app(app=app)
    migrate.init_app(app=app,db=db)
    cache.init_app(app=app)

python之 flask 框架(1),在这里插入图片描述,第44张

cache 应用

# views.py
# @ 装饰器
@blue.route('/')
@cache.cached(timeout=20)    @ 开始访问(执行里面的代码),第二个方法缓存(不执行代码),缓存有效期20s,超时,会再次访问执行里面的代码
def home():
	print('xxx')
	# 模拟访问复杂的逻辑运算
	time.sleep(5)
	return 'ZEN'

钩子函数= 中间件,类似AOP框架拦截,类似Vue中的挂载点

钩子函数(中间件 MIddleware)是执行函数(视图函数)和目标函数之前挂载的函数,框架开发者给调用方提供一个point-挂载点

是一个AOP切面编程思想

常用钩子函数

  1. before_first_request:处理第一次请求之前执行
  2. before_request: 在每次请求之前执行。通常使用这个钩子函数预处理一些比哪里,实现反爬 request.user_agent等
  3. after_request: 注册一个函数,如果没有未处理的异常抛出,在每次请求之后运行
  4. teardown_appcontext: 当app上下文被移除之后的函数,可以进行数据库的提交或者回滚

用爬虫访问 如果没有做反爬 (headers没配置 cookie、user-agent)

request.user_agent.string # python-requests/2.28.2 类似这种结果

python之 flask 框架(1),在这里插入图片描述,第45张

from .exts import *
# views.py 
#钩子函数不需要配置路由
@blue.before_request
def before():
	ip=request.remote_addr
	# cache.get()   cache.set()
	if cache.get(ip):
		# 做了拦截,不会进入视图函数
		return '禁止爬虫访问!'
	else:
		# 对每个IP配置一个缓存,1秒内不让重复访问
		cache.set(ip,'value',timeout=1)
	# string 别忘记
	if "python" in request.user_agent.string:
		return "禁止用python爬虫"
	
	
# @ 装饰器
@blue.route('/')
@cache.cached(timeout=20)    @ 开始访问(执行里面的代码),第二个方法缓存(不执行代码),缓存有效期20s,超时,会再次访问执行里面的代码
def home():
	print('xxx')
	# 模拟访问复杂的逻辑运算
	time.sleep(5)
	return 'ZEN'

python之 flask 框架(1),在这里插入图片描述,第46张

Flask 内置对象

python之 flask 框架(1),在这里插入图片描述,第47张

# views.py   钩子函数
@blue.before_request
def before():
    # Flask内置对象
    # request :   请求对象
    # session  :  会话对象
    # g    :  global 全局对象
    # current_app   Flask应用对象
    g.xx = 'yyds'

python之 flask 框架(1),在这里插入图片描述,第48张

python之 flask 框架(1),在这里插入图片描述,第49张

默认 static、templates 跟__init__.py 是平级的, app=Flask(name)

如果不是平级 要在初始化app=Flask(name,static_folder=‘路径’,template_folder=‘路径’)

python之 flask 框架(1),在这里插入图片描述,第50张

前端后端分离 值 Flask-RESTful

render_template 模板渲染 是前端和后端混在一起的

.net 中基于MVC框架的 webapi 是专门做接口的,后端的, python值flask框架提供了flask-restful包

render_template 用在views.py中的,是 # 视图函数: FBV Function Based View 路由用@装饰器

类视图 : CBV Class Based View 不需要是使用后端分离的, 不需要有views.py 不用路由@装饰器

flask-restful

安装

pip install flask-restful

# exts.py  插件管理
# 1、导入第三方插件
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
# 是下划线,不是连接符
from flask_caching import Cache
#  注意是Api
from flask_restfull import Api
# 2、 初始化对象
db = SQLAlchemy()   # ORM
migrate = Migrate() # 数据迁移
cache = Cache(config = {
	'CACHE_TYPE':'simple'
})
api = Api()
# 3、与app对象绑定
def init_exts(app):
    db.init_app(app=app)
    migrate.init_app(app=app,db=db)
    cache.init_app(app=app)
    api.init_app(app=app)

python之 flask 框架(1),在这里插入图片描述,第51张

app.py

运行前先加载__init__.py

init.py中会加载三个包

from flask import Flask

– 插件管理—

from .exts import init_exts

– 路由—

from .urls import *

在执行app.py 的Create_App(),创建flask对象, 同时给这个flask对象绑定插件

python之 flask 框架(1),在这里插入图片描述,第52张

#	app.py
# Create_APP 写在__init__.py 中,所以导入把 要 包名 APP
from APP import Create_App
app = Create_App()
if __name__ == '__main__':
    app.run(host='0.0.0.0',debug=True)
# __init__.py :初始化文件、创建Flask应用
from flask import Flask
from .exts import init_exts
from .urls import *
def Create_App():
    # 返回Flask对象
    app = Flask(__name__)
    # 初始化插件,创建的app应用,附加了哪些插件
    init_exts(app=app)
    return app
# exts.py  插件管理  三部曲
# 1、导入第三方插件
from flask_restful import Api
# 2、 初始化对象
api=Api()
# 3、与app对象绑定
def init_exts(app):
    api.init_app(app=app)

python之 flask 框架(1),在这里插入图片描述,第53张

# apis.py  接口用的
from flask_restful import Resource
# 类视图  : CBV  Class  Based View
# 视图函数: FBV   Function Based View
# 继承Resource
class StudentResource(Resource):
    def get(self):
        return '我是get 请求'
    def post(self):
        return '我是Post请求'
# urls.py   路由文件
from .exts import api
from .apis import *
#  注册路由				api.add_resource(类视图 ,路由)
api.add_resource(StudentResource,'/stu/')

python之 flask 框架(1),在这里插入图片描述,第54张

字段格式化

为了定义规范接口输出数据格式,要对字段格式化

分两步:

1、fields进行定义

2、在接口用@装饰器修饰 @marshal_with(需要返回的数据格式)

说明:

如果返回的数据在预定义的结构中存在,数据会正常返回

如果返回的数据比预定义结构中字段少,预定义的字段会呈现默认值。默认值也可以设定

如果返回的数据不在预定义结构中,则数据会被自动过滤(舍弃)

python之 flask 框架(1),在这里插入图片描述,第55张

python之 flask 框架(1),在这里插入图片描述,第56张

#	apis.py
from flask_restful import Resource,fields,marshal_with
# 输出字段格式
ret_info={
    'name':fields.String,
    'age':fields.Integer,
    'SchoolName':fields.String,
    'address':fields.String
}
# 输出字段格式
ret_fields={
    'status':fields.Integer,
    'isSecces':fields.String(default='fail'),
    #  对方用data,其实映射是password数据的值
    'data':fields.String(attribute='password'),
    'msg':fields.String,
    'studentinfo':fields.Nested(ret_info)
}
# 继承Resource
class StudentResource(Resource):
    @marshal_with(ret_fields)
    def get(self):
    	# Student是models.py 需要数据迁移
        stu=Student.query.first()
        return {
            'status':200,
            'isSecces':'ok',
            'msg':'win',
            'password':'123',
            # Student信息
            'studentinfo':stu
        }
ret_fields2={
    'status':fields.Integer,
    'isSecces':fields.String(default='fail'),
    #  对方用data,其实映射是password数据的值
    'data':fields.String(attribute='password'),
    'msg':fields.String,
    'studentinfo':fields.List(fields.Nested(ret_info))
}
class StudentALLResource(Resource):
    @marshal_with(ret_fields2)
    def get(self):
    	# Student是models.py 需要数据迁移
        stu=Student.query.all()
        return {
            'status':200,
            'isSecces':'ok',
            'msg':'win',
            'password':'123',
            # Student信息
            'studentinfo':stu
        }
"""
# 返回的结果
{
    "status": 200,
    "isSecces": "ok",
    "data": "123",
    "msg": "win",
    "studentinfo":[
	    {
			"name":"ZEN",
			"age":33,
			"SchoolName":"家里蹲",
			"address":"中国"
		},   {
			"name":"ZEN1",
			"age":331,
			"SchoolName":"家里蹲1",
			"address":"中国1"
		}
	]
}
"""  
ret_url={
	'name':fields.String,
	'url':fields.url(endpoint='id',absolute=False)
}
class urlResource(Resource):
    @marshal_with(ret_url)
    def get(self):    	
        return {
            'name':200,
            'url':'/'                   
        }
"""
# 返回的结果
{
    "status": 200,
    "isSecces": "ok",
    "data": "123",
    "msg": "win",
    "studentinfo":{
		"name":"ZEN",
		"age":33,
		"SchoolName":"家里蹲",
		"address":"中国"
	}
}
"""
# urls.py   路由文件
from .exts import api
from .apis import *
#  路由
api.add_resource(StudentResource,'/')
api.add_resource(urlResource,'/url/',endpoint='id')
api.add_resource(StudentALLResource,'/stuall/')

参数解析

可以不通过post : request.form 或 get : request.args 获取参数。而是通过reqparse.RequestParser 来解析

# apis.py 
from flask_restful import Resource,reqparse
# 参数转换器
parser = reqparse.RequestParser()
parser.add_argument('name',type=str)
parser.add_argument('info',type=str,action='append') # 支持多个info
parser.add_argument('cookiex',type=str,location='cookies') # 获取cookies中数据
class StudentResource(Resource):
    def get(self):
        # 获取参数
        args=parser.parse_args()
        name=args.get('name')
        return {
            'key':name
        }
# spider.py  爬虫测试
import requests
request = requests.get('http://127.0.0.1:5000/',
                       json={
                           'name':'23',
                           'info':['123','erew']
                       },
                       headers={
                           'Content-Type':'application/json'
                       }
                       )
print(request.text)