首页 技术 正文
技术 2022年11月20日
0 收藏 809 点赞 2,619 浏览 5665 个字

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 Blueprint
bp = 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 Flask
import bpuser.blueprint_user
import bpmanager.blueprint_manager
app = 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 application
url_for(blueprint_user.info)
# in blueprint
url_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_template
class 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 <–> 业务

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

相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:8,965
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,486
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,331
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,114
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:7,747
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:4,781