博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Flask备注4(Structure)
阅读量:5981 次
发布时间:2019-06-20

本文共 6547 字,大约阅读时间需要 21 分钟。

Flask备注4(Structure)

package

通过Flask可以非常简单的通过一个module(一个py文件)创建一个简单的application。这种简单程序的文件结构如下:

/yourapplication    /yourapplication.py    /static        /style.css    /templates        layout.html        index.html        login.html        ...

这种结构对于较大或者复杂的程序并不合适。对于复杂程序可以通过python自带的package结构来组织代码结构。

包含init.py的文件夹都是package,引用该目录下的所有module都会先导入init.py并执行顶层代码。

使用package的Flask的代码结构如下:

/yourapplication    /runserver.py    /yourapplication        /__init__.py        /application.py        /views.py        /static            /style.css        /templates            layout.html            index.html            login.html            ...

因为导入任何目录下的文件,都会执行__init__.py中的顶层代码,而且在多层嵌套的情况下,引用会执行每层目录的__init__.py文件,因此建议将次文件留空。将单独module的程序转变为package结构程序的步骤如下:

  1. 将App的初始化以及参数的配置等功能放到application.py中。
  2. 在每个单独的功能module(例如views.py)通过from application import app 对app进行引用,以使用app的接口。
  3. 创建一个顶层module(runserver.py)来执行application,在此module中先引入app初始moduleimport yourapplication.application然后分别导入功能module例如import yourapplication.views,最终执行applicationapp.run(debug=True)

在代码里面应该尽量避免循环引用,避免依赖循环。在上述步骤里面。modulerunserver依赖application以及各个功能module,各个功能module依赖于applicationmodule,形成不了依赖循环。当不得不面对循环依赖时,将其中的一个应用放到函数或者方法里面。

Blueprints

Flask支持blueprint将application可以分成几个部分,从接口功能上,blueprint对象和flask对象的类似。在Flask application中增加blueprint的支持,可以为较大或者复杂的application提供了一个新的组织结构方式:将程序中相似的部分功能放到一个blueprint对象中,然后将这些blueprints注册成到application。最终的application包含一个application对象(flask对象),所需要的extension的对象以及一系列blueprint对象。使用这种结构的优势:

  • 将一个较大或者复杂的appliction转变为一系列相对独立的blueprints,便于维护。
  • 每个blueprint在注册时对应一个URL前缀和subdomain,这样所有包含于blueprints中的view函数都以此前缀和subdomain作为参数。
  • 可以将同一个blueprints,使用不同的URL规则进行注册。实现模块化复用代码。
  • 对blueprints可以单独提供template filter,templates文件目录以及static文件目录。优先级比application的templates和static的优先级要低一些。

在使用blueprint的组织结构中,每个blueprint部分必须包含一个blueprint对象,以及这个部分的功能实现。blueprint对象的声明示例如下:

from flask import Blueprintbp = Blueprint('blueprint_user', __name__, template_folder='templates')

每个blueprint部分的实现简单点可以放在一个module中同样也可以和package结构相结合,放到一个目录结构中。和package结构结合的代码结构如下:

/yourapplication    /runserver.py    /yourapplication        /__init__.py        /application.py        /views.py        /static            /style.css        /templates            layout.html            index.html            login.html        /bpuser            /__init__.py            /blueprint_user.py            /views.py            /templates                info.html        /bpmanager            /__init__.py            /blueprint_manager.py            ...

在示例代码中,bpuser以及bpmanager是两个blueprints的目录。其中在blueprint_user.py以及blueprint_manager.py进行了blueprint对象的声明。在application.py中引用并注册blueprints。注册时示例如下:

from flask import Flaskimport bpuser.blueprint_userimport bpmanager.blueprint_managerapp = Flask(__name__)app.register_blueprint(blueprint_user.bp, url_prefix='/user')app.register_blueprint(blueprint_manager.bp, url_prefix='manager')

在application注册blueprint时,从根本实现上,application会记录blueprint的功能。然后application在功能触发时根据记录分发到相应的blueprint所在的模块进行处理。例如在blueprint_user.py中声明一个view endpoint。

@blueprint_user.route('/info')def info():    try:        return render_template('info.html')    except TemplateNotFound:        abort(404)

然后application在注册blueprint时,将blueprint的功能记录在application中,在application中增加一些规则,在application使用时会根据相应规则发送到blueprint进行处理。这些记录的规则示例如下:

[<Rule '/user/info' (HEAD, OPTIONS, GET) ->blueprint_user.info>]

如规则中所示,在application使用blueprint所声明的endpoint(入口函数)都加了一个前缀,这个前缀就是blueprint的名字。因此在进行url转换时,使用url_for函数也必须要在endpoint前加上blueprint名字的前缀。如果转换函数在当前blueprint中使用,可以只在endpoint加一个点。

# in applicationurl_for(blueprint_user.info)# in blueprinturl_for(.info)

面向对象编程

如我们所知,面向对象的编程思想以及设计模式能够提供更好的代码结构,当前所描述的基于blueprint以及package的代码结构,虽然代码的实现在Module(源文件)以及函数中,但是依然符合了OOP(面向对象编程)的思想,同样也使用了相应的设计模式。也可以理解为当前结构是面向对象的结构。

  1. everthing in python is object. python中的一切都是对象,也可以按照处理对象的方式处理。比如函数、module、字符串、以及上述的package和blueprint都是对象。因此可以获取类型,可以作为参数传入函数,作为函数值,甚至包含属性和方法。因此这个结构是面向对象的。
  2. package以及blueprint的结构是使用目的,就是封装以及多态。这本身就符合面向对象的设计思想。blueprint的注册,decorator的使用本身也是设计模式的应用。因此这个结构是面向对象的。

但是当前结构中没有使用类(class),python的代码设计并不需要类来完成面向对象的设计,灵活的Module以及对于环境影响较小的函数是更推荐的方式。因此使用类需要基于以下原则:

  • 如果需要将功能以及功能的状态绑定在一起,可以通过自定义类实现。将功能变为方法(method)将状态变为属性(property)。
  • 如果功能会被多个线程使用,他所操作的资源在多线程环境下具备异步风险,因此不建议使用自定义类。

对于Flask程序,业务逻辑的实现,因为会同时发生很多个相同的请求,因此并不建议放到自定义类中。而用户界面在会有较多的功能重用,并且单一View会响应同一入口的不同的Http方法,因此可以放到自定义类中。对于用户界面的自定义类,Flask引入Pluggable view。

Pluggable View

通过Pluggable view,Flask通过自定义类为URL入口提供View。这种方式相比较于函数endpoint结构更清晰,同时提供了更多的灵活性。通过自定义类提供endpoint的简单示例如下:

from flask import View, render_templateclass ShowUsersView:    def dispatch_request(self):        users = User.query.all()        return render_tempalte('show_users.html', objects = users)app.add_url_rule('/users/', view_func=ShowUsersView.as_view('show_users'))

自定义类提供VIEW的实现的必要因素有:

  • 自定义类必须继承自View类(或者MethodView类)。
  • 实现dispatch_request函数。
  • 在app添加url处理规则时,通过as_view方法转变为一个endponit函数。其中参数就是endponit名称。

相比较于endpoint函数的方式,Pluggable view实现方式的优势包含:

  1. 通过一个类,对应同一入口可以定义不同的方法应对不同的http方法,结构更清晰。
  2. 通过类的继承和多态的特点将相似度很高的VIEW整合在一起,代码复用度较高切结构清晰。

Method View

自定义View继承MehtodView,可以在自定义View中响应不同的Htpp方法的请求。例如上述'/users/'的URL中可以对应的方法包含:

*URL* *Method* *Description*
/users/ GET 获取所有的用户列表
/users/ POST 创建新用户
/users/id GET 获取单个用户
/users/id PUT 更新单个用户
/users/id DELETE 删除单个用户

通过继承自MethodView的自定义View,这些HTTP请求都可以在一个入口清晰的实现。实现示例:

class UsersView(MethodView):    def get(self, user_id):        if user_id is None:            # return all users.            pass        else:            # return a singal view            pass    def post(self):        # create a new user        pass    def put(self, user_id):        # update a user        pass    def delete(self, user_id):        # delete a user.        pass

然后逐条注册URL处理规则,同时可以将整个注册抽象出来作为函数在所有的自定义VIEW注册时使用。

def register_api(view, endpoint, url, pk='id', pk_type='int'):    view_func = view.as_view(endpoint)    app.add_url_rule(url, defaults={pk: None},                    view_func=view_func, methods=['GET',])    app.add_url_rule(url,                    view_func=view_func, methods=['POST',])    app.add_url_rule('%s<%s:%s> % (url, pk, pk_type)                    view_func=view_func,                    methods=['GET', 'PUT', 'DELETE'])register_api(UsersView, 'users', '/users/', pk='user_id', pk_type='int')

View inherits

Pluggable view是自定义类,因此可以使用类的继承和多态的特性,将相似的VIEW整合在一起。例如:Users的VIEW是一个列表; Items的VIEW也是一个列表;因此可以继承自一个自定义的ListView。VIEW的继承关系可以和对应templates的继承关系一致,也也可以都使用父VIEW的template,非常灵活。

更进一步使用自定义类定义VIEW,可以将VIEW的实现已经VIEW的注册分发这种和业务逻辑有关的部分分离开来,将程序变成MVC的机构:

VIEW <--> Model <--> 业务

当前使用这种结构需要符合应用的真实需要。代码结构设计的目的是更清晰的代码结构,更容易的代码阅读和维护。

转载于:https://www.cnblogs.com/3days/p/5339376.html

你可能感兴趣的文章
LinkedBlockingDeque
查看>>
iOS7 兼容及部分细节
查看>>
[C#]MemoryStream.Dispose之后,为什么仍可以ToArray()?
查看>>
洛谷1508 Likecloud-吃、吃、吃
查看>>
js基本数据类型 BigInt 和 Number 的区别
查看>>
Request JSON
查看>>
转 Solr vs. Elasticsearch谁是开源搜索引擎王者
查看>>
转://Window下安装Oracle ASM单实例数据库
查看>>
solrCloud+zk+tomcat配置
查看>>
Java 程序中的多线程(四)
查看>>
【NOI2018模拟5】三角剖分Bsh
查看>>
redis安装使用
查看>>
git 几款好用的客户端工具
查看>>
拍拍贷月还款的理解
查看>>
【jBox】2.3正式版 多功能jQuery对话框插件下载及常见使用问题解答
查看>>
一个数如果恰好等于它的因子之和,这个数就称为 "完数 "。例如6=1+2+3.编程 找出1000以内的所有完数。...
查看>>
如何添加localizable.strings本地化
查看>>
css 禁用移动端部分特性
查看>>
Online Judge(OJ)搭建——2、数据库,SQL语句
查看>>
MIT自然语言处理第三讲:概率语言模型(第六部分)
查看>>