在Flet架构中,前端可以是基于浏览器的Web,或者windows桌面端exe程序,或者移动端的apk等等,由于前后端代码都写到一起的,要去理解哪些是前端代码,哪些是后端代码就很费解了。
我们先分析一个简单的页面如下,页面显示了服务端的ini配置文件的值。左边是ini文件列表,下一级菜单是sections,右边是每个section下面的配置名称和值,可以修改保存。
暂时不涉及复杂的交互,按照目前的前后端分离的架构,前端进行页面渲染,然后向后端去请求数据并动态响应展示。保存也通过接口传递给后端,修改ini文件。
前后端分离
如上图所示,分离架构里面,服务端主要提供RestFul接口服务,只需要提供数据查询和更新即可,不用关注用户动作和呈现,前端去定义数据展示形态,实现用户查询动作和更新动作的捕获,并将请求发送到后端,根据后端范围的数据动态渲染。
Flet比较神奇,比方说前面例子中的Web服务,页面的展示、动作定义和数据获取都在Python中实现的,感觉好像是Python的代码Run起来之后,Server端也把前端的事情也干了。
我贴一下代码来看看,首先是主入口代码,这里基本上就是定义主页面,启动一个flet服务。
Inis类是我自己封装的加载和管理ini的数据处理对象; 而iniControls是定义的展示视图,是一个自定义Controls类,用来定义页面展示元素和事件响应。Inis类可以理解为纯后端数据处理的类,由于前后端开发时间比较长,用Flet的时候还是习惯将数据处理也页面处理分开[捂脸]
另外比较有意思的是main入库,需要有一个page,在flet中,不管是Web还是APP,page可以看做前端的页面主容器,页面的最终展示可以看成是通过page.update()来渲染的。官网与介绍,每个flet都有一个page,下面可以包含多个view,通过view的切换来完成视图的切换,呈现不同的前端页面。
不管是BS还是CS,用户层面上最重要的两个动作就是展示和事件响应。参见前面范例的代码,controls是自定义的ini展示组件,将这个组件append到系统的columns中,最终将columns添加到主页面page里面,在page里面展示,我们这个范例里面只有一个view。有前端基础的很容易理解这个处理。
再来深入看下自定义的控件实现,build函数是重写了父类的函数,看实现就知道主要是完成前端显示元素构建和布局设置。
其他的内容我们暂时不关注,先重点看看保存按钮,为每个保存按钮添加self._save_cfg点击处理函数,有点像一个回调函数,这就是一个前端页面动作响应。
而保存动作是保存到后端,看下self._save_config函数。我们save到后端,同时对控件状态进行了更新,e.control.disabled的目的是保存之后设置按钮状态并更新页面。
按照flet的思路,我们根据web的一个案例进行了分析,这个写法确实没有前后端的概念了[捂脸]这是因为Flet是SDUI架构,官网也进行了阐述,我们下一小节来描述。
参见官网https://flet.dev/docs/guides/python/mobile-support
SDUI架构全称是Server-driven UI,简单理解就是服务端驱动UI,如下图,在我们的Web应用中,User program和Flet server都运行在Server端,Flet client可以是Web、exe或者apk应用。
我们的所有Python程序构成User program模块,完成业务流程, 与Flet client的交互通过Flet框架中的Flet server,这部分是由go实现。
每个模块详细说明如下:
可以看出来SDUI架构,动作响应和页面刷新都需要由Server端驱动,Server端需要干很多以前前端干的是事情,websockets连接对资源消耗也更大,所以Flet引入了Flet Server并用go来实现作为底层通道,解决Python性能较差的问题,但Flet仍然存在两个弊端
在官方博客
因为是单客户端场景,并发少,缩短交互路径能够减少时延,提升响应速度。
如上图,该场景下我称之为纯客户端场景,用Python+Flutter去驱动Flet Client,如果要跟服务端通信,可以像前端一样,通过requests等库与第三方服务端通信,基于HTTP。
移动端APP也是类似的,只是按照官方所述,需要注意Python程序需要引入比较纯粹的python,或者必须支持在ARM64架构上编译。