helloworld
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
return 'Hello, World!'
URL参数
@app.route('/user/<username>')
def show_user_profile(username):
# show the user profile for that user
return 'User %s' % escape(username)
@app.route('/post/<int:post_id>')
def show_post(post_id):
# show the post with the given id, the id is an integer
return 'Post %d' % post_id
@app.route('/path/<path:subpath>')
def show_subpath(subpath):
# show the subpath after /path/
return 'Subpath %s' % escape(subpath)
路由
projects的 URL 是中规中矩的,尾部有一个斜杠,看起来就如同一个文件夹。 访问一个没有斜杠结尾的 URL 时 Flask 会自动进行重定向,帮你在尾部加上一个斜杠。
about的 URL 没有尾部斜杠,因此其行为表现与一个文件类似。如果访问这个 URL 时添加了尾部斜杠就会得到一个 404 错误。这样可以保持 URL 唯一,并帮助 搜索引擎避免重复索引同一页面。
@app.route('/projects/')
def projects():
return 'The project page'
@app.route('/about')
def about():
return 'The about page'
# route源码
def route(self, rule, **options):
def decorator(f):
endpoint = options.pop("endpoint", None)
self.add_url_rule(rule, endpoint, f, **options)
return f
return decorator
如果为提供
endpoint则使用视图函数的名称作为endpoint
def _endpoint_from_view_func(view_func):
"""Internal helper that returns the default endpoint for a given
function. This always is the function name.
"""
assert view_func is not None, "expected view func if endpoint is not provided."
return view_func.__name__
URL构建
url_for()函数用于构建指定函数的 URL。它把函数名称作为第一个 参数。它可以接受任意个关键字参数,每个关键字参数对应 URL 中的变量。未知变量 将添加到 URL 中作为查询参数
url_for()
HTTP方法
Web 应用使用不同的 HTTP 方法处理 URL 。当你使用 Flask 时,应当熟悉 HTTP 方法。 缺省情况下,一个路由只回应
GET请求。 可以使用route()装饰器的methods参数来处理不同的 HTTP 方法:
from flask import request
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
return do_the_login()
else:
return show_the_login_form()
静态文件
url_for('static', filename='style.css')
# 这个静态文件在文件系统中的位置应该是 static/style.css
渲染模板
@app.route('/')
def hello_world():
return """
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>index</title>
</head>
<body>
<h1 style="color: red;">hello wolrd</h1>
</body>
</html>
"""
@app.route('/home')
def home():
return render_template('index.html')
模板转义
@app.route('/home')
def home():
label = Markup("<a href='http://www.baidu.com'>百度</a>")
print(label)
return render_template('index.html', label=label)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>index</title>
</head>
<body>
<h1 style="color: green;">hello wolrd</h1>
{{ label }}
</body>
</html>
or
@app.route('/home')
def home():
label = "<a href='http://www.baidu.com'>百度</a>"
return render_template('index.html', label=label)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>index</title>
</head>
<body>
<h1 style="color: green;">hello wolrd</h1>
{{ label | safe }}
</body>
</html>
Jinja2
@app.route('/')
def hello_world():
a = 1
b = 2
age = 23
name = 'wanghaha'
nums = [1, 8, 28, 33]
info = {'name': '王哈哈', 'age': 23}
users = [
{'name': '迪丽热巴', 'age': 27},
{'name': '古力娜扎', 'age': 26}
]
return render_template('index.html', **locals())
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>index</title>
</head>
<body>
{# 这里是注释内容 #}
{# 渲染一个变量, 并做计算 #}
<p>a+b={{ a + b }}</p>
{# for循环遍历列表 #}
<ul>
{% for item in nums %}
<li>{{ item }}</li>
{% endfor %}
</ul>
{# if判断 #}
{% if age >=18 and age <=100 %}
<p>你成年了</p>
{% elif age <18 and age >0 %}
<p>未成年</p>
{% else %}
<p>年龄不合法</p>
{% endif %}
{# 遍历字典 #}
{% for key, val in info.items() %}
<p>key: {{ key }} val:{{ val }}</p>
{% endfor %}
{# 遍历字典数组 #}
{% for user in users %}
{% for key, val in user.items() %}
<p>key: {{ key }} val: {{ val }}</p>
{% endfor %}
{% endfor %}
{# 过滤器使用 大小写转换#}
<p>{{ name | upper }}</p>
<p>{{ name | upper | lower}}</p>
{# 定义宏 #}
{% macro input(type, name, placeholder) %}
<div>
<label for="{{ name }}">{{ name }}</label>
<input type='{{type}}' id="{{ name }}" name="{{ name }}" placeholder="{{ placeholder }}">
</div>
{% endmacro %}
{# 调用宏 #}
<p>{{ input('text', 'username', '请输入用户名') }}</p>
<p>{{ input('password', 'password', '请输入密码') }}</p>
</body>
</html>
模板继承
@app.route('/')
def hello_world():
return render_template('index.html')
base.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{% block title %}{% endblock %}</title>
{% block head_region %}{% endblock %}
</head>
<body>
{% block content %}
<h1>welcome</h1>
{% endblock %}
{% block footer_region %}{% endblock %}
</body>
</html>
public.html
<h1>public.html 内容</h1>
index.html
{% extends 'base.html' %}
{% block title %}首页{% endblock %}
{% block content %}
{{ super() }}
<h1>hello world</h1>
{# 导入其它html文件内容 #}
{% include "public.html" %}
{% endblock %}
{% block footer_region %}
<script>
alert('hello');
</script>
{% endblock %}
自定义模板函数,过滤器
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/')
def hello_world():
return render_template('index.html')
# 定义全局函数,在模板中使用
@app.add_template_global
def my_sum(a, b):
return a + b
# 自定义过滤器
@app.template_filter()
def my_filter(arg):
return arg.upper()
if __name__ == '__main__':
app.run(debug=True)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<p>1 + 5 = {{ my_sum(1, 5) }}</p>
<p>{{ "hello" | my_filter }}</p>
</body>
</html>
请求
@app.route('/home')
def home():
print('cookies:', request.cookies) # 获取cookies
print('headers:', request.headers) # 获取请求头信息
print('method:', request.method) # 请求方法
print('url:', request.url) # URL全部内容,请求地址加参数
print('url_rule:', request.url_rule) # 请求URL不含请求地址和参数
print('url_root:', request.url_root) # 请求地址
print('host_url:', request.host_url) # 与url_root类似
print('base_url:', request.base_url) # 请求地址和URL和,不含参数
print('path:', request.path) # 请求URL
print('values:', request.values) # 包含GET, POST请求的参数
print('args:', request.args) # 获取URL参数
print('form:', request.form) # 获取POST提交formdata的参数
print('files:', request.files) # 获取提交的文件
print('json:', request.json) # 获取header为applicaiton/json提交的数据
return 'home page'
响应
from flask import Flask, render_template, make_response, abort, Response, send_file, redirect, url_for
app = Flask(__name__)
@app.route('/page1')
def page1():
return 'page1'
@app.route('/page2')
def page2():
return render_template('index.html')
@app.route('/page3')
def page3():
resp = make_response('<h1>hello world</h1>')
resp.headers['name'] = 'hello'
return resp
@app.route('/page4')
def page4():
resp = make_response(render_template('index.html'))
return resp
@app.route('/page5')
def page5():
info = {'name': 'wanghaha', 'age': 23}
resp = make_response(info)
resp.headers['Content-Type'] = 'application/json'
return resp
@app.route('/page6')
def page6():
abort(403)
@app.route('/page7')
def page7():
return Response('Hello World!', status=200, mimetype='text/html')
@app.route('/page8')
def page8():
return send_file('mn.jpg')
@app.route('/page9')
def page9():
return redirect(url_for('page8'))
if __name__ == '__main__':
app.run(debug=True)
文件上传
from flask import Flask, request
app = Flask(__name__)
@app.route('/upload', methods=['GET', 'POST'])
def upload():
if request.method == 'GET':
return """
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>index</title>
</head>
<body>
<form action="/upload" method="post" enctype="multipart/form-data">
<input type="file" name="file">
<input type="submit">
</form>
</body>
</html>"""
elif request.method == 'POST':
file = request.files['file']
file.save(file.filename)
return 'upload successful'
if __name__ == '__main__':
app.run(debug=True)
cookies
from flask import Flask, request, make_response
app = Flask(__name__)
@app.route('/page1')
def page1():
resp = make_response('<h1>hello world</h1>')
resp.set_cookie('name', 'wanghaha')
return resp
@app.route('/page2')
def page2():
name = request.cookies.get('name')
return f'cookies name: {name}'
if __name__ == '__main__':
app.run(debug=True)
重定向和错误
from flask import Flask, redirect, url_for, abort
app = Flask(__name__)
@app.route('/index')
def index():
return 'index page'
@app.route('/page1')
def page1():
return redirect(url_for('index'))
# 永久重定向,浏览器缓存下来不经过服务器端处理直接跳转
@app.route('/page2')
def page2():
return redirect(url_for('index')), 301
@app.route('/abort500')
def abort500():
abort(500)
@app.errorhandler(404)
def not_found_page(code_or_exception):
return '找不到页面', 404
@app.errorhandler(500)
def server_error(code_or_exception):
return '服务器错错误', 500
if __name__ == '__main__':
app.run()
JSON格式API
from flask import Flask, jsonify, json, make_response
app = Flask(__name__)
@app.route('/page1')
def page1():
info = {'name': 'wanghaha', 'age': 23}
resp = make_response(info)
resp.headers['Content-Type'] = 'application/json'
return resp
@app.route('/page2')
def page2():
info = {'name': 'wanghaha', 'age': 23}
return jsonify(info)
if __name__ == '__main__':
app.run()
session
from flask import Flask, session
from os import urandom
app = Flask(__name__)
app.secret_key = urandom(25)
@app.route('/page1')
def page1():
session['u'] = 'admin'
return 'page1 page'
@app.route('/page2')
def page2():
return f"session u:{session.get('u')}"
if __name__ == '__main__':
app.run()
闪现
from flask import Flask, flash, get_flashed_messages
from os import urandom
app = Flask(__name__)
app.secret_key = urandom(25)
@app.route('/page1')
def page1():
flash('hello')
flash('world')
flash('welcome', 'success')
return 'page1 page'
@app.route('/page2')
def page2():
print(get_flashed_messages())
return 'page2 page'
@app.route('/page3')
def page3():
print(get_flashed_messages(with_categories=True))
return 'page3 page'
if __name__ == '__main__':
app.run()
日志
蓝图
from flask import Flask, Blueprint
api = Blueprint('api', 'api')
admin = Blueprint('admin', 'admin')
@api.route('/page1')
def page1():
return 'api page1'
@admin.route('/page2')
def page2():
return 'admin page2'
app = Flask(__name__)
app.register_blueprint(api)
app.register_blueprint(admin)
@app.route('/')
def hello_world():
return 'Hello World!'
if __name__ == '__main__':
app.run()
钩子函数
from flask import Flask
app = Flask(__name__)
@app.route('/page1')
def page1():
return 'page1'
@app.route('/page2')
def page2():
return 'page2'
@app.before_request
def first_request():
print('请求进入视图函数之前')
@app.after_request
def after_request(response):
print('视图函数结束之前调用')
return response
if __name__ == '__main__':
app.run()
CBV
from flask import Flask, views, request
app = Flask(__name__)
class Index(views.MethodView):
def get(self):
return 'get method page'
def post(self):
return 'post method page'
class Upload(views.MethodView):
methods = ['GET', 'POST']
def get(self):
return """
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>index</title>
</head>
<body>
<form action="/upload" method="post" enctype="multipart/form-data">
<input type="file" name="file">
<input type="submit">
</form>
</body>
</html>"""
def post(self):
file = request.files['file']
file.save(file.filename)
return 'upload successful'
app.add_url_rule('/index', view_func=Index.as_view(name='index'))
app.add_url_rule('/upload', view_func=Upload.as_view(name='upload'))
if __name__ == '__main__':
app.run(debug=True)
配置
# 默认配置
default_config = ImmutableDict(
{
"ENV": None,
"DEBUG": None,
"TESTING": False,
"PROPAGATE_EXCEPTIONS": None,
"PRESERVE_CONTEXT_ON_EXCEPTION": None,
"SECRET_KEY": None,
"PERMANENT_SESSION_LIFETIME": timedelta(days=31),
"USE_X_SENDFILE": False,
"SERVER_NAME": None,
"APPLICATION_ROOT": "/",
"SESSION_COOKIE_NAME": "session",
"SESSION_COOKIE_DOMAIN": None,
"SESSION_COOKIE_PATH": None,
"SESSION_COOKIE_HTTPONLY": True,
"SESSION_COOKIE_SECURE": False,
"SESSION_COOKIE_SAMESITE": None,
"SESSION_REFRESH_EACH_REQUEST": True,
"MAX_CONTENT_LENGTH": None,
"SEND_FILE_MAX_AGE_DEFAULT": timedelta(hours=12),
"TRAP_BAD_REQUEST_ERRORS": None,
"TRAP_HTTP_EXCEPTIONS": False,
"EXPLAIN_TEMPLATE_LOADING": False,
"PREFERRED_URL_SCHEME": "http",
"JSON_AS_ASCII": True,
"JSON_SORT_KEYS": True,
"JSONIFY_PRETTYPRINT_REGULAR": False,
"JSONIFY_MIMETYPE": "application/json",
"TEMPLATES_AUTO_RELOAD": None,
"MAX_COOKIE_SIZE": 4093,
}
)
class Config(object):
DEBUG = False
TESTING = False
DATABASE_URI = 'sqlite:///:memory:'
class ProductionConfig(Config):
DATABASE_URI = 'mysql://user@localhost/foo'
class DevelopmentConfig(Config):
DEBUG = True
class TestingConfig(Config):
TESTING = True
app.config.from_object('configmodule.ProductionConfig')
项目布局
部署
uwsgi.ini
[uwsgi]
http=0.0.0.0:5000
socket=0.0.0.0:8001
chdir = /root
wsgi-file = main.py
stats = 127.0.0.1:9191
callable = app
processes = 4
threads = 10
location / {
include uwsgi_params;
uwsgi_pass 127.0.0.1:8001;
}
扩展
Flask-session
flask-migrate
from flask import Flask
from api import api as api_blueprint
from flask_migrate import Migrate, MigrateCommand
from flask_script import Manager
from models import db
import config
app = Flask(__name__)
app.config.from_object(config)
app.register_blueprint(api_blueprint)
db.init_app(app)
manager = Manager(app)
migrate = Migrate(app, db)
manager.add_command('db', MigrateCommand)
if __name__ == '__main__':
manager.run()
python3 manage.py db init
python3 manage.py db migrate
python3 manage.py db upgrade
flask-sqlalchemy
将结果集转为json格式
# sqlalchemy结果转json
from sqlalchemy.orm import class_mapper
# 将sqlalchemy结果转为json
def mapper(model):
columns = [c.key for c in class_mapper(model.__class__).columns]
return dict((c, getattr(model, c)) for c in columns)
# 判断是结果是多个还是一个
def to_json(model):
if isinstance(model, list):
data = []
[data.append(mapper(item)) for item in model]
return data
return mapper(model)
flask-script
flask-login
flask-rbac
Flask-debugToolbar
flask-restful
flask-admin
flask-cli
flask-mail
flask-cors
from flask_cors import CORS
app = Flask(__name__)
cors = CORS(app, resources={r"/*": {"origins": "*"}})
# 单独蓝图配置
api_v1 = Blueprint('API_v1', __name__)
CORS(api_v1)
返回SQLAlchemy对象
在模型中添加如下方法
def to_json(self):
dict = self.__dict__
if "_sa_instance_state" in dict:
del dict["_sa_instance_state"]
return dict
在返回数据是通过to_json方法放到列表中
@app.route('/comments', methods=['GET'])
def comments():
comments = db.session.query(Comment).all()
result = []
for comment in comments:
result.append(comment.to_json())
return jsonify(result), 200