范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

Jinja2教程包含和导入

  欢迎来到我的 Jinja2 教程系列的另一部分。到目前为止,我们已经了解了很多关于渲染、控制结构和各种功能的知识。在这里,我们将开始讨论帮助我们处理组织模板的语言特性。我们将看的第一个构造是include 和import 语句。
  介绍
  Include 和Import 语句是 Jinja 为我们提供帮助组织模板集合的一些工具,尤其是当这些模板的大小增加时。
  通过使用这些结构,我们可以将模板拆分为更小的逻辑单元,从而生成具有明确定义范围的文件。反过来,当出现新需求时,这将使修改模板变得更加容易。
  结构良好的模板集合的最终目标是提高可重用性和可维护性。 目的和语法
  "包含"语句允许您将大型模板分解为更小的逻辑单元,然后可以在最终模板中组装这些单元。
  当你使用时,include 你引用另一个模板并告诉 Jinja 渲染引用的模板。Jinja 然后将渲染文本插入到当前模板中。
  语法为include :
  {% include "path_to_template_file" %}
  其中 "path_to_template_file" 是我们想要包含的模板的完整路径。
  例如,下面我们有一个名为模板的模板,cfg_draft.j2 它告诉 Jinja 找到名为模板的模板,渲染它,并用渲染的文本users.j2 替换块。{% include ... %}
  cfg_draft.j2  {% include "users.j2" %}
  users.j2  username przemek privilege 15 secret NotSoSecret
  最后结果: username przemek privilege 15 secret NotSoSecret 使用"包含"拆分大型模板
  如果您查看典型的设备配置,您将看到与给定功能相对应的许多部分。您可能有接口配置部分、路由协议一、访问列表、路由策略等。我们可以编写单个模板来生成整个配置:
  device_config.j2  hostname {{ hostname }}  banner motd ^ =========================================== |   This device is property of BigCorpCo  | |   Unauthorized access is unauthorized   | |  Unless you"re authorized to access it  | |  In which case play nice and stay safe  | =========================================== ^  no ip domain lookup ip domain name local.lab ip name-server {{ name_server_pri }} ip name-server {{ name_server_sec }}  ntp server {{ ntp_server_pri }} prefer ntp server {{ ntp_server_sec }}  {% for iname, idata in interfaces.items() -%} interface {{ iname }}  {{ idata.description }}  {{ idata.ipv4_address }} {% endfor %}  {% for pl_name, pl_lines in prefix_lists.items() -%} ip prefix-list {{ pl_name }} {%- for line in pl_lines %}  {{ line -}} {%  endfor -%} {% endfor %}  router bgp {{ bgp.as_no }} {%- for peer in bgp.peers %}  neighbor {{ peer.ip }} remote-as {{ peer.as_no }}  neighbor {{ peer.ip }} description {{ peer.description }} {%- endfor %}
  通常我们会有机地扩展我们的模板,并将一个接一个的部分添加到负责生成配置的单个模板中。然而,随着时间的推移,这个模板变得太大,并且变得难以维护。
  处理日益增长的复杂性的一种方法是识别大致对应于单个特征的部分。然后我们可以将它们移动到自己的模板中,这些模板将包含在最后一个模板中。
  我们的目标是使用一些较小的模板来处理明确定义的功能配置部分。这样,当您需要进行更改时,更容易找到要修改的文件。也更容易分辨哪个模板做什么,因为我们现在可以给它们适当的名称,如"bgp.j2"和"acls.j2",而不是一个名为"device_config.j2"的大模板。
  使用前面的模板,我们可以将其分解为更小的逻辑单元:
  base.j2  hostname {{ hostname }}  banner motd ^ {% include "common/banner.j2" %} ^
  dns.j2  no ip domain lookup ip domain name local.lab ip name-server {{ name_server_pri }} ip name-server {{ name_server_sec }}
  ntp.j2  ntp server {{ ntp_server_pri }} prefer ntp server {{ ntp_server_sec }}
  interfaces.j2  {% for iname, idata in interfaces.items() -%} interface {{ iname }}  {{ idata.description }}  {{ idata.ipv4_address }} {% endfor %}
  prefix_lists.j2  {% for pl_name, pl_lines in prefix_lists.items() -%} ip prefix-list {{ pl_name }} {%- for line in pl_lines %}  {{ line -}} {%  endfor -%} {% endfor %}
  bgp.j2  router bgp {{ bgp.as_no }} {%- for peer in bgp.peers %}  neighbor {{ peer.ip }} remote-as {{ peer.as_no }}  neighbor {{ peer.ip }} description {{ peer.description }} {%- endfor %}
  我们现在有一组单独的模板,每个模板都有一个明确的名称来传达其用途。虽然我们的示例没有太多行,但我认为您会同意我的观点,即我们得出的逻辑分组将更易于使用,并且可以更快地建立关于这里发生的事情的心理模型。
  随着功能移动到单独的模板,我们终于可以使用include 语句来组成我们的最终配置模板:
  config_final.j2  {# Hostname and banner -#} {% include "base.j2" %}  {% include "dns.j2" %}  {% include "ntp.j2" %}  {% include "interfaces.j2" %}  {% include "prefix_lists.j2" %}  {# BGP instance and peering -#} {% include "bgp.j2" %}
  您打开此模板,只需快速浏览一下,您就应该能够了解它正在尝试做什么。它更简洁,我们可以轻松添加不会在数百行其他行中丢失的注释。
  作为奖励,您可以通过注释单行或简单地暂时删除它来快速测试禁用一个功能的模板。
  现在更容易进行更改,并且可以更快地识别特征和相应的模板,而不是搜索一个可能有数百行的大模板。
  同样,当需要新部分时,我们可以创建单独的模板并将其包含在最终模板中,从而实现我们增加模块化的目标。 带有"包含"的共享模板片段
  您可能还注意到其中一个包含的模板有自己的include 声明。
  base.j2  hostname {{ hostname }}  banner motd ^ {% include "common/banner.j2" %} ^
  您可以include 在模板层次结构中的任何级别以及您想要的模板中的任何位置使用语句。这正是我们在这里所做的;我们将横幅的文本移动到一个单独的文件中,然后我们将其包含在base.j2 模板中。
  我们可以争辩说,横幅本身并不重要,不足以保证有自己的模板。但是,还有另一类include 有用的用例。我们可以维护跨许多不同模板使用的通用片段库。
  这与我们之前的示例不同,在之前的示例中,我们将一个大模板分解为更小的逻辑单元,所有这些单元都与最终模板紧密相关。使用通用库,我们可以在许多不同的模板中重复使用这些单元,这些模板可能没有任何相似之处。 缺失和替代模板
  Jinja 允许我们optionally 通过ignore missing 向include .
  {% include "guest_users.j2" ignore missing %}
  它本质上告诉 Jinja 寻找guest_users.j2 模板并在找到时插入呈现的文本。如果找不到模板,这将导致空行,但不会引发错误。
  我通常建议不要在您的模板中使用它。它不是被广泛使用的东西,所以阅读您的模板的人可能不知道它的用途。最终结果还取决于特定文件的存在,这可能会使故障排除更加困难。
  有更好的方法来处理可选特性,其中一些依赖于我们将在下一篇文章中讨论的模板继承。
  与"忽略缺失"密切相关的是提供要包含的模板列表的可能性。Jinja 将检查模板是否存在,包括第一个存在的模板。
  在下面的示例中,如果local_users.j2 不存在但radius_users.j2 存在,则渲染radius_users.j2 最终将被插入。
  {% include ["local_users.j2", "radius_users.j2"] %}
  您甚至可以将模板列表与ignore missing 参数结合起来:
  {% include ["local_users.j2", "radius_users.j2"]  ignore missing   %}
  这将导致搜索列出的模板,如果没有找到它们,则不会引发错误 。
  同样,虽然很诱人,但我建议不要使用此功能,除非您用尽其他途径。如果在我的最终渲染中有些东西看起来不正确,我不会喜欢弄清楚列出的模板中的哪一个最终被包含在内。
  总而言之,您可以使用"包含"来: 将大模板拆分为较小的逻辑单元 重复使用跨多个模板共享的片段 进口声明
  在 Jinja 中,我们使用import 语句来访问保存在其他模板中的宏。这个想法是经常在他们自己的文件中使用宏,然后将这些宏导入需要它们的模板中。
  这与include 声明不同,这里不进行渲染。相反,它的工作方式与 Python 中的 import 语句非常相似。导入的宏可用于导入它们的模板。 三种导入方式
  我们可以通过三种方式导入宏。
  所有三种方式都将使用导入以下模板:
  macros/ip_funcs.j2  {% macro ip_w_wc(ip_net) -%} {{ ip_net|ipaddr("network") }} {{ ip_net|ipaddr("hostmask")}} {%- endmacro -%}  {% macro ip_w_netm(ip_net) -%} {{ ip_net|ipaddr("network") }} {{ ip_net|ipaddr("netmask") }} {%- endmacro -%}  {% macro ip_w_pfxlen(ip_net) -%} {{ ip_net|ipaddr("network/prefix") }} {%- endmacro -%} 导入整个模板并将其分配给变量。宏是变量的属性。 imp_ipfn_way1.j2  {% import "macros/ip_funcs.j2" as ipfn %} {{ ipfn.ip_w_wc("10.0.0.0/24") }} {{ ipfn.ip_w_netm("10.0.0.0/24") }} {{ ipfn.ip_w_pfxlen("10.0.0.0/24") }}  将特定宏导入当前命名空间。 imp_ipfn_way2.j2  {% from "macros/ip_funcs.j2" import ip_w_wc, ip_w_pfxlen %} {{ ip_w_wc("10.0.0.0/24") }} {{ ip_w_pfxlen("10.0.0.0/24") }}  将特定宏导入当前命名空间并为其赋予别名。 imp_ipfn_way3  {% from "macros/ip_funcs.j2" import ip_w_wc as ipwild %} {{ ipwild("10.0.0.0/24") }}
  您还可以将 2 与 3 结合起来:
  imp_ipfn_way2_3  {% from "macros/ip_funcs.j2" import ip_w_wc as ipwild, ip_w_pfxlen %}  {{ ipwild("10.0.0.0/24") }} {{ ip_w_pfxlen("10.0.0.0/24") }}
  我的建议是始终使用1 . 这迫使您通过显式命名空间访问宏。方法2 和3 风险与当前命名空间中定义的变量和宏发生冲突。正如 Jinja 中经常出现的情况一样,显式优于隐式。 缓存和上下文变量
  导入被缓存,这意味着它们在每次后续使用时都会非常快速地加载。这是要付出代价的,即导入的模板无法访问导入它们的模板中的变量。
  这意味着默认情况下,您无法访问从另一个文件导入的宏内部的上下文中传递的变量。
  相反,您必须构建宏,以便它们仅依赖于显式传递给它们的值。
  为了说明这一点,我编写了两个版本的宏命名def_if_desc ,一个尝试访问可用于模板导入的变量。另一个宏依赖于通过值显式传递给它的字典。
  两个版本都使用以下数据:
  default_desc.yaml  interfaces:  Ethernet10:    role: desktop 版本访问模板变量: macros/def_desc_ctxvars.j2  {% macro def_if_desc(ifname) -%} Unused port, dedicated to {{ interfaces[ifname].role }} devices {%- endmacro -%}  im_defdesc_vars.j2  {% import "macros/def_desc_ctxvars.j2" as desc -%} {{ desc.def_if_desc("Ethernet10") }}  当我尝试渲染时,im_defdesc_vars.j2 我得到以下回溯: ...(cut for brevity) File "F:projectsj2-tutorial	emplatesmacrosdef_desc_ctxvars.j2", line 2, in template Unused port, dedicated to {{ interfaces[ifname].descri }} devices File "F:projectsj2-tutorialvenvlibsite-packagesjinja2environment.py", line 452, in getitem return obj[argument] jinja2.exceptions.UndefinedError: "interfaces" is undefined  您可以看到 Jinja 抱怨它无法访问interfaces 。这和我们预期的一样。 通过导入模板显式传递的字典的版本访问键。 default_desc.j2  {% macro def_if_desc(intf_data) -%} Unused port, dedicated to {{ intf_data.role }} devices {%- endmacro -%}  im_defdesc.j2  {% import "macros/default_desc.j2" as desc -%} {{ desc.def_if_desc(interfaces["Ethernet10"]) }}  这渲染得很好: Unused port, dedicated to desktop devices
  希望现在您可以看到导入宏时的默认行为。由于上下文中的变量值可以随时更改,Jinja 引擎无法缓存它们,我们也不允许从宏中访问它们。 禁用宏缓存
  但是,如果出于某种原因您认为允许宏访问上下文变量是个好主意,您可以使用with context 传递给import 语句的附加参数来更改默认行为。
  Note: This will automatically disable caching.
  为了完整起见,这是我们如何"修复"失败的宏:
  macros/def_desc_ctxvars.j2  {% macro def_if_desc(ifname) -%} Unused port, dedicated to {{ interfaces[ifname].role }} devices {%- endmacro -%}
  im_defdesc_vars_wctx.j2  {% import "macros/def_desc_ctxvars.j2" as desc with context -%}  {{ desc.def_if_desc("Ethernet10") }}
  现在它起作用了: Unused port, dedicated to devices
  就个人而言,我不认为import 一起使用是一个好主意with context 。从单独的文件中导入宏的全部意义在于允许它们在其他模板中使用并利用缓存。可能有数百个,如果不是数千个,并且一旦您使用with context 缓存就消失了。
  我还可以在依赖于从模板上下文访问变量的宏中看到一些非常微妙的错误。
  为了安全起见,我会说坚持标准导入并始终使用命名空间,例如
  {% import "macros/ip_funcs.j2" as ipfn %}  结论
  我们了解了两种 Jinja 构造,它们可以帮助我们管理随着模板大小增加而出现的复杂性。通过利用import 和include 语句,我们可以提高可重用性并使我们的模板更易于维护 。我希望包含的示例向您展示了如何使用这些知识来使您的模板集合更好地组织和更容易理解。
  这是我在以下情况下使用的内容的快速摘要:
  import
  include
  目的
  从其他模板导入宏
  渲染其他模板并插入结果
  上下文变量
  不可访问(默认)
  无障碍
  适合
  创建共享宏库
  将模板拆分为逻辑单元和常用片段
  我希望你发现这篇文章很有用,并期待更多。下一篇文章将继续讨论通过模板继承来组织模板的方法。敬请关注! 参考Jinja2 导入,官方文档:https ://jinja.palletsprojects.com/en/2.11.x/templates/#import Jinja2 包含,官方文档:https ://jinja.palletsprojects.com/en/2.11.x/templates/#include 包含这篇文章资源的 GitHub 存储库。可在:https ://github.com/progala/ttl255.com/tree/master/jinja2/jinja-tutorial-p6-import-include

Hexo实战004Hexo博客目录结构浅析Hexo通过指令hexoinitfolder可以初始化构建一个hexo项目,如果没有设置folder则默认在当前的文件夹建立hexo项目。初始化会将Hexo项目从gitHub上克隆邮箱大师如何登录企业邮箱什么是电子邮箱电子邮箱(简称Email)是一种具有存储和收发电子信息功能的网络通信工具,可以为为用户传送文字图片语音附件等各类型的信息,也可以自动接收网络任何电子邮箱所发的电子邮件Git实战002Git快速入门使用详解上篇通过Git实战001Windows系统Git安装及设置详解已经安装配置好了Git,现在我们利用Gitlab来快速的实现项目git版本控制功能。Git版本控制为文件提供了3种状态Git实战004branch分支操作详解什么是分支分支指在主干道上分出来的支线,可以通往不同的地方也可以走向到同一个终点(只是实现的路线不同而已)。在Git中分支指向团队开发中的个体,每位开发者都可以拥有属于自己的分支,本地Windows系统如何向Windows云服务器上传文件最近需求在Windows云服务器上安装NX10。0版本的UG软件,该版本需要安装SiemensNX10。0。3和SiemensNX10。0。3UpdateWin64补丁包。因为NX万能的Windows定时开关机设置方法详解,不需要BIOS支持前面写了一篇文章Windows定时开关机,让你告别开机烦恼,也不用担心忘关电脑了来为电脑设置定时开关的功能,但是定时开机需要主板和BIOS的支持才能实现。在没有硬件支持的情况下我们Vue实战078权限管理实现导航菜单动态加载权限管理主要体现在对菜单操作页面等权限的控制,实现根据用户权限来动态显示不同的导航菜单操作权限及页面内容等功能。菜单的动态权限控制主要用到了VueRouter和Vuex这两个技术,Git实战005如何正确的使用同步获取和拉取指令为了更好的管理跟进掌控和维护项目开发,我们通常会借用Gitlab等代码托管平台来管理项目资源。当然我们不会将项目公开在互联网上,而是在局域网搭建属于自己的Git远程仓库服务(我司搭Hexo实战003使用GitPage部署个人博客什么是GitpageGitpage是代码托管平台提供给开发者部署个人博客用的技术,目前支持Gitpage的代码托管平台有GithubCodingGitee等。借助Gitpage我们React实战002快速入门实例HelloReact在第一篇我们顺利的搭建了React项目并简单的了解了React项目的目录结构,这里先不用管其他的文件我们主要看index。html(该文件在public目录中)和index。js(Linux实战010VMware桥接配置Centos网络VMware网络模式VMware提供了三种网络工作模式分别是Bridged(桥接模式)NAT(网络地址转换模式)HostOnly(仅主机模式),可以在Vmware虚拟机的菜单栏中选
换个智能台灯放音乐无线充AI语音居家随心所欲一盏好的台灯,不仅是照明工具,更是陪伴和氛围的制造者。但是,现在真的还有人会花点时间去选购台灯吗?平时逛商场看到设计得不错的台灯,会感叹这个灯真好看摆在家里逼格很高花大价钱买放在家微信可以听文字消息了3步教你开启据微信派微信公众号消息,微信关怀模式目前已支持听文字消息,开启该功能后,仅需点一下聊天中的文字消息就能听到。值得一提的是,无论是安卓手机,还是苹果手机,用户只要将微信更新到最新版本GIECCandyPodsTWS耳机体验惊艳的颜值还有不俗的声音表现蓝牙耳机这几年发展还是挺快的,才几年间就诞生出各种各样的耳机,并且价格也在不断地下探。同时在价格下调的同时,蓝牙耳机的性能也在不断地提升。这就诞生出很多价格实惠,性能优异的高性价比北京大中电器联合北京国美发放绿色节能消费券北京商报讯(记者何倩)4月13日,北京商报记者从北京大中电器北京国美联合举办的绿色节能消费节启动仪式上了解到,绿色节能消费节将贯穿于4月9月,为北京消费者提供以旧换新补贴节能补贴补3D打印人造骨骼,成为未来太空急救需要3D打印正在社会生产中发挥着越来越重要的作用。首先,3D打印可以缩短生产制造的时间,提高效率。用传统方法制造出一个模型通常需要数天,根据模型的尺寸以及复杂程度而定,而用3D打印技术谷歌回应公开俄军事战略设施细节传言未改变俄罗斯卫星图像模糊程度美国科技媒体TheVerge4月18日报道,谷歌表示公司未改变审查俄罗斯卫星图像的方法。此前媒体广泛报道称谷歌公开俄军事战略设施高分辨率图像。据报道,当地时间周一,未实名的推特账户再无A72遗憾搭载骁龙778G,GalaxyA73物有所值GalaxyA52是三星去年最好的综合中端手机。GalaxyA72紧随其后,搭载了许多有趣的功能(包括3倍光学长焦摄像头),但三星在其最重要的一个方面做出了妥协GalaxyA72搭因价格错误瑞幸咖啡暂时关闭饿了么平台上门店北京商报讯(记者赵述评张天元)4月18日,瑞幸咖啡发布道歉信。其中显示,由于饿了么后台价格配置问题,导致瑞幸椰云套餐价格短时内出现错误,门店受到大量异常订单挤压。为正常运营,瑞幸咖为何要高频次重复地做核酸检测?专家回应来源央视新闻客户端17日上午举行的上海市疫情防控工作新闻发布会上,上海中医药大学附属岳阳中西医结合医院检验实验中心主任高春芳就目前仍在进行的高频次核酸检测的原因做了说明。高春芳表示浩瀚宇宙,无奇不有,有没有可能存在魔法文明和修仙文明?在人类的幻想之中,还存在其他和人类科技文明完全不同的文明形态,比如说魔法文明和修仙文明。人类的想象力是没有极限的,在我们的想象中,任何不可能发生的事情都有可能实现。那么宇宙这么大,总结一下4月份未来10天的新品发布会,可谓手机圈的干架4月份注定不平凡,可谓是惊喜连连不断。眼看4月份只剩下十一天,在这些时间内将举行诸多新品发布会,看看有没有你期待的,本人最喜欢的vivox80系列了吧!4月19日周二1908Hin