Python dominate庫:用代碼優(yōu)雅生成HTML的完整指南
1. 項(xiàng)目概述為什么我們需要一個(gè)優(yōu)雅的HTML生成方案在Python的世界里生成HTML文檔聽起來是個(gè)再基礎(chǔ)不過的需求。無論是構(gòu)建一個(gè)簡單的報(bào)告頁面、開發(fā)一個(gè)內(nèi)部管理工具的后臺(tái)模板還是為Web應(yīng)用動(dòng)態(tài)生成郵件內(nèi)容我們總免不了要和HTML打交道。新手最直接的想法可能是用字符串拼接html htmlheadtitle title /title/head。稍微進(jìn)階一點(diǎn)可能會(huì)用上format方法或者f-string。我早期也這么干過直到一個(gè)項(xiàng)目里一個(gè)嵌套了五層的復(fù)雜表格加上各種動(dòng)態(tài)屬性讓我的代碼變成了一團(tuán)難以維護(hù)、充斥著轉(zhuǎn)義字符和加號(hào)的“意大利面條”。調(diào)試一個(gè)缺失的閉合標(biāo)簽就像在迷宮里找出口。后來我們知道了模板引擎比如Jinja2。它確實(shí)解決了動(dòng)態(tài)內(nèi)容和結(jié)構(gòu)的分離問題但對(duì)于一些需要完全用代碼邏輯來構(gòu)建和組裝DOM樹的場景比如根據(jù)實(shí)時(shí)數(shù)據(jù)流生成結(jié)構(gòu)多變的HTML片段或者編寫一個(gè)生成HTML的庫或工具時(shí)在Python代碼和模板文件之間來回切換有時(shí)會(huì)顯得不夠“原生”和流暢。我們渴望一種方式能像在Python中操作列表和字典一樣自然地操作HTML元素。這就是dominate庫出現(xiàn)的意義。它不是一個(gè)模板引擎而是一個(gè)用于創(chuàng)建和操作HTML/XML文檔的純Python庫。它的核心哲學(xué)是“Pythonic”——讓你用Python的語法和思維來構(gòu)建HTML。你不再需要手動(dòng)拼接字符串而是通過創(chuàng)建對(duì)象、設(shè)置屬性、添加子元素的方式來“組裝”你的文檔。代碼即結(jié)構(gòu)清晰、直觀并且得益于Python的語法特性能極大地減少因標(biāo)簽不匹配或?qū)傩赞D(zhuǎn)義錯(cuò)誤導(dǎo)致的Bug。簡單來說如果你遇到過以下任何一種情況dominate都值得你深入了解需要從零開始完全用代碼邏輯生成一個(gè)完整的HTML文檔。生成的HTML結(jié)構(gòu)復(fù)雜且動(dòng)態(tài)性強(qiáng)用字符串模板寫起來很痛苦。你希望生成HTML的代碼本身具有良好的可讀性和可維護(hù)性。你正在開發(fā)一個(gè)工具其輸出是HTML格式你希望輸出模塊干凈、優(yōu)雅。dominate讓生成HTML這件事從一門“手藝活”變成了“組裝樂高”優(yōu)雅且高效。2. Dominate 核心設(shè)計(jì)與思路拆解2.1 面向?qū)ο笈c流暢接口Dominate的設(shè)計(jì)哲學(xué)dominate的設(shè)計(jì)非常巧妙它深度借鑒了現(xiàn)代前端開發(fā)中“一切皆組件”的思想并將其與Python的面向?qū)ο筇匦越Y(jié)合。在dominate眼里HTML文檔中的每一個(gè)標(biāo)簽Tag都是一個(gè)Python對(duì)象。div是一個(gè)div()對(duì)象a是一個(gè)a()對(duì)象html本身也是一個(gè)html()對(duì)象。這種設(shè)計(jì)的第一個(gè)巨大優(yōu)勢是類型安全與IDE友好。當(dāng)你輸入d div()后IDE的代碼補(bǔ)全功能可以提示你d這個(gè)對(duì)象有哪些方法如add,set_attribute和屬性。相比之下在字符串模板里“div”只是一個(gè)普通的字符串沒有任何語義信息。第二個(gè)優(yōu)勢是流暢接口Fluent Interface。dominate中大部分方法都返回對(duì)象本身self這允許你將多個(gè)操作鏈接在一起寫成一行流暢的代碼。例如你可以這樣創(chuàng)建并設(shè)置一個(gè)鏈接a(“點(diǎn)擊這里”, href“#”, cls“btn”).set_attribute(“data-id”, 123)。這行代碼依次完成了創(chuàng)建a標(biāo)簽對(duì)象、設(shè)置其文本內(nèi)容、設(shè)置href和class屬性、再設(shè)置一個(gè)自定義的># 使用pip安裝這是最推薦的方式 pip install dominate # 如果你使用Poetry管理項(xiàng)目 poetry add dominate # 或者使用Pipenv pipenv install dominate安裝完成后你可以通過導(dǎo)入dominate包下的document和各個(gè)標(biāo)簽類來開始使用。一個(gè)常見的實(shí)踐是直接導(dǎo)入整個(gè)dominate包或者導(dǎo)入你常用的標(biāo)簽。# 方式一導(dǎo)入document和所需標(biāo)簽 from dominate import document from dominate.tags import * # 方式二導(dǎo)入整個(gè)tags模塊個(gè)人更推薦清晰明了 from dominate.tags import *注意使用from dominate.tags import *雖然方便但會(huì)“污染”你的命名空間將大量HTML標(biāo)簽名如div,p,a引入為函數(shù)。在大型項(xiàng)目或模塊中為了更清晰可以考慮只導(dǎo)入需要的標(biāo)簽或者使用import dominate.tags as tags然后通過tags.div()的方式調(diào)用。3.2 理解文檔、標(biāo)簽與上下文管理器這是dominate最核心的三個(gè)概念理解了它們你就掌握了dominate的八成功力。1. 文檔Documentdocument對(duì)象代表整個(gè)HTML文檔。它是你所有內(nèi)容的根容器。創(chuàng)建文檔時(shí)你可以指定一些全局屬性比如title、lang語言、是否包含!DOCTYPE html聲明等。from dominate import document # 創(chuàng)建一個(gè)基本的HTML5文檔 doc document(title‘我的優(yōu)雅網(wǎng)頁’) # 查看當(dāng)前文檔的字符串表示 print(doc) # 此時(shí)只有基本的框架沒有body內(nèi)容2. 標(biāo)簽Tag每一個(gè)HTML元素都對(duì)應(yīng)一個(gè)函數(shù)。調(diào)用這個(gè)函數(shù)就創(chuàng)建了一個(gè)標(biāo)簽對(duì)象。函數(shù)參數(shù)非常靈活第一個(gè)參數(shù)通常是標(biāo)簽的文本內(nèi)容字符串或者是另一個(gè)標(biāo)簽/可迭代對(duì)象作為子元素。關(guān)鍵字參數(shù)絕大多數(shù)會(huì)直接轉(zhuǎn)換為HTML屬性。例如href“#”,cls“container”注意因?yàn)閏lass是Python關(guān)鍵字所以用cls代替data_toggle“modal”下劃線會(huì)被轉(zhuǎn)換為連字符>from dominate.tags import * # 創(chuàng)建一個(gè)帶文本的段落 p1 p(“這是一個(gè)段落。”) # 創(chuàng)建一個(gè)帶屬性和子元素的div div1 div(cls“box”, data_id“1”) div1.add(h1(“標(biāo)題”)) # 使用add方法添加子元素3. 上下文管理器with語句—— 精髓所在這是dominate實(shí)現(xiàn)優(yōu)雅嵌套結(jié)構(gòu)的秘密武器。通過Python的with語句你可以建立一個(gè)臨時(shí)的“上下文”在這個(gè)上下文中創(chuàng)建的所有標(biāo)簽都會(huì)自動(dòng)成為當(dāng)前“上下文標(biāo)簽”的子元素。這完美模擬了HTML的嵌套結(jié)構(gòu)且代碼縮進(jìn)直接反映了DOM的層級(jí)一目了然。from dominate import document from dominate.tags import * doc document(title‘測試’) with doc.head: meta(charset“utf-8”) meta(name“viewport”, content“widthdevice-width, initial-scale1.0”) link(rel“stylesheet”, href“style.css”) with doc: with div(id“app”, cls“container”): h1(“歡迎使用Dominate”) with ul(cls“nav”): li(a(“首頁”, href“/”)) li(a(“關(guān)于”, href“/about”)) p(“這里是用Python優(yōu)雅生成的頁面內(nèi)容。”) print(doc)這段代碼生成的HTML結(jié)構(gòu)清晰與Python代碼的縮進(jìn)完全對(duì)應(yīng)。with doc:表示接下來的元素是html的直接子元素即bodydominate會(huì)自動(dòng)處理。with div(...):表示在div內(nèi)部創(chuàng)建子元素。這種方式徹底告別了手動(dòng)管理閉合標(biāo)簽的噩夢。3.3 屬性、樣式與事件處理的特殊技巧屬性設(shè)置除了在創(chuàng)建標(biāo)簽時(shí)傳入還可以用set_attribute方法動(dòng)態(tài)設(shè)置。對(duì)于>btn button(“提交”) btn.set_attribute(“type”, “submit”) btn[“disabled”] “disabled” # 也可以像字典一樣操作樣式CSS處理dominate提供了非常靈活的方式來處理內(nèi)聯(lián)樣式。字符串形式直接傳遞一個(gè)樣式字符串。div(style“color: red; font-size: 16px;”)字典形式推薦更Pythonic更易編程操作。styles {“color”: “red”, “font-size”: “16px”, “display”: “none”} div(stylestyles) # 動(dòng)態(tài)修改 my_div div() my_div.style[“color”] “blue”事件處理對(duì)于onclick,onmouseover等事件處理器可以直接作為屬性傳入。但請(qǐng)注意dominate只負(fù)責(zé)生成HTML字符串事件處理函數(shù)JavaScript需要你另行定義。btn button(“點(diǎn)我”, onclick“alert(‘Hello!’)”)實(shí)操心得對(duì)于復(fù)雜的樣式或大量的>attrs {“id”: “user-123”, “data_role”: “admin”, “data_department”: “IT”} user_div div(“張三”, **attrs)4. 實(shí)操過程從零構(gòu)建一個(gè)完整的HTML報(bào)告頁面讓我們通過一個(gè)實(shí)際案例將上述知識(shí)點(diǎn)串聯(lián)起來。假設(shè)我們需要為一個(gè)內(nèi)部數(shù)據(jù)分析系統(tǒng)生成一個(gè)用戶行為報(bào)告頁面包含標(biāo)題、摘要表格、趨勢圖和詳情列表。4.1 初始化文檔與頭部信息任何規(guī)范的HTML文檔都應(yīng)以正確的DOCTYPE開頭并包含必要的head信息。dominate的document對(duì)象默認(rèn)就會(huì)幫我們做好這些。from dominate import document from dominate.tags import * from datetime import datetime # 1. 創(chuàng)建文檔設(shè)置標(biāo)題和語言 report_title f“用戶行為分析報(bào)告 - {datetime.now().strftime(‘%Y-%m-%d’)}” doc document(titlereport_title, lang“zh-CN”) # 2. 構(gòu)建頭部 (head) with doc.head: meta(charset“UTF-8”) meta(name“viewport”, content“widthdevice-width, initial-scale1.0”) # 引入Bootstrap CSS使頁面快速美化示例用CDN link( rel“stylesheet”, href“https://cdn.jsdelivr.net/npm/bootstrap5.1.3/dist/css/bootstrap.min.css”, integrity“sha384-...”, # 實(shí)際使用時(shí)請(qǐng)?zhí)顚懻_的integrity hash crossorigin“anonymous” ) # 引入Chart.js用于繪制圖表 script( src“https://cdn.jsdelivr.net/npm/chart.js”, defer“” # defer屬性確保腳本在頁面解析后執(zhí)行 ) # 自定義樣式 style(“”” body { font-family: ‘Segoe UI’, sans-serif; padding-top: 20px; } .summary-card { border-left: 4px solid #0d6efd; } .chart-container { position: relative; height: 300px; } “””)這里我們使用了with doc.head:上下文管理器來向head中添加元素。我們引入了Bootstrap和Chart.js這兩個(gè)外部庫來簡化樣式和圖表繪制并添加了少量內(nèi)聯(lián)自定義樣式。4.2 構(gòu)建頁面主體布局與摘要卡片接下來我們構(gòu)建頁面的主體內(nèi)容。我們將使用Bootstrap的網(wǎng)格系統(tǒng)來創(chuàng)建響應(yīng)式布局。with doc: # 使用Bootstrap容器 with div(cls“container”): # 報(bào)告標(biāo)題 h1(report_title, cls“mb-4 text-primary”) hr() # 第一行關(guān)鍵指標(biāo)摘要卡片 with div(cls“row mb-4”): # 假設(shè)我們從某個(gè)數(shù)據(jù)源獲取了這些指標(biāo) summary_data [ {“title”: “總訪問量”, “value”: “124,567”, “change”: “12.5%”, “color”: “info”}, {“title”: “獨(dú)立訪客”, “value”: “23,456”, “change”: “5.2%”, “color”: “success”}, {“title”: “平均停留時(shí)長”, “value”: “3m 45s”, “change”: “-0.3%”, “color”: “warning”}, {“title”: “轉(zhuǎn)化率”, “value”: “2.34%”, “change”: “0.8%”, “color”: “danger”}, ] for item in summary_data: with div(cls“col-md-3 col-sm-6 mb-3”): with div(cls“card summary-card shadow-sm h-100”): with div(cls“card-body”): h5(item[“title”], cls“card-title text-muted”) # 使用flex布局排列數(shù)值和變化率 with div(cls“d-flex justify-content-between align-items-end”): h2(item[“value”], cls“card-text mb-0”) span(item[“change”], clsf“badge bg-{item[‘color’]}”)這段代碼展示了dominate如何與Python邏輯for循環(huán)無縫結(jié)合。我們遍歷summary_data列表為每個(gè)指標(biāo)動(dòng)態(tài)生成一個(gè)Bootstrap卡片。代碼的縮進(jìn)層級(jí)清晰地對(duì)應(yīng)了HTML的嵌套結(jié)構(gòu)container-row-col-md-3-card-card-body- 內(nèi)部元素。4.3 動(dòng)態(tài)生成數(shù)據(jù)表格與圖表占位符報(bào)告通常需要展示詳細(xì)數(shù)據(jù)。我們將創(chuàng)建一個(gè)表格和一個(gè)為JavaScript圖表準(zhǔn)備的畫布。# 第二行詳細(xì)數(shù)據(jù)表格 h2(“詳細(xì)數(shù)據(jù)”, cls“mt-5 mb-3”) # 模擬數(shù)據(jù) table_data [ {“date”: “2023-10-26”, “visits”: 8456, “users”: 1523, “bounce_rate”: “32.1%”}, {“date”: “2023-10-25”, “visits”: 8123, “users”: 1489, “bounce_rate”: “31.5%”}, # ... 更多數(shù)據(jù)行 ] with table(cls“table table-striped table-hover”): # 表頭 with thead(cls“table-dark”): with tr(): th(“日期”, scope“col”) th(“訪問量”, scope“col”) th(“獨(dú)立用戶”, scope“col”) th(“跳出率”, scope“col”) # 表體 with tbody(): for row in table_data: with tr(): td(row[“date”]) td(f”{row[‘visits’]:,}”) # 千位分隔符格式化 td(f”{row[‘users’]:,}”) td(row[“bounce_rate”]) # 第三行趨勢圖 h2(“訪問量趨勢”, cls“mt-5 mb-3”) with div(cls“chart-container”): canvas(id“visitTrendChart”) # 為Chart.js提供一個(gè)畫布注意表格中td(f”{row[‘visits’]:,}”)的用法這是Python的格式化字符串語法用于給數(shù)字添加千位分隔符使得展示更友好。canvas標(biāo)簽只是一個(gè)占位符真正的圖表將由后面引入的Chart.js庫通過JavaScript渲染。4.4 嵌入JavaScript與最終渲染為了激活圖表我們需要在頁面底部添加一段JavaScript代碼。同時(shí)我們需要將dominate文檔對(duì)象渲染成最終的HTML字符串。# 在body末尾添加腳本 with script(): # 這里使用JavaScript模板字符串反引號(hào)來嵌入Python變量 # 注意在Python字符串中表示JavaScript反引號(hào)需要轉(zhuǎn)義 labels [row[‘date’] for row in table_data] data [row[‘visits’] for row in table_data] # 構(gòu)建JavaScript代碼字符串。在實(shí)際復(fù)雜場景中可以考慮使用json.dumps來序列化數(shù)據(jù)。 js_code f“”” const ctx document.getElementById(‘visitTrendChart’).getContext(‘2d’); const myChart new Chart(ctx, {{ type: ‘line’, data: {{ labels: {labels}, datasets: [{{ label: ‘日訪問量’, data: {data}, borderColor: ‘rgb(75, 192, 192)’, tension: 0.1 }}] }}, options: {{ responsive: true, maintainAspectRatio: false }} }}); “”” # dominate會(huì)正確處理script標(biāo)簽內(nèi)的內(nèi)容 raw(js_code) # 使用raw函數(shù)防止字符串被HTML轉(zhuǎn)義 # 最終將文檔渲染為字符串 html_output doc.render() print(html_output) # 可以打印到控制臺(tái)查看 # 或者寫入文件 with open(‘user_behavior_report.html’, ‘w’, encoding‘utf-8’) as f: f.write(html_output)這里的關(guān)鍵點(diǎn)是raw()函數(shù)。dominate默認(rèn)會(huì)對(duì)所有字符串內(nèi)容進(jìn)行HTML轉(zhuǎn)義例如將轉(zhuǎn)成lt;以防止XSS攻擊。但在script標(biāo)簽內(nèi)我們需要的是原始的JavaScript代碼而不是轉(zhuǎn)義后的文本。raw()函數(shù)告訴dominate“這段內(nèi)容不用轉(zhuǎn)義原樣輸出”。這在需要嵌入JSON數(shù)據(jù)或復(fù)雜JS邏輯時(shí)至關(guān)重要。至此一個(gè)結(jié)構(gòu)完整、樣式美觀、包含動(dòng)態(tài)數(shù)據(jù)和交互圖表的HTML報(bào)告頁面就完全通過Python代碼生成了。打開生成的user_behavior_report.html文件你就能在瀏覽器中看到效果。5. 常見問題與排查技巧實(shí)錄在實(shí)際使用dominate的過程中你可能會(huì)遇到一些典型問題。下面是我踩過坑后總結(jié)出來的經(jīng)驗(yàn)。5.1 標(biāo)簽嵌套錯(cuò)誤與上下文管理器的誤用問題現(xiàn)象生成的HTML結(jié)構(gòu)混亂或者某些元素出現(xiàn)在了意想不到的位置。根本原因with語句的縮進(jìn)沒有正確反映你想要的DOM層級(jí)或者錯(cuò)誤地混用了add()方法和上下文管理器。排查技巧堅(jiān)持單一風(fēng)格在一個(gè)代碼塊內(nèi)盡量統(tǒng)一使用with上下文管理器來嵌套子元素。避免在with塊內(nèi)又頻繁使用add()這會(huì)讓邏輯變得難以追蹤。檢查縮進(jìn)Python的縮進(jìn)就是你的DOM結(jié)構(gòu)圖。確保每個(gè)with語句后的代碼塊縮進(jìn)代表了正確的父子關(guān)系。使用render(prettyTrue)調(diào)試在調(diào)試階段使用doc.render(prettyTrue, indent‘ ‘)來生成格式化的HTML輸出。漂亮的縮進(jìn)能讓你一眼看出結(jié)構(gòu)問題。print(doc.render(prettyTrue, indent‘ ‘))錯(cuò)誤示例與修正# 錯(cuò)誤div2本應(yīng)是div1的子元素但因?yàn)闆]有使用with它成了兄弟元素。 with div(id“div1”): p(“Inside div1”) div(id“div2”) # 這行與with塊同級(jí)是div1的兄弟節(jié)點(diǎn)而非子節(jié)點(diǎn) # 正確使用with將div2嵌套進(jìn)div1 with div(id“div1”): p(“Inside div1”) with div(id“div2”): p(“Inside div2”)5.2 屬性名沖突與特殊屬性處理問題現(xiàn)象設(shè)置的屬性沒有出現(xiàn)在生成的HTML中或者屬性名不對(duì)。常見原因Python關(guān)鍵字沖突最典型的就是class。必須使用cls或_class。屬性名包含連字符例如>Python 代碼生成的 HTML 屬性div(cls“container”)div class“container”div(_class“container”)div class“container”button(disabledTrue)button disabledbutton(disabledFalse)(屬性被忽略)input(type“checkbox”, checkedNone)input type“checkbox”div(data_user_id“123”, aria_hidden“true”)div>from dominate.util import raw # 假設(shè)我們有一段來自可信源的HTML片段 trusted_html “strong加粗文本/strong 和 em斜體文本/em” # 錯(cuò)誤會(huì)被轉(zhuǎn)義 div(f“內(nèi)容{trusted_html}”) # 輸出內(nèi)容lt;stronggt;加粗文本lt;/stronggt;... # 正確使用raw div(“內(nèi)容”, raw(trusted_html)) # 輸出內(nèi)容strong加粗文本/strong...重要安全提醒絕對(duì)不要對(duì)來自用戶輸入、外部API等不可信源的數(shù)據(jù)使用raw()。這會(huì)導(dǎo)致嚴(yán)重的XSS安全漏洞。對(duì)于不可信數(shù)據(jù)應(yīng)依賴dominate的自動(dòng)轉(zhuǎn)義或使用專門的HTML清理庫如bleach處理后再用raw()。5.4 性能考量與大型文檔處理問題當(dāng)需要生成一個(gè)包含成千上萬個(gè)節(jié)點(diǎn)的超大HTML文檔比如導(dǎo)出大量數(shù)據(jù)的表格時(shí)直接使用dominate在內(nèi)存中構(gòu)建整個(gè)DOM樹可能會(huì)導(dǎo)致性能下降或內(nèi)存消耗過高。優(yōu)化策略流式生成與寫入不要一次性在內(nèi)存中構(gòu)建完整的document對(duì)象再渲染??梢苑謮K生成HTML字符串并直接寫入文件。with open(‘large_report.html’, ‘w’, encoding‘utf-8’) as f: f.write(‘!DOCTYPE htmlhtmlhead.../headbody’) f.write(‘table’) for chunk in data_chunks: # 分批處理數(shù)據(jù) rows_html “” for row in chunk: # 對(duì)小片段使用dominate或字符串格式化 rows_html f“trtd{row[‘id’]}/td.../tr” f.write(rows_html) f.write(‘/table/body/html’)混合使用對(duì)于結(jié)構(gòu)固定的框架部分如頭部、尾部、側(cè)邊欄使用dominate生成并緩存為字符串。對(duì)于海量的動(dòng)態(tài)數(shù)據(jù)行部分使用更輕量的字符串模板或f-string生成然后拼接。這樣既保持了主要代碼的優(yōu)雅又兼顧了性能。評(píng)估需求首先確認(rèn)是否真的需要一次性生成如此龐大的HTML。對(duì)于海量數(shù)據(jù)分頁、異步加載或直接提供CSV/Excel下載可能是更好的用戶體驗(yàn)。5.5 與其他庫的集成實(shí)踐dominate生成的最終產(chǎn)物是HTML字符串這使它能夠輕松地與任何其他輸出HTML的Python框架或工具集成。與Web框架Flask/FastAPI集成from flask import Flask, Response from dominate import document from dominate.tags import * app Flask(__name__) app.route(‘/report’) def generate_report(): doc document(title“動(dòng)態(tài)報(bào)告”) with doc: h1(“實(shí)時(shí)數(shù)據(jù)報(bào)告”) p(f“生成于{datetime.now()}”) # ... 更多動(dòng)態(tài)內(nèi)容 # 直接返回渲染后的HTML字符串 return Response(doc.render(), mimetype‘text/html’)生成郵件HTML內(nèi)容import smtplib from email.mime.text import MIMEText from dominate import document from dominate.tags import * def create_email_body(user_name): doc document(title“通知郵件”) with doc.body: h3(f“親愛的 {user_name}”) p(“您本月的數(shù)據(jù)報(bào)告已生成請(qǐng)查收附件?!? with div(style“text-align: center; margin-top: 20px;”): a(“點(diǎn)擊查看詳情”, href“https://example.com/report”, style“padding: 10px 20px; background: #007bff; color: white; text-decoration: none; border-radius: 5px;”) return doc.render() # 然后使用email庫發(fā)送 msg MIMEText(create_email_body(“張三”), ‘html’, ‘utf-8’) # ... 設(shè)置發(fā)件人、收件人、主題等 # server.send_message(msg)與Jinja2模板互補(bǔ)你可以用dominate生成一個(gè)復(fù)雜的、可復(fù)用的組件比如一個(gè)導(dǎo)航欄、一個(gè)卡片組件將其渲染為HTML字符串然后作為變量傳入Jinja2模板。# 用dominate定義一個(gè)組件函數(shù) def generate_navbar(active_page): with dominate.tags.nav(cls“navbar”): # ... 復(fù)雜的導(dǎo)航欄生成邏輯 if active_page “home”: a(“首頁”, href“#”, cls“active”) else: a(“首頁”, href“#”) # ... return nav.render() # 在Flask視圖函數(shù)中 navbar_html generate_navbar(“home”) return render_template(‘base.html’, navbarnavbar_html)在Jinja2模板base.html中使用{{ navbar|safe }}來插入這個(gè)安全的HTML片段。通過以上這些場景和技巧你應(yīng)該能充分感受到dominate在“用代碼優(yōu)雅生成HTML”這件事上的強(qiáng)大與便利。它填補(bǔ)了Python生態(tài)中一個(gè)特定的需求空白讓程序化構(gòu)建HTML文檔變得既嚴(yán)謹(jǐn)又富有表達(dá)力。下次當(dāng)你需要從數(shù)據(jù)中“生長”出一個(gè)網(wǎng)頁時(shí)不妨試試dominate它很可能會(huì)成為你工具箱中一件稱手的利器。

相關(guān)新聞

GPU顯存“慢性失血”正在吞噬你的ROI——2024最危險(xiǎn)的AI內(nèi)存泄漏TOP3(僅剩最后17份調(diào)試模板)

GPU顯存“慢性失血”正在吞噬你的ROI——2024最危險(xiǎn)的AI內(nèi)存泄漏TOP3(僅剩最后17份調(diào)試模板)

更多請(qǐng)點(diǎn)擊: https://codechina.net 第一章:GPU顯存“慢性失血”的ROI危機(jī)本質(zhì) 當(dāng)訓(xùn)練一個(gè)中等規(guī)模的Transformer模型時(shí),開發(fā)者常觀察到顯存占用隨迭代輪次緩慢上升——并非OOM崩潰,而是每輪增加數(shù)十MB,數(shù)小時(shí)后顯存耗…

2026/8/1 11:40:37 閱讀更多
深入解析RestTemplate:Java HTTP客戶端核心原理、配置優(yōu)化與實(shí)戰(zhàn)避坑指南

深入解析RestTemplate:Java HTTP客戶端核心原理、配置優(yōu)化與實(shí)戰(zhàn)避坑指南

1. 項(xiàng)目概述:為什么RestTemplate依然是Java開發(fā)者的“老朋友” 在微服務(wù)架構(gòu)大行其道的今天,服務(wù)間的HTTP通信成了家常便飯。提起Java里做HTTP客戶端,很多開發(fā)者會(huì)立刻想到Feign、OkHttp,甚至是Spring 5引入的WebClient。但如果你…

2026/8/1 11:40:37 閱讀更多
三分鐘搞定全網(wǎng)免費(fèi)音樂:MusicFree插件終極配置指南

三分鐘搞定全網(wǎng)免費(fèi)音樂:MusicFree插件終極配置指南

三分鐘搞定全網(wǎng)免費(fèi)音樂:MusicFree插件終極配置指南 【免費(fèi)下載鏈接】MusicFreePlugins MusicFree播放插件 項(xiàng)目地址: https://gitcode.com/gh_mirrors/mu/MusicFreePlugins 還在為音樂平臺(tái)的VIP限制而煩惱嗎?想要一個(gè)真正免費(fèi)、跨平臺(tái)的音樂解決…

2026/8/1 11:30:37 閱讀更多
STC89C52驅(qū)動(dòng)DS18B20:單總線協(xié)議深度解析與穩(wěn)定測溫實(shí)戰(zhàn)

STC89C52驅(qū)動(dòng)DS18B20:單總線協(xié)議深度解析與穩(wěn)定測溫實(shí)戰(zhàn)

1. 項(xiàng)目緣起:為什么還在用STC89C52和DS18B20?最近在整理一些老項(xiàng)目的資料,翻出來一個(gè)基于STC89C52和DS18B20的溫度監(jiān)測小模塊??赡苡腥藭?huì)問,現(xiàn)在STM32、ESP32滿天飛,性能強(qiáng)、外設(shè)多、開發(fā)方便,為什么還要去…

2026/8/1 12:50:41 閱讀更多
公寓管理軟件對(duì)比:全房通、好房通、悅居通,入住交割怎么選?

公寓管理軟件對(duì)比:全房通、好房通、悅居通,入住交割怎么選?

連鎖中介開始經(jīng)營公寓直營業(yè)務(wù)后,入住交割往往是最能檢驗(yàn)系統(tǒng)能力的環(huán)節(jié)。它不只是簽完合同后把鑰匙交給租客,而是要同步確認(rèn)房屋狀態(tài)、家具家電、門鎖權(quán)限、水電底數(shù)、費(fèi)用賬單、服務(wù)責(zé)任和門店業(yè)績。公寓管理軟件如果只覆蓋合同或成交,交割…

2026/8/1 12:50:41 閱讀更多
10.1寸HDMI屏幕硬件解析與嵌入式開發(fā)實(shí)戰(zhàn):從接口驅(qū)動(dòng)到EMC設(shè)計(jì)

10.1寸HDMI屏幕硬件解析與嵌入式開發(fā)實(shí)戰(zhàn):從接口驅(qū)動(dòng)到EMC設(shè)計(jì)

1. 項(xiàng)目概述:一塊自帶“房子”的10.1寸HDMI屏幕如果你正在為你的樹莓派、RK3588開發(fā)板,甚至是迷你PC尋找一塊即插即用、顏值在線的便攜屏幕,那么“10.1inch HDMI LCD (B) (with case)”這個(gè)標(biāo)題,很可能就是你正在尋找的答案。這不…

2026/8/1 12:50:41 閱讀更多
OpenSSL EVP對(duì)稱加密接口詳解:從算法抽象到AEAD實(shí)戰(zhàn)

OpenSSL EVP對(duì)稱加密接口詳解:從算法抽象到AEAD實(shí)戰(zhàn)

1. 從“裸奔”到“標(biāo)準(zhǔn)接口”:為什么我們需要EVP系列函數(shù)如果你在C/C里搞過對(duì)稱加解密,大概率是從AES_encrypt、AES_decrypt這類直接調(diào)用底層算法的函數(shù)開始的。代碼寫起來挺直接,但很快就發(fā)現(xiàn)不對(duì)勁:你得自己處理分組模式&#x…

2026/8/1 12:50:41 閱讀更多
SEO實(shí)戰(zhàn):長尾關(guān)鍵詞與內(nèi)容優(yōu)化提升流量

SEO實(shí)戰(zhàn):長尾關(guān)鍵詞與內(nèi)容優(yōu)化提升流量

1. 為什么SEO仍然是流量增長的核心引擎 在信息爆炸的時(shí)代,網(wǎng)站流量獲取成本越來越高。我運(yùn)營過十幾個(gè)不同行業(yè)的網(wǎng)站,發(fā)現(xiàn)那些依賴付費(fèi)廣告的站點(diǎn)一旦停止投放,流量就會(huì)斷崖式下跌。而那些持續(xù)做好SEO的網(wǎng)站,即使三年不更新廣告&a…

2026/8/1 12:50:41 閱讀更多
2026年商用工業(yè)通用UL變壓器貨源廠家盤點(diǎn)

2026年商用工業(yè)通用UL變壓器貨源廠家盤點(diǎn)

在全球商用與工業(yè)電氣系統(tǒng)中,UL認(rèn)證變壓器早已成為項(xiàng)目合規(guī)落地的核心門檻。尤其在出口北美市場、高端智能制造、數(shù)據(jù)中心、新能源配套等場景,一臺(tái)穩(wěn)定可靠的UL變壓器,直接關(guān)系到整線設(shè)備的安全認(rèn)證與長期運(yùn)行效率。2026年,隨著供…

2026/8/1 12:40:41 閱讀更多
AMAT 0100-02186 I/O 分配 PCB

AMAT 0100-02186 I/O 分配 PCB

AMAT 0100-02186 I/O分配PCB板是應(yīng)用材料(Applied Materials)公司生產(chǎn)的一款用于半導(dǎo)體設(shè)備的I/O信號(hào)分配電路板。該型號(hào)(0100-02186)的核心特點(diǎn)如下:專用于Endura等半導(dǎo)體工藝腔室。集成信號(hào)路由與分配功能。連接控制…

2026/8/1 0:09:33 閱讀更多
Nissei Corp FFMN-32L-10-T0 40AX 三相異步電動(dòng)機(jī)

Nissei Corp FFMN-32L-10-T0 40AX 三相異步電動(dòng)機(jī)

Nissei Corp FFMN-32L-10-T0 40AX 三相異步電動(dòng)機(jī)是日本日清(Nissei)品牌的一款工業(yè)用三相異步電機(jī),適用于自動(dòng)化設(shè)備及通用機(jī)械驅(qū)動(dòng)。該型號(hào)(FFMN-32L-10-T0 40AX)的核心特點(diǎn)如下:三相交流異步電動(dòng)機(jī)。額定…

2026/8/1 0:09:33 閱讀更多
AMAT 0100-02186 I/O 分配 PCB

AMAT 0100-02186 I/O 分配 PCB

AMAT 0100-02186 I/O分配PCB板是應(yīng)用材料(Applied Materials)公司生產(chǎn)的一款用于半導(dǎo)體設(shè)備的I/O信號(hào)分配電路板。該型號(hào)(0100-02186)的核心特點(diǎn)如下:專用于Endura等半導(dǎo)體工藝腔室。集成信號(hào)路由與分配功能。連接控制…

2026/8/1 0:09:33 閱讀更多
Nissei Corp FFMN-32L-10-T0 40AX 三相異步電動(dòng)機(jī)

Nissei Corp FFMN-32L-10-T0 40AX 三相異步電動(dòng)機(jī)

Nissei Corp FFMN-32L-10-T0 40AX 三相異步電動(dòng)機(jī)是日本日清(Nissei)品牌的一款工業(yè)用三相異步電機(jī),適用于自動(dòng)化設(shè)備及通用機(jī)械驅(qū)動(dòng)。該型號(hào)(FFMN-32L-10-T0 40AX)的核心特點(diǎn)如下:三相交流異步電動(dòng)機(jī)。額定…

2026/8/1 0:09:33 閱讀更多