网站首页 > 技术文章 正文
参考文档:
- flask官方文档:https://flask.palletsprojects.com/en/1.1.x
- jinja2官方文档:https://jinja.palletsprojects.com/en/2.11.x/templates/
基本使用
简介
安装
搭建环境
mkdir flask_demo
cd flask_demo
python -m venv venv
source venv/bin/activate
安装flask
pip install Flask
入门案例
最小的flask应用
# 导入flask
from flask import Flask
# 创建app
app = Flask(__name__)
# 创建路由
@app.route('/')
def hello_world():
return 'Hello, lxgzhw!'
if __name__ == '__main__':
app.run(debug=True)
运行方式
python main.py
添加路由
示例
# 添加一个新的路由
@app.route('/hello')
def hello():
return {"name":"lxgzhw","age":22}
完整代码
# 导入flask
from flask import Flask
# 创建app
app = Flask(__name__)
# 创建路由
@app.route('/')
def hello_world():
return 'Hello, lxgzhw!'
# 添加一个新的路由
@app.route('/hello')
def hello():
return {"name":"lxgzhw","age":22}
if __name__ == '__main__':
app.run(debug=True)
常用配置
配置静态文件目录
说明:默认静态文件目录是根目录下的static文件夹,或模块下的static文件夹
注意
- 该文件夹需要我们手动创建
- 该文件夹是相对于main.py的位置而言的,main.py所在目录的static文件夹会被作为静态文件夹使用
请求
总结
flask中如何处理请求
- 把请求封装在了request对象中,从request中,我们可以获取post提交的表单数据get提交的请求参数文件上传的文件cookie
响应
添加自定义响应头
核心代码
# 构造一个响应对象
resp = make_response(render_template('404.html'), 404)
# 给响应对象的headers属性,添加一个键值对(像字典)
resp.headers['X-Something'] = 'lxgzhw'
# 返回响应对象
return resp
全部代码
from flask import Flask, make_response
from flask import abort, redirect, url_for
from flask import render_template
app = Flask(__name__)
@app.route('/')
def index():
# 重定向,跳转到登录页面
return redirect(url_for('login'))
@app.route('/login')
def login():
# 直接返回错误信息
# 401 Unauthorized 权限校验未通过
# abort(401)
# 200 301 404 500
# abort(404)
abort(404)
# 全局错误处理器
@app.errorhandler(404)
def page_not_found(error):
resp = make_response(render_template('404.html'), 404)
resp.headers['X-Something'] = 'lxgzhw'
return resp
if __name__ == '__main__':
app.run(debug=True)
返回json
如果我们返回的是一个字典,flask会自动帮我们把字典转换为json字符串,然后响应给前端
from flask import Flask
app = Flask(__name__)
@app.route("/")
def me_api():
user = {
'username': 'lxgzhw',
'age': 22,
'gender': '男'
}
# 返回一个字典
return user
if __name__ == '__main__':
app.run(debug=True)
如果我们响应的是列表嵌套字典的结构,我们可以使用jsonify函数,将其转化为json数据字符串
from flask import Flask, jsonify
app = Flask(__name__)
@app.route("/")
def users_api():
# 返回的是一个列表嵌套字典,也能够使用jsonify转换为json格式
users = [
{'name': f"root{i}", 'age': 22, 'gender': '男'}
for i in range(20)
]
return jsonify(users)
if __name__ == '__main__':
app.run(debug=True)
路由
路径参数
示例1:安全的路径参数
# markupsafe 安全标记
from markupsafe import escape
# 定义了一个路由
@app.route('/user/<username>')
def show_user_profile(username):# 将username原封不动的搬下来,表示这是一个路径参数
# 返回路径参数
# 防止黑客注入攻击
return '你输入的用户名是 %s' % escape(username)
示例2:将路径参数转换为int类型
# <int:post_id>,说明post_id是一个int类型
@app.route('/post/<int:post_id>')
def show_post(post_id):
# 打印路径参数
return '你输入的数字是: %d' % post_id
示例3:将路径参数转换为路径类型
# path:subpath,转换成路径类型
@app.route('/path/<path:subpath>')
def show_subpath(subpath):
# 打印
return '你输入的路径是: %s' % escape(subpath)
参考:flask支持的所有路径参数转换类型
路径构造器
url_for的基本用法
- 能够根据路由函数的名称,反向找到该路由函数对应的“路由路径”
print(url_for('index'))#index是路由函数名称:解析得到url路径
print(url_for('login'))
- 能够传递查询参数
# url_for可以添加其他的参数
# 如果说,没有路径参数:则,添加的参数会被作为get查询参数传递
print(url_for('login', hello='world'))
- 能够指定路径参数
# 可以替换路径参数
print(url_for('profile', username='lxgzhw'))
完整案例
from flask import Flask, url_for
from markupsafe import escape
app = Flask(__name__)
# 首页路由
@app.route('/')
def index():
return 'index'
# 登录路由
@app.route('/login')
def login():
return 'login'
# 用户/用户名
@app.route('/login/<username>')
def profile(username):
return '{}\'s profile'.format(escape(username))
# 测试
with app.test_request_context():#在每次flask重新加载的时候,都会执行
print("-----------------------------")
print(url_for('index'))#index是路由函数名称:解析得到url路径
print(url_for('login'))
# url_for可以添加其他的参数
# 如果说,没有路径参数:则,添加的参数会被作为get查询参数传递
print(url_for('login', hello='world'))
# 可以替换路径参数
print(url_for('profile', username='lxgzhw'))
if __name__ == '__main__':
app.run(debug=True)
HTTP方法
常见的HTTP方法有
- GET:查询
- PUT:查询
- POST:传数据,一般用来新增数据
- PATCH:修改
- DELETE:删除
规定路由支持哪些方法
from flask import Flask,request
app = Flask(__name__)
# 登录的路由:支持GET请求和POST请求
@app.route('/login', methods=['GET', 'POST'])
def login():
# 如果是POST请求
if request.method == 'POST':
return "这是一个POST请求"
# 如果是GET请求
else:
return "这是一个GET请求"
if __name__ == '__main__':
app.run(debug=True)
重定向与错误
from flask import Flask
from flask import abort, redirect, url_for
app = Flask(__name__)
@app.route('/')
def index():
# 重定向,跳转到登录页面
return redirect(url_for('login'))
@app.route('/login')
def login():
# 直接返回错误信息
# 401 Unauthorized 权限校验未通过
# abort(401)
# 200 301 404 500
# abort(404)
abort(500)
if __name__ == '__main__':
app.run(debug=True)
模板
基本使用
第一步:在视图函数中渲染模板
from flask import Flask, request
from flask import render_template
app = Flask(__name__)
@app.route('/')
@app.route('/index')
def hello():
return render_template('index.html', name="理想国真惠玩")
if __name__ == '__main__':
app.run(debug=True)
第二步:编写templates/index.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
<title>Bootstrap 101 Template</title>
<!-- Bootstrap -->
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css"
rel="stylesheet"
/>
<!-- HTML5 shim 和 Respond.js 是为了让 IE8 支持 HTML5 元素和媒体查询(media queries)功能 -->
<!-- 警告:通过 file:// 协议(就是直接将 html 页面拖拽到浏览器中)访问页面时 Respond.js 不起作用 -->
<!--[if lt IE 9]>
<script src="https://cdn.jsdelivr.net/npm/html5shiv@3.7.3/dist/html5shiv.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/respond.js@1.4.2/dest/respond.min.js"></script>
<![endif]-->
</head>
<body>
<h1>你好,世界!</h1>
<p>欢迎您:{{name}}</p>
<!-- jQuery (Bootstrap 的所有 JavaScript 插件都依赖 jQuery,所以必须放在前边) -->
<script src="https://cdn.jsdelivr.net/npm/jquery@1.12.4/dist/jquery.min.js"></script>
<!-- 加载 Bootstrap 的所有 JavaScript 插件。你也可以根据需要只加载单个插件。 -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/js/bootstrap.min.js"></script>
</body>
</html>
在flask模板中渲染变量的方式
{{ name }}
登录案例
目录结构
main.py
templates
index.html
login.html
main.py
from flask import Flask, request
from flask import render_template
app = Flask(__name__)
@app.route('/')
@app.route('/index')
def hello():
return render_template('index.html', name="理想国真惠玩")
@app.route('/login', methods=['POST', 'GET'])
def login(): # 登录
error = "" # 错误信息
if request.method == 'POST': # post请求
# 校验用户名和密码
username = request.form['username']
password = request.form['password']
print(f"用户传过来的用户名是:{username},密码是:{password}")
if username == 'lxgzhw' and password == 'lxgzhw':
return render_template("index.html", name=username)
else:
# 记录错误信息
error = '用户名或密码错误'
# GET请求 POST请求失败
return render_template('login.html', error=error)
if __name__ == '__main__':
app.run(debug=True)
index.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
<title>Bootstrap 101 Template</title>
<!-- Bootstrap -->
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css"
rel="stylesheet"
/>
<!-- HTML5 shim 和 Respond.js 是为了让 IE8 支持 HTML5 元素和媒体查询(media queries)功能 -->
<!-- 警告:通过 file:// 协议(就是直接将 html 页面拖拽到浏览器中)访问页面时 Respond.js 不起作用 -->
<!--[if lt IE 9]>
<script src="https://cdn.jsdelivr.net/npm/html5shiv@3.7.3/dist/html5shiv.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/respond.js@1.4.2/dest/respond.min.js"></script>
<![endif]-->
</head>
<body>
<h1>你好,世界!</h1>
<p>欢迎您:{{name}}</p>
<div>
<ul>
<li>
<a href="/login">登录</a>
</li>
</ul>
</div>
<!-- jQuery (Bootstrap 的所有 JavaScript 插件都依赖 jQuery,所以必须放在前边) -->
<script src="https://cdn.jsdelivr.net/npm/jquery@1.12.4/dist/jquery.min.js"></script>
<!-- 加载 Bootstrap 的所有 JavaScript 插件。你也可以根据需要只加载单个插件。 -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/js/bootstrap.min.js"></script>
</body>
</html>
login.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
<title>Bootstrap 101 Template</title>
<!-- Bootstrap -->
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css"
rel="stylesheet"
/>
<!-- HTML5 shim 和 Respond.js 是为了让 IE8 支持 HTML5 元素和媒体查询(media queries)功能 -->
<!-- 警告:通过 file:// 协议(就是直接将 html 页面拖拽到浏览器中)访问页面时 Respond.js 不起作用 -->
<!--[if lt IE 9]>
<script src="https://cdn.jsdelivr.net/npm/html5shiv@3.7.3/dist/html5shiv.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/respond.js@1.4.2/dest/respond.min.js"></script>
<![endif]-->
</head>
<body>
<div class="container-fluid">
<div class="row">
<div class="col-md-6 col-md-offset-3">
<h1>用户登录</h1>
<br />
<div class="alert alert-danger" role="alert">{{error}}</div>
<br />
<form method="post" action="/login">
<div class="form-group">
<label for="username">用户名</label>
<input
type="text"
class="form-control"
id="username"
name="username"
/>
</div>
<div class="form-group">
<label for="password">密码</label>
<input
type="password"
class="form-control"
id="password"
name="password"
/>
</div>
<button type="submit" class="btn btn-default">立即登录</button>
</form>
</div>
</div>
</div>
<!-- jQuery (Bootstrap 的所有 JavaScript 插件都依赖 jQuery,所以必须放在前边) -->
<script src="https://cdn.jsdelivr.net/npm/jquery@1.12.4/dist/jquery.min.js"></script>
<!-- 加载 Bootstrap 的所有 JavaScript 插件。你也可以根据需要只加载单个插件。 -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/js/bootstrap.min.js"></script>
</body>
</html>
运行方式
python main.py
访问:http://127.0.0.1:5000
提示:如何获取get传递的参数
searchword = request.args.get('key', '')
文件上传
main.py
from flask import Flask, request
from flask import render_template
app = Flask(__name__)
@app.route('/', methods=['GET', 'POST'])
def upload_file():
if request.method == 'POST':
# 获取文件对象
f = request.files['file_name']
# 保存文件
f.save('./111.jpg')
return render_template('upload.html')
if __name__ == '__main__':
app.run(debug=True)
upload.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
<title>Bootstrap 101 Template</title>
<!-- Bootstrap -->
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css"
rel="stylesheet"
/>
<!-- HTML5 shim 和 Respond.js 是为了让 IE8 支持 HTML5 元素和媒体查询(media queries)功能 -->
<!-- 警告:通过 file:// 协议(就是直接将 html 页面拖拽到浏览器中)访问页面时 Respond.js 不起作用 -->
<!--[if lt IE 9]>
<script src="https://cdn.jsdelivr.net/npm/html5shiv@3.7.3/dist/html5shiv.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/respond.js@1.4.2/dest/respond.min.js"></script>
<![endif]-->
</head>
<body>
<div class="container-fluid">
<div class="row">
<div class="col-md-6 col-md-offset-3">
<h1>文件上传</h1>
<br />
<br />
<form method="post" action="/" enctype="multipart/form-data">
<div class="form-group">
<label for="upload">文件上传</label>
<input type="file" id="upload" name="file_name" />
<p class="help-block">请选择要上传的文件</p>
</div>
<button type="submit" class="btn btn-default">立即上传</button>
</form>
</div>
</div>
</div>
<!-- jQuery (Bootstrap 的所有 JavaScript 插件都依赖 jQuery,所以必须放在前边) -->
<script src="https://cdn.jsdelivr.net/npm/jquery@1.12.4/dist/jquery.min.js"></script>
<!-- 加载 Bootstrap 的所有 JavaScript 插件。你也可以根据需要只加载单个插件。 -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/js/bootstrap.min.js"></script>
</body>
</html>
注意
- 前端上传文件,form表单必须添加enctype="multipart/form-data"
- 一定要定义上传文件的名称<input type="file" id="upload" name="file_name" />
- 后端通过文件名称获取文件对象f = request.files['file_name']
- 调用文件的保存方法可以直接保存文件f.save('./111.jpg')
常用语法
if语句
{% if name %}
<h1>Hello {{ name }}!</h1>
{% else %}
<h1>Hello, World!</h1>
{% endif %}
for语句
{% with messages = get_flashed_messages() %}
{#如果存在#}
{% if messages %}
{#打印所有的闪现消息#}
<ul class=flashes>
{% for message in messages %}
<li>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
{% endwith %}
动态生成url
<a href="{{ url_for('login') }}">登录</a>
模板继承
模板继承主要用于解决代码重复问题,比如头部,底部,左侧,菜单等,可能大多数页面都会使用,就可以添加在模板中,被其他的html继承。
这里有个简单的案例
templates/layout.html
<!doctype html>
<title>AIPyGo</title>
<h1>这里是头部内容</h1>
{#获取所有闪现消息#}
{% with messages = get_flashed_messages() %}
{#如果存在#}
{% if messages %}
{#打印所有的闪现消息#}
<ul class=flashes>
{% for message in messages %}
<li>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
{% endwith %}
{#用来定义一个块,这个块能够被继承,实现,重写#}
{% block body %}{% endblock %}
<div>这里是底部的内容</div>
templates/index.html
{#继承layout.html#}
{% extends "layout.html" %}
{#重写body代码块#}
{% block body %}
<h3>这里是重写的内容</h3>
<ul>
<li>
<a href="{{ url_for('login') }}">登录</a>
</li>
</ul>
{% endblock %}
main.py
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/')
def index():
return render_template('index.html')
@app.route('/login')
def login():
return "登录页面"
if __name__ == '__main__':
app.run(debug=True)
运行方法
python main.py
全局变量
cookie
设置cookie
from flask import make_response
@app.route('/set_cookie')
def set_cookie():
# 创建一个响应对象
resp = make_response(render_template('index.html'))
# 响应对象上,有一个set_cookie的方法:当字典中,set(键,值)
resp.set_cookie('username', '理想国真惠玩')
# 返回响应
return resp
读取cookie
from flask import request
@app.route('/')
def read_cookie():
# session,只在服务器端可以访问
# 缺点:很不安全 auth, cookie 只读:禁止JavaScript读取
# 从cookie当中读取
# cookie可以当做是字典来用, get [] 遍历
username = request.cookies.get('username')
return render_template('index.html', name=username)
session
基本使用
# 导入
from flask import session
# 增加
session[key] = value
# 获取
value = session.get(key)
# 删除
session.pop(key, None)
完整案例
from flask import Flask, session, redirect, url_for, request, render_template
from markupsafe import escape
app = Flask(__name__)
# 生成了一个秘钥
# 生成方法:python -c 'import os; print(os.urandom(16))'
app.secret_key = b'_5#y2L"F4Q8z\n\xec]/'
@app.route('/')
def index():
# 如果session中有username这个key
# 取session
username = session.get('username')
if username:
return render_template('index.html', name=username)
return redirect(url_for('login'))
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
# 存储session
session['username'] = request.form['username']
# 跳转到首页: index指的是 index函数
return redirect(url_for('index'))
# return redirect('/')
return render_template('login.html')
@app.route('/logout')
def logout():
# 删除session
session.pop('username', None)
# 跳转到首页
return redirect(url_for('login'))
if __name__ == '__main__':
app.run(debug=True)
flash
传递:参数1是闪现内容,参数2是闪现分类
flash(u'Invalid password provided', 'error')
获取
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
<ul class=flashes>
{% for category, message in messages %}
<li class="{{ category }}">{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
{% endwith %}
过滤
{% with errors = get_flashed_messages(category_filter=["error"]) %}
{% if errors %}
<div class="alert-message block-message error">
<a class="close" href="#">×</a>
<ul>
{%- for msg in errors %}
<li>{{ msg }}</li>
{% endfor -%}
</ul>
</div>
{% endif %}
{% endwith %}
错误处理
全局错误处理器
from flask import Flask
from flask import abort, redirect, url_for
from flask import render_template
app = Flask(__name__)
@app.route('/')
def index():
# 重定向,跳转到登录页面
return redirect(url_for('login'))
@app.route('/login')
def login():
# 直接返回错误信息
# 401 Unauthorized 权限校验未通过
# abort(401)
# 200 301 404 500
# abort(404)
abort(404)
# 全局错误处理器
@app.errorhandler(404)
def page_not_found(error):
return render_template('404.html'), 404
if __name__ == '__main__':
app.run(debug=True)
日志
基本使用
from flask import Flask
app = Flask(__name__)
app.logger.info('消息级别的日志')
app.logger.debug('调试级别的日志')
# 默认只打印warning以上级别的日志到控制台
app.logger.warning('注意级别的日志 (%d 个错误)', 42)
app.logger.error('错误级别日志')
if __name__ == '__main__':
app.run(debug=True)
猜你喜欢
- 2024-10-15 Python Flask Web表单(flask form表单)
- 2024-10-15 如何在Flask应用程序中使用JSON Web Tokens进行安全认证
- 2024-10-15 综合指南:将 Flask 与 MongoDB 结合使用
- 2024-10-15 python-flask搭建平台,HTML+CSS+JS写前端的web全栈-动画轮播
- 2024-10-15 Flask 表单处理(flask formdata)
- 2024-10-15 三、flask博客项目实战-之表单(flask 表单)
- 2024-10-15 flask python web开发的简单易学框架
- 2024-10-15 Flask-APScheduler使用教程(flask apscheduler)
- 2024-10-15 flask 项目中使用 bootstrapFileInput(进阶篇)
- 2024-10-15 基于flask框架展示数据可视化的一次尝试
- 02-21走进git时代, 你该怎么玩?_gits
- 02-21GitHub是什么?它可不仅仅是云中的Git版本控制器
- 02-21Git常用操作总结_git基本用法
- 02-21为什么互联网巨头使用Git而放弃SVN?(含核心命令与原理)
- 02-21Git 高级用法,喜欢就拿去用_git基本用法
- 02-21Git常用命令和Git团队使用规范指南
- 02-21总结几个常用的Git命令的使用方法
- 02-21Git工作原理和常用指令_git原理详解
- 最近发表
- 标签列表
-
- cmd/c (57)
- c++中::是什么意思 (57)
- sqlset (59)
- ps可以打开pdf格式吗 (58)
- phprequire_once (61)
- localstorage.removeitem (74)
- routermode (59)
- vector线程安全吗 (70)
- & (66)
- java (73)
- org.redisson (64)
- log.warn (60)
- cannotinstantiatethetype (62)
- js数组插入 (83)
- resttemplateokhttp (59)
- gormwherein (64)
- linux删除一个文件夹 (65)
- mac安装java (72)
- reader.onload (61)
- outofmemoryerror是什么意思 (64)
- flask文件上传 (63)
- eacces (67)
- 查看mysql是否启动 (70)
- java是值传递还是引用传递 (58)
- 无效的列索引 (74)