<返回更多

Flask框架及其应用

2021-03-03    
加入收藏

Flask介绍

对于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的框架,flask框架是基于Werkzeug和Jinja2两大基础框架,Werkzeug是基于WSGI协议的框架,已经有了基本的路由、数据结构、请求和响应等功能,在此之上Flask扩展了一些特性:

Flask利用Werkzeug的Local、LocalStack和LocalProxy,实现了AppContext和RequestContext的线程或者协程安全功能,也就是:

  1. 当请求过来,Flask将app_context和request,这两个对象压入一个线程号或者协程号对应的栈中,说白了就是dict字典,线程或者携程号有get_indent内置方法获得
  2. 请求过程中,由栈弹出上次压入栈中的app_context和request
  3. 请求结束释放空间

另外说明flask-sqlalchemy利用线程或者携程号有get_indent,可以使用scope_session功能,将session隔离,它是线程或者协程安全的,也和flask的请求保持一致。

使得每个view方法,有个名称,这个名称是唯一的,它能够通过这个名称找到这个视图方法,也就能够获得路由。

这里数据结构简单地说就是一个map类型,一个名称唯一对应一个视图方法,不允许相同的endpoint出现,这个应用在使用url_for这个方法上:

  1. 程序中使用url_for进行路由跳转
  2. template模板总是用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的目录形式进行组织项目的框架,例如:

Flask框架及其应用

 

core文件夹基本这个样子,app 是项目Flask应用初始化,settings是配置信息,应用是user和config等,static存放静态文件,templates是模板目录,requirements.txt里面配置依赖,run.py是调试使用的启动入口。

特别的一个应用目录为:

Flask框架及其应用

 

其中,__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;
        }
}

以上是总结的一些内容跟大家分享,由于篇幅有限有些细节没有说清,大家可以在评论区提问。希望大家多多支持。

声明:本站部分内容来自互联网,如有版权侵犯或其他问题请与我们联系,我们将立即删除或处理。
▍相关推荐
更多资讯 >>>