用于enaml的web组件工具包
enaml-web的Python项目详细描述
搪瓷网
一个web组件工具包,用于 让我们用python声明性地构建网站。
您可以使用enaml web使用python、enaml和几行simplejavascript构建"交互式"网站(请参阅simple pandasdataframe viewer示例)。视图状态(DOM)作为一个名称视图存储在服务器上,交互通过在 在客户端和服务器之间使用WebSocket(或轮询)。
为了演示,下面的交互都是用enaml web处理的
示例
请参见"示例"文件夹
- www.codelv.com-完全使用珐琅网构建
- SMD组件搜索-查看和搜索熊猫数据框
简介
要使用enaml web,只需将html标记替换为enaml组件 (大写的标记名)。例如:
fromweb.components.apiimport*enamldefIndex(Html):Head:Title:text="Hello world"Body:H1:text="Hello world"
在这个名称视图的一个实例上调用render(),然后生成html 从视野看。这在静态站点生成器的简单示例中显示:
importenamlfromweb.core.appimportWebApplication# Create an enaml Application that supports web componentsapp=WebApplication()# Import Index from index.enamlwithenaml.imports():fromindeximportIndex# Render the Index.enaml to index.htmlview=Index()withopen('index.html','w')asf:f.write(view.render())
您还可以在请求处理程序中使用它来处理您喜爱的web框架。例如龙卷风 网络您可以这样做:
importenamlimporttornado.webimporttornado.ioloopfromweb.core.appimportWebApplication# Import Index from index.enamlwithenaml.imports():fromindeximportIndexclassIndexHandler(tornado.web.RequestHandler):view=Index()defget(self,request):returnself.view.render(request=request)classApplication(tornado.web.Application):def__init__(self):super(Application,self).__init__([(r'/',IndexHandler)],)if__name__=="__main__":web_app=WebApplication()app=Application()app.listen(8888)tornado.ioloop.IOLoop.current().start()
那么与普通的html相比有什么优势呢?
它和HTML一样简单,但它是Python,所以你可以循环列表,有条件地呈现, 格式变量等。
此外,它不仅格式化模板,服务器还维护页面状态,以便 您可以在呈现页面后与之交互。这是没有别的东西 python模板框架可以做到(据我所知)。
工作原理
它生成一个由lxml元素组成的dom。
固有安全性
由于生成了lxml dom,这意味着您的代码本质上是安全的 注入,因为它会自动转义所有属性。而且结束标记不能 不小心错过。
atom框架通过强制运行时类型提供额外的安全性 检查和可选验证。
可通过模板和块扩展
与其他模板引擎一样,enaml web提供了一个"block"节点,允许 您可以定义模板中可以重写或扩展的部分。
enaml还提供模式节点来处理条件语句、循环, 基于列表或模型的动态节点,以及由更复杂的 模板(例如自动生成表单)。
不需要模板标记
许多模板引擎需要使用包装在{%}
中的"模板标记"
或者类似于允许使用python代码转换变量。
因为enaml是python,所以可以直接在 你的恩AML组件和模板。您不需要任何模板标记。
测试更容易
因为内部表示是lxml节点,所以可以使用lxml的xpath 查询用于E2E视图测试的DOM。不需要使用无头浏览器和 那些复杂的东西(除非你用了很多js)。
基于组件
由于enaml视图类似于python类,所以可以"子类"并扩展任何 组件并扩展其功能。这使您能够快速构建 可重复使用的部件。
我正在研究几个常用css框架的组件,这样它们就可以 安装并使用。
- 物化用户界面
- 语义用户界面(即将推出)
- 引导(即将推出) < > >
- 在页面中包含enaml.js
- 观察html节点的
modified
事件,并将这些更改传递给 通过WebSocket客户端。 - enamljs将事件发送回服务器,相应地更新dom。 < > >
数据绑定
因为enaml web正在生成一个dom,所以可以使用websockets和一些js 操作dom在客户端到服务器之间进行数据绑定。
可以为每个用户或每个会话共享dom,这样可以轻松地创建 协作页面,或者它们对每个页面都是唯一的。
每个节点都是唯一的标识符,可以使用更改事件进行修改。安 示例位于"示例"文件夹中。
您还可以在服务器上设置客户机触发器事件,并在服务器上设置 在客户端上触发js事件。
使用:
数据模型
可以使用enaml的dynamictemplate自动生成和填充表单
节点。使用materalize css实现autoform
框架可以在我的个人回购协议上找到。有了这个,我们可以采用这样的模型:
fromatom.apiimportAtom,Unicode,Bool,EnumclassMessage(Atom):name=Unicode()email=Unicode()message=Unicode()options=Enum("Email","Phone","Text")sign_up=Bool(True)
然后使用autoform
节点并传入
要呈现窗体的模型。
fromtemplatesimportBasefromweb.components.apiimport*fromweb.core.apiimportBlockenamldefAddMessageView(Base):page:attrmessageBlock:block=page.contentAutoForm:model<<message
带有atom的数据库orm
有关使用atom处理数据库的信息,请参见atom db
原始、标记和代码节点
raw
节点将文本解析为dom节点(使用lxml的html解析器)。同样地
标记
和代码
节点分别解析标记和突出显示代码。
例如,您可以使用wagtal的richtext标记通过:
fromweb.components.apiimport*fromweb.core.apiimport*fromwagtail.core.templatetags.wagtailcore_tagsimportrichtextfrommyapp.views.baseimportPageenamldefBlogPage(Page):body.cls='template-blogpage'Block:block=parent.contentRaw:source<<richtext(page.body)
让我们使用web所见即所得编辑器将内容插入到dom中。
块节点
您可以定义基本模板,然后使用块
节点覆盖零件。
在一个文件中输入:
fromweb.components.apiimport*fromweb.core.apiimportBlockenamldefBase(Html):attruserattrsiteattrrequestaliascontentHead:Title:text<<site.titleBody:Header:text="Header"Block:content:passFooter:text="Footer"
然后可以导入该视图并扩展模板并覆盖 块的内容。
fromtemplatesimportBasefromweb.components.apiimport*fromweb.core.apiimportBlockenamldefPage(Base):page:Block:block=page.contentP:text="Content inserted between Header and Footer"
块使您可以替换、追加或预处理内容。
自定义组件
使用enaml,您可以轻松地创建可重用组件并通过 视图与任何使用常规python导入的python类一样。
例如,要创建 将breadcrumbs组件具体化 它自动遵循当前的请求路径,只需包含所需的 css/脚本在基本模板中,定义如下所示的组件:
fromweb.components.apiimport*fromweb.core.apiimportLooperenamldefBreadcrumbs(Nav):nav:attrpath# ex. pass in a tornado request.pathattrcolor=""attrbreadcrumbs<<path[1:-1].split("/")tag='nav'Div:cls='nav-wrapper {}'.format(nav.color)Div:cls='container'Div:cls='col s12'Looper:iterable<<breadcrumbsA:href="/{}/".format("/".join(breadcrumbs[:loop_index+1]))cls="breadcrumb"text=loop_item.title()
然后按如下方式使用它
fromweb.components.apiimport*enamldefIndex(Html):Head:Title:text="Hello world"Body:H1:text="Hello world"0
哥特卡斯
< H5>XT和尾部节点lxml使用文本和尾部属性设置子节点之前和之后的文本,这可能会造成混淆。
例如,在html中,您可以执行
fromweb.components.apiimport*enamldefIndex(Html):Head:Title:text="Hello world"Body:H1:text="Hello world"1
要使用enaml进行此操作,您需要执行以下操作:
fromweb.components.apiimport*enamldefIndex(Html):Head:Title:text="Hello world"Body:H1:text="Hello world"2
注意如何在a而不是
p>上设置尾部。
有关详细信息,请参见lxml etree文档。
标记属性
在当前实现中,使用的xml标记是类名的小写。 子类化组件时,必须明确地将标记属性设置为 所需的标记名。例如:
fromweb.components.apiimport*enamldefIndex(Html):Head:Title:text="Hello world"Body:H1:text="Hello world"3