参考: https://dormousehole.readthedocs.io/en/2.1.2/tutorial/factory.html
随便编写一个py文件,如test.py
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello_world():
return "Hello Flask!
"
如果没有写
if __name__ == '__main__':
app.run()
方式一:
修为为app.py
或者wsgi.py
方式二:
使用命令flask --app test.py run
方式三:
加上
if __name__ == '__main__':
app.run()
url_for()
将函数名转为对应的url请求地址
from flask import url_for
app = Flask(__name__)
@app.route('/')
def index():
return 'index'
@app.route('/login')
def login():
return 'login'
@app.route('/user/' )
def profile(username):
return f'{username}\'s profile'
with app.test_request_context():
print(url_for('index'))
print(url_for('login'))
print(url_for('login', next='/'))
# 对于变量类型的url,需要在第二个参数位置传递参数名
print(url_for('profile', username='John Doe'))
if __name__ == '__main__':
app.run(debug=True)
app.test_request_context()有啥用?
用于测试使用, 例如测试发送一个请求地址为
/login
,请求方式为GET
的请求with app.test_request_context('/login', method='GET'): print("测试请求到来...") # 对测试的请求地址和方式进行断言,如果断言不通过,就会报错 assert request.path == '/login' assert request.method == 'GET'
在html中使用
{{url_for("参数1","参数2")}}
- 参数1: 表示static静态文件目录
- 参数2: 表示要引入的文件, 格式: filename=“xxx”
说明: 文件层级结构为
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
测试html
<img src="/static/test.jpg" alt="">
body>
html>
关键方法:
Markup()
from markupsafe import Markup
request.args
获取url后
?
号后面的参数如: http://127.0.0.1:5000/login?info=shanghai&address=BJ使用request.args获取到的是
info=shanghai&address=BJ
这部分数据无论此时的请求方式是
POST
还是GET
,request.args获取到的永远都是url中?
后面的那部分request.form
- 获取的是body中的数据(如form表单提交)
- 无论此时的请求方式是
GET
还是POST
,request.form获取的永远都是body中的数据
from flask import Flask, request
app = Flask(__name__)
@app.route("/login", methods=['GET', 'POST'])
def login():
print(request.form)
print(request.args)
return "hello!"
if __name__ == '__main__':
app.run(debug=True)
展示GET请求Params部分请求参数 | 展示GET请求Body部分请求参数 |
---|---|
响应结果如下:
ImmutableMultiDict([('sex', 'nan')])
ImmutableMultiDict([('info', 'shanghai'), ('address', 'BJ')])
展示POST请求Params部分请求参数 | 展示POST请求Body部分请求参数 |
---|---|
响应结果如下:
ImmutableMultiDict([('sex', 'nan')])
ImmutableMultiDict([('info', 'shanghai'), ('address', 'BJ')])
from flask import Flask, request, render_template, make_response, redirect, abort
from werkzeug.utils import secure_filename
app = Flask(__name__)
@app.route("/")
def index():
# 重定向
return redirect(url_for("showInfo"))
@app.route("/info")
def showInfo():
return "info信息..."
if __name__ == '__main__':
app.run(debug=True)
from flask import Flask, request, render_template, make_response, redirect, abort
from werkzeug.utils import secure_filename
app = Flask(__name__)
@app.route("/")
def index():
abort(404)
if __name__ == '__main__':
app.run(debug=True)
from flask import Flask, request, render_template, make_response, redirect, abort,url_for
from werkzeug.utils import secure_filename
app = Flask(__name__)
@app.route("/")
def index():
abort(404)
"""
当访问 http://localhost:5000/ 时,会先走index方法, index方法终止,并响应404, 404码会被标注了@app.errorhandler(404)注解的方法捕获,最终走自定义的404页面
"""
@app.errorhandler(404)
def page_not_found(error):
# 自定义错误页面
return render_template("404.html",error=error),404
if __name__ == '__main__':
app.run(debug=True)
from flask import Flask, session, redirect, url_for, request
app = Flask(__name__)
"""
设置 secret_key,可以使用如下方式生成:
import secrets
print(secrets.token_hex())进行生成
"""
app.secret_key = b'_5#y2L"F4Q8z\n\xec]/'
@app.route('/')
def index():
if 'username' in session:
return f'Logged in as {session["username"]}'
return 'You are not logged in'
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
session['username'] = request.form['username']
return redirect(url_for('index'))
return '''
'''
@app.route('/logout')
def logout():
# remove the username from the session if it's there
session.pop('username', None)
return redirect(url_for('index'))
if __name__ == '__main__':
app.run(debug=True)
app.logger
from flask import Flask
app = Flask(__name__)
@app.route('/')
def index():
app.logger.debug("debug信息...")
app.logger.warning("提醒信息")
app.logger.error("出错了..")
return "hello"
if __name__ == '__main__':
app.run(debug=True)
class Flask(Scaffold):
# ...省略...
# 构造方法如下,着重看下初始化参数含义:
def __init__(
self,
import_name: str,
static_url_path: t.Optional[str] = None,
static_folder: t.Optional[t.Union[str, os.PathLike]] = "static",
static_host: t.Optional[str] = None,
host_matching: bool = False,
subdomain_matching: bool = False,
template_folder: t.Optional[t.Union[str, os.PathLike]] = "templates",
instance_path: t.Optional[str] = None,
instance_relative_config: bool = False,
root_path: t.Optional[str] = None,
):
参数说明
import_name: 值flask应用所在的包名或模块名, 一般为 __name__
static_folder: 默认值为 static
, 指的是静态文件所在的目录; 如改为assets
,则需要将静态资源文件css/js/images等放到assets
目录下
static_url_path: 指的是会在页面静态资源(图片,css,js)文件展示的时候,会在路径前面追加上指定的字符;
举例: 在页面显示一张图片时,html代码为
渲染到页面上后,为 http://localhost:5000/test.jpg
; 如果设置了: static_url_path=“/abc/def”, 则页面渲染后变成了 http://localhost:5000/abc/def/test.jpg
template_folder: 指定模板html的路径,默认为templates
Flask框架的蓝图(Blueprint)类似与PHP的控制器,如用户控制器UserController.php,商品控制器GoodsController.php; 从对应关系上来说, 一个蓝图(Blueprint)对应一个控制器; 如果没有蓝图概念的话,估计需要将所有的处理页面请求的逻辑代码写到一个py文件(如: main.py)中, 有了蓝图以后就可以对不同的请求进行拆分了: 用户模块的前端请求逻辑写到用户蓝图(如: User.py)中; 商品模块的前端请求逻辑写到商品蓝图(如: Goods.py)中. 最后在将写好的蓝图注册到主应用(如: main.py, 主应用就是写有
app=Flask(__name__)
并启动(app.run()
)了的那个py文件)中就行了
举例: 有两个模块: 一个是用户鉴权模块,需要登录和注册(auth.py); 另外一个是网站的其他普通页面(main.py)
auth.py 是一个蓝图
from flask import Flask, Blueprint, render_template
auth_bp = Blueprint("auth", __name__, url_prefix="/auth")
@auth_bp.route("/register")
def user_register():
print("用户注册...")
return render_template("register.html")
@auth_bp.route("/login")
def user_login():
print("用户登录...")
return render_template("login.html")
"""
@auth_bp.before_app_request注解在其他方法之前先调用, 可以用它做统一的校验,类似与`前置方法`,
类似的注解, Flask框架提供的还有很多
"""
@auth_bp.before_app_request
def check():
print("Before request 被调用了...")
main.py 应用实例文件
from flask import Flask, render_template
import auth
app = Flask(__name__)
@app.route("/")
@app.route("/index")
def index():
print("网站首页...")
return render_template("index.html")
if __name__ == '__main__':
"""在服务启动前将auth.py蓝图注册进来"""
from auth import auth_bp
app.register_blueprint(auth_bp)
app.run(debug=True)
浏览器访问: http://localhost:5000, 响应结果如下:
index首页面
浏览器访问: http://localhost:5000/auth/login, 响应结果如下:
登录页面
浏览器访问: http://localhost:5000/auth/register, 响应结果如下:
注册页面
使用蓝图起到了不同的逻辑分文件编写的作用
参考: https://dormousehole.readthedocs.io/en/2.1.2/tutorial/install.html
大致过程如下:
在开发完成的项目根目录中书写setup.py
文件和MANIFEST.in
文件
例如你可以按照下列的demo样例进行书写, 详细的书写规则请百度搜索:
setup.py
from setuptools import find_packages, setup
setup(
name='MyFlaskProject',
version='1.0.0',
packages=find_packages(),
include_package_data=True,
zip_safe=False,
install_requires=[
'flask',
],
)
MANIFEST.in
:
include MyFlaskProject/myData.sql
graft MyFlaskProject/static
graft MyFlaskProject/templates
global-exclude *.pyc
执行python setup.py bdist_wheel
命令进行打包项目, 打包完成后,会在根目录下生成文件 /dist/MyFlaskProject-1.0.0-py3-none-any.whl
, 该文件就是项目打包后的压缩文件
将该文件MyFlaskProject-1.0.0-py3-none-any.whl
发送到其他有python开发环境的电脑上, 直接进行pip install MyFlaskProject-1.0.0-py3-none-any.whl
就可以安装使用了
在本地开发的时候可以使用内置的web服务器,但是到真正生产环境的时候不可以这么干,需要使用专业的服务器:如waitress
具体使用方式请百度
相关指令如:
pip install waitress waitress-serve --call 'MyFlaskProject:create_app' Serving on http://0.0.0.0:8080
对于一段普通的 html
渲染到html模板的时候, 默认会原样输出, 如下
import flask
from flask import Flask, render_template, flash, render_template_string, Markup
app = Flask(__name__)
@app.route("/")
@app.route("/index")
def index():
"""该段html代码会直接输出在html页面上"""
data = "点击查看详情"
return render_template("index.html", data=data)
if __name__ == '__main__':
app.run(debug=True)
html页面如下:
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<h1>index首页面h1>
{{data}}
body>
html>
浏览器输出如下:
要想在html页面解析这段html,方法有三种:
① python代码中使用Markup()
import flask
from flask import Flask, render_template, flash, render_template_string, Markup
app = Flask(__name__)
@app.route("/")
@app.route("/index")
def index():
"""该段html代码会直接输出在html页面上"""
data = "点击查看详情"
return render_template("index.html", data=Markup(data))
if __name__ == '__main__':
app.run(debug=True)
页面如下:
② html页面中是有|safe过滤器
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<h1>index首页面h1>
{{data|safe}}
body>
html>
页面如下:
③ html中关闭转义设置
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<h1>index首页面h1>
{% autoescape false %}
{{data}}
{% endautoescape %}
body>
html>
页面如下:
方式一:
使用@app.template_filter(“xxx”)注解来定义
import flask
from flask import Flask, render_template, flash, render_template_string, Markup
app = Flask(__name__)
@app.route("/")
@app.route("/index")
def index():
data = "点击查看详情"
return render_template("index.html", data=data, target_str="javaAndPhp")
"""
使用@app.template_filter注解来进行自定义过滤器
"""
@app.template_filter("my_reverse_filter")
def reverse_filter(s):
return s[::-1]
if __name__ == '__main__':
app.run(debug=True)
在html中使用该过滤器
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<h1>index首页面h1>
{{target_str|my_reverse_filter}}
body>
html>
页面显示:
方式二:
在app启动前进使用
app.jinja_env.filters['xxx1'] = xxx2
进行注册
import flask
from flask import Flask, render_template, flash, render_template_string, Markup
app = Flask(__name__)
app.secret_key = "ABC"
@app.route("/")
@app.route("/index")
def index():
data = "点击查看详情"
return render_template("index.html", data=data, target_str="javaAndPhp")
def test_filter(s):
return s[::-1]
if __name__ == '__main__':
# 注册自定义的过滤器
app.jinja_env.filters['my_reverse_filter'] = test_filter
app.run(debug=True)
在html中使用该过滤器
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<h1>index首页面h1>
{{target_str|my_reverse_filter}}
body>
html>
界面显示如下:
环境处理器有点像过滤器
用法一: 向模板页面传递变量
使用
@app.context_processor
注解传递变量; 当访问一个url时, 被该注解标注的方法会自动执行,并将变量传递到html模板页面
from flask import Flask, render_template, flash, render_template_string, Markup
app = Flask(__name__)
@app.route("/")
@app.route("/index")
def index():
data = "点击查看详情"
return render_template("index.html")
"""
使用 @app.context_processor 向模板传递变量
"""
@app.context_processor
def my_env_param():
print("被调用了...")
return dict(user="ZhangSan and LiSi")
if __name__ == '__main__':
app.run(debug=True)
html页面如下:
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<h1>index首页面h1>
{{user}}
body>
html>
响应如下:
用法二: 向html模板页面传递Python函数或者自定义函数
这个用法非常广泛, 可以传递自定义函数来作为过滤器使用
也可以传递python内置函数(因为在模板html页面中直接使用python内置函数会有受限, 很多内置函数没法直接使用)
from flask import Flask, render_template, flash, render_template_string, Markup
from datetime import date
app = Flask(__name__)
@app.route("/")
@app.route("/index")
def index():
data = "点击查看详情"
return render_template("index.html")
"""
使用 @app.context_processor 向模板传递python内置函数 datetime.date.today(); 该函数在html模板中不能直接使用,通过
这种方式就可以传递到html模板中进行使用了
"""
@app.context_processor
def my_env_param():
return dict(my_date=datetime.date.today())
if __name__ == '__main__':
app.run(debug=True)
html页面内容如下:
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<h1>index首页面h1>
{{my_date}}
body>
html>
响应结果如下: