对于Flask大家很熟悉了,现在主流Python的web框架,除了Django就数Flask了。
Django不用多说,集合了orm、template模板引擎、后台管理系统、参数验证、路由系统、用户认证和其他一些工具的,方便快速建站,主要构建了ORM和复写ADMIN模块,就可以快速生成网站和后台增上改查和一些其他的定制化开发。
Flask是一个轻量级的可定制框架,使用Python语言编写,较其他同类型框架更为灵活、轻便、安全且容易上手。它可以很好地结合MVC模式进行开发,开发人员分工合作,小型团队在短时间内就可以完成功能丰富的中小型网站或Web服务的实现。另外,Flask还有很强的定制性,用户可以根据自己的需求来添加相应的功能,在保持核心功能简单的同时实现功能的丰富与扩展,其强大的插件库可以让用户实现个性化的网站定制,开发出功能强大的网站。
笔者更倾向于Flask这个框架,因为它更加透明,更能掌控项目的质量。
Flask的插件管理是一个很不错的特性,我们利用它可以在启动web服务之前加载我们所需要的插件,一下是笔者经常用到的:
flask的restapi开发框架,有参数校验,路由拦截等功能。
Sqlalchemy的flask插件,这个插件作者扩展了针对与session中的query的分页功能,可以使用SQLALCHEMY_BINDS进行多个数据库的绑定,可以配置连接池,连接池过期时间。
Sqlalchemy连接mysql的引擎,不过pymysql需要加入一句话:
import pymysql
pymysql.install_as_MySQLdb()
Sqlalcemy序列化数据利器,可以使用它针对query返回的QuerySet结果集合进行序列化成dict 数据。
开发API会遇到跨域访问的问题,可以就是客户端OPTIONS的请求,先探知服务器允不允许跨域访问,允许会返回header中允许那些方法进行请求服务器(GET、POST、DELETE、PUT等),这个插件可以通过简单的配置,让您的服务允许跨域访问,不过在生产环境,还是推荐使用Nginx的好,能够使用lua语言进行更加严格的控制。
这两个都是用户认证用到的插件,使用session控制,选择flask-login,使用jwt使用flask-jwt-extended。
下面简单说一下flask的框架,flask框架是基于Werkzeug和Jinja2两大基础框架,Werkzeug是基于WSGI协议的框架,已经有了基本的路由、数据结构、请求和响应等功能,在此之上Flask扩展了一些特性:
Flask利用Werkzeug的Local、LocalStack和LocalProxy,实现了AppContext和RequestContext的线程或者协程安全功能,也就是:
另外说明flask-sqlalchemy利用线程或者携程号有get_indent,可以使用scope_session功能,将session隔离,它是线程或者协程安全的,也和flask的请求保持一致。
使得每个view方法,有个名称,这个名称是唯一的,它能够通过这个名称找到这个视图方法,也就能够获得路由。
这里数据结构简单地说就是一个map类型,一个名称唯一对应一个视图方法,不允许相同的endpoint出现,这个应用在使用url_for这个方法上:
这样可以灵活根据名称去使用路由,而不是硬编码到程序中非常死板,如果说我们修改了一个url的地址,只是微小的修改,其他引用这个路由的地方也需要修改,我们可能忘记了使用它的地方,这时url_for非常好的解决了这个问题。
扩展应用,提供了两种方式,一种是直接加载,之类用生成对象例如CORS(flask_app),也可以懒加载,在创建应用之前定义对象,创建flask_app时加载插件,例如flask-sqlalchemy
from flask import Flask
from flask_sqlalcemy import Sqlalchemy
db = Sqlalchemy()
def create_app():
"""
创建Flask app
"""
f_app = Flask()
f_app.config.from_object("core.settings")
db.init_app(app=f_app)
return f_app
这样的形式,我们可以使用全局这个db对象了。
我们可以借鉴django的目录形式进行组织项目的框架,例如:
core文件夹基本这个样子,app 是项目Flask应用初始化,settings是配置信息,应用是user和config等,static存放静态文件,templates是模板目录,requirements.txt里面配置依赖,run.py是调试使用的启动入口。
特别的一个应用目录为:
其中,__init__.py是module的文件,dbis.py里面都是面向数据操作的方法,models.py里面都是ORM的定义,urls.py里面是路由配置,validators.py存放参数校验方法,views.py存放视图方法,serializers.py存放序列化的方法,dbi_services.py存放构造views.py中使用的数据类型。
我们如何将他们和Flask的应用联系起来呢,可以进行如下操作:
生成Flask的应用代码:
import os
from flask_sqlalchemy import SQLAlchemy
from flask_bootstrap import Bootstrap
from flask_url.conf import FlaskUrlConf
from flask_wtf.csrf import CSRFProtect
from flask import Flask
db = SQLAlchemy()
def create_app(import_name):
"""
创建Flask应用
:param import_name: [str] 模块名称
:return:
"""
f_app = Flask(import_name)
# 根据环境变量加载配置信息
env_dict = {
"DEV": "core.dev_settings",
"ONLINE": "core.online_settings"
}
env = os.environ.get("PRO_ENV", "DEV")
f_app.config.from_object(env_dict.get(env, "core.dev_settings"))
FlaskUrlConf(app=f_app)
db.init_app(app=f_app)
CSRFProtect(app=f_app)
print(f_app.url_map)
return f_app
app = create_app(__name__)
其中使用了FlaskUrlConf(app=f_app)这个,是我自己构造的一个插件,贴出这段代码:
from flask import Flask
from flask.blueprints import Blueprint
from flask_url.utils import get_mod_attr
def path(rule, endpoint, view_func, **options):
return Url(rule=rule, endpoint=endpoint, view_func=view_func, **options)
class Url:
rule = None
endpoint = None
view_func = None
options = {}
def __init__(self, rule, endpoint, view_func, **options):
self.rule = rule
self.endpoint = endpoint
self.view_func = view_func
self.options = options
class FlaskUrlConf:
def __init__(self, app: Flask = None):
if app:
self.init_app(app=app)
def init_app(self, app: Flask):
install_apps = app.config.get("INSTALL_APPS", [])
for app_str in install_apps:
mod_path = f"{app_str}.urls"
try:
urls = get_mod_attr(mod_path, "urls")
b = Blueprint(import_name=mod_path, name=app_str)
for url in urls:
if isinstance(url, Url):
b.add_url_rule(
rule=url.rule,
endpoint=url.endpoint,
view_func=url.view_func,
**url.options
)
app.register_blueprint(b)
except ImportError as e:
app.logger.warn(f"Import module {mod_path} err {e}")
except IndexError as e:
app.logger.warn(f"Split module {mod_path} attr error {e}")
except AttributeError as e:
app.logger.warn(f"Get attr from url module {mod_path}, error {e}")
其核心思想是通过INSTALL_APPS这个配置,将各级模块儿应用下的urls.py中的urls列表进行加载,urls.py示例:
from flask_url.conf import path
from article import views
urls = [
path(rule="/article/page/<int:a_id>/", view_func=views.get_article, endpoint="page")
]
那我们就完成了MVC的项目目录结构的搭建。
最后我们再来谈一下flask应用的部署,我们可以使用gunicorn或者uwsgi进行部署,通过nginx进行代理即可。
uwsgi配置示例:
uwsgi]
uid = root
gid = root
master = true
processes = 1
listen = 10
socket = 127.0.0.1:9000
pidfile = /uwsgi.pid # 你的路径
vacuum = true
daemonize = /uwsgi.log # 你的日志路径
chdir = ${你的项目路径}
home=${你的env的路径}
buffer-size = 32768 # 可以修改允许最大交换数据
module = core.wsgi # 你的 wsgi模块路径
callable = app # 选择你的应用,Flask的应用
http-websockets = true # 是否启用web socket
gevent = 10 # 启用协程
async = 10
nginx配置示例
server {
listen 8888;
charset UTF-8;
location ^~ /api/ {
include uwsgi_params;
uwsgi_pass http://127.0.0.1:9000;
client_max_body_size 100m;
}
}
以上是总结的一些内容跟大家分享,由于篇幅有限有些细节没有说清,大家可以在评论区提问。希望大家多多支持。