Django_渲染詳解

来源:https://www.cnblogs.com/ivanlee717/archive/2022/09/15/16695109.html
-Advertisement-
Play Games

Django_render 模板語法 模板引擎是一種可以讓開發者把服務端數據填充到html網頁中完成渲染效果的技術。它實現了把前端代碼和服務端代碼分離的作用,讓項目中的業務邏輯代碼和數據表現代碼分離,讓前端開發者和服務端開發者可以更好的完成協同開發。 靜態網頁:頁面上的數據都是寫死的,萬年不變 動態 ...


Django_render

模板語法

模板引擎是一種可以讓開發者把服務端數據填充到html網頁中完成渲染效果的技術。它實現了把前端代碼和服務端代碼分離的作用,讓項目中的業務邏輯代碼和數據表現代碼分離,讓前端開發者和服務端開發者可以更好的完成協同開發。

靜態網頁:頁面上的數據都是寫死的,萬年不變

動態網頁:頁面上的數據是從後端動態獲取的(比如後端獲取當前時間;後端獲取資料庫數據然後傳遞給前端頁面)

Django框架中內置了web開發領域非常出名的一個DjangoTemplate模板引擎(DTL)。DTL官方文檔

要在django框架中使用模板引擎把視圖中的數據更好的展示給客戶端,需要完成3個步驟:

  1. 在項目配置文件中指定保存模板文件的模板目錄。一般模板目錄都是設置在項目根目錄或者主應用目錄下。

  2. 在視圖中基於django提供的渲染函數綁定模板文件和需要展示的數據變數

  3. 在模板目錄下創建對應的模板文件,並根據模板引擎內置的模板語法,填寫輸出視圖傳遞過來的數據。

配置模板目錄:在當前項目根目錄下創建了模板目錄templates. 然後在settings.py, 模板相關配置,找到TEMPLATES配置項,填寫DIRS設置模板目錄。

render內部本質

image-20220908194058936

def index(request):
	name = "hello world!"
	# 1. 初始化模板,讀取模板內容,實例化模板對象
    # get_template會從項目配置中找到模板目錄,我們需要填寫的參數就是補全模板文件的路徑
	template = get_template("index.html")
	# 2. 識別context內容, 和模板內容裡面的標記[標簽]替換,針對複雜的內容,進行正則的替換
	context = {"name": name}
	content = template.render(context, request) # render中完成了變數替換成變數值的過程,這個過程使用了正則。
	print(content)
	# 3. 通過response響應對象,把替換了數據的模板內容返回給客戶端
	return HttpResponse(content)
	# 上面代碼的簡寫,直接使用 django.shortcuts.render
	# return render(request, "index.html",context={"name":name})
    # return render(request,"index3.html", locals())
    # data = {}
    # data["name"] = "xiaoming"
    # data["message"] = "你好!"
    # return render(request,"index3.html", data)
  1. DTL模板文件與普通html文件的區別在哪裡?

DTL模板文件是一種帶有特殊語法的HTML文件,這個HTML文件可以被Django編譯,可以傳遞參數進去,實現數據動態化。在編譯完成後,生成一個普通的HTML文件,然後發送給客戶端。

  1. 開發中,我們一般把開發中的文件分2種,分別是靜態文件和動態文件。
    • 靜態文件,數據保存在當前文件,不需要經過任何處理就可以展示出去。普通html文件,圖片,視頻,音頻等這一類文件叫靜態文件。
    • 動態文件,數據並不在當前文件,而是要經過服務端或其他程式進行編譯轉換才可以展示出去。 編譯轉換的過程往往就是使用正則或其他技術把文件內部具有特殊格式的變數轉換成真實數據。 動態文件,一般數據會保存在第三方存儲設備,如資料庫中。django的模板文件,就屬於動態文件。

模板語法內容

  1. 變數渲染(深度查詢、過濾器)

    {{val}}
    {{val|filter_name:參數}}
    
  2. 標簽

    {% tag_name %}
    
  3. 嵌套和繼承

1.1 深度查詢

def index(request):
    name = "ZhangJR"
    age = 22
    is_married = True
    course = ["global education","hongkong economy"]

    regina = {
        "name":"ZhangJR",
        "age": 22,
        "is_married": True,

    }

    class info():
        def __init__(self,name,age):
            self.name = name
            self.age = age
    Info = info("ZhangJR",22)

    Info1 = info("ZhangJR",22)
    Info2 = info("regina", 23)
    Info3 = info("ivnalee", 24)
    Info4 = info("qianniu", 25)
    Infos = [Info1,Info2,Info3,Info4]

    return render(request,"index.html",locals())

深度查詢在查詢屬性或者取值的過程都用.作為判斷,locals函數代表將視圖函數所有的內容全部傳送給模板文件渲染

分別通過普通類型,字典類型,類,類的列表進行學習

<h3>深度查詢:句點符"."</h3>
<hr>普通類型
<p>姓名:{{name}}</p>
<p>年齡:{{age}}</p>
<p>婚否:{{is_married}}</p>
<p>課程:{{course}}</p>
<p>第一個課程:{{course.0}}</p>

<hr>字典
<p>個人信息:{{regina}}</p>
<p>個人名字:{{regina.name}}</p>
<p>個人年齡:{{regina.age}}</p>

<hr>類對象
<p>類對象名字:{{Info.name}}</p>
<p>類對象年齡:{{Info.age}}</p>

<hr>類列表取值
<p>第二個人的姓名:{{Infos.1.name}}</p>

image-20220908201405331

1.2 內置過濾器

語法:

{{obj|過濾器名稱:過濾器參數}}

內置過濾器

過濾器 用法 代碼
last 獲取列表/元組的最後一個成員 {{list | last}}
first 獲取列表/元組的第一個成員 {{list|first}}
length 獲取數據的長度 {{list | length}}
default 當變數沒有值的情況下, 系統輸出預設值, {{str|default:"預設值"}}
safe 讓系統不要對內容中的html代碼進行實體轉義 {{htmlcontent| safe}}
upper 字母轉換成大寫 {{str | upper}}
lower 字母轉換成小寫 {{str | lower}}
title 每個單詞首字母轉換成大寫 {{str | title}}
date 日期時間格式轉換 `{{ value
cut 從內容中截取掉同樣字元的內容 {{content | cut:"hello"}}
list 把內容轉換成列表格式 {{content | list}}
add 加法 {{num| add}}
filesizeformat 把文件大小的數值轉換成單位表示 {{filesize | filesizeformat}}
join 按指定字元拼接內容 {{list| join("-")}}
random 隨機提取某個成員 {list | random}}
slice 按切片提取成員 {{list | slice:":-2"}}
truncatechars 按字元長度截取內容 {{content | truncatechars:30}}
truncatewords 按單詞長度截取內容 同上
Infos = [Info1.name,Info2.name,Info3.name,Info4.name]
<p>信息的最後一個人的姓名:{{Infos | last}}</p>
<p>信息的第一個人的姓名:{{Infos | first}}</p>
<p>共有{{Infos | length}}個人</p>

image-20220908202840812

  • 預設值

    如果渲染的值為空,可以添加預設渲染值,效果如圖

    Name= ""
    
    姓名{{Name}}
    

    image-20220908203046383

如果變成<p>姓名 {{Name|default:"regina"}}</p>(default後面不能有空格)

image-20220908203351068

  • 日期轉換

    now = datetime.datetime.now()
    <p>當前時間預設格式:{{now}}</p>
    <p>格式化日期:{{now|date:"Y-m-d"}}</p>
    <p>格式化日期2:{{now|date:"D/d/m/Y"}}</p>
    

    image-20220908204007197

  • 文件大小

    filesizeformat過濾器自動會識別位元組大小進行單位的選擇

     file1 = 717
      file2 = 127717
      file3 = 1271221
      file4 = 1155178797
    <p>文件大小:{{file1|filesizeformat}}</p>
    <p>文件大小:{{file2|filesizeformat}}</p>
    <p>文件大小:{{file3|filesizeformat}}</p>
    <p>文件大小:{{file4|filesizeformat}}</p>
    

    image-20220908204656545

  • 按字元截斷

    str = "ABCDEFGHIJK"
    <p>content: {{str | truncatechars:6}}</p>
    

    image-20220908205214957

    這個...預設算作了一個字元

  • safe過濾

    如果我們輸入的是一段帶有標簽的html語言,類似於

        link = "<a href='www.gs.cuhk.edu.hk'>cuhk</a>"
        script = "<script>alert('regina')</script>"
    

    如果正常傳輸,那網頁上得到的則是

    image-20220909102044206

    並不是一個我們想要的效果,因為預設過濾器會對一些字元進行轉義,打開頁面源碼就會發現這一問題

    image-20220909102146093

    如果我們加上safe過濾器

    <p>link:{{link| safe}}</p>
    <p>script:{{script|safe}}</p>
    

    image-20220909102248840

    image-20220909102306168

    image-20220909102323379

    代碼也沒有進行任何的修改

1.3 自定義過濾器

雖然官方已經提供了許多內置的過濾器給開發者,但是很明顯,還是會有存在不足的時候。例如:希望輸出用戶的手機號碼時, 13912345678 ---->> 139*****678,這時我們就需要自定義過濾器。要聲明自定義過濾器並且能在模板中正常使用,需要完成2個前置的工作:

  1. 當前使用和聲明過濾器的子應用必須在setting.py配置文件中的INSTALLED_APPS中註冊了!!!

    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
    ]
    

    這裡面並沒有添加自定義的app進去,現在我們找到如下文件,併在上述代碼添加regina.apps.ReginaConfig

    image-20220914094726582

    1. 自定義過濾器函數必須被 template.register進行裝飾使用,而且過濾器函數所在的模塊必須在templatetags包裡面保存

      在home子應用下創建templatetags包[必須包含__init__.py], 在包目錄下創建任意py文件

      image-20220914095239114

      myfilters的名字是自定義的,這裡就是存儲過濾函數,並需要在最開始加上一些頭文件

      from django import template
      register = template.Library()
      
      @register.filter("mobile")
      def mobile(number):
          return number[:3]+"****"+number[-3:]
      
    2. 在需要使用的模板文件中頂部使用load標簽載入過濾器文件my_filters.py並調用自定義過濾器{% load myfilters %}

      過濾的函數要和myfilters文件裡面的函數是同名的

      最終當輸入一個手機號時,得到就是一個隱藏後的手機號

      image-20220914101648307

2.1 標簽

{% tagname %}

if標簽

is_married = True
{% if is_married == True %}
    <p>張女士已婚</p>
{% else %}
    <p>張女士未婚</p>
{% endif %}

這裡需要註意的幾個點:

  1. {% if condition %}這裡的condition和if都需要和周圍的%空開一格
  2. {% if is_married == true %}這裡要用雙等號
  3. 最後一定要加{% endif %}

image-20220914155633365

<div>
    {% if age < 20 %}
        <p>太小</p>
    {% elif age < 22 %}
        <p>還行</p>
    {% else %}
        <p>正好</p>
    {% endif %}
</div>

for迴圈

<ul>
    {% for name in course %}
    <li>{{ name }}</li>
    {% endfor %}
</ul>

image-20220914161141722

<table width="800" border="1" align="center">
    <tr>
        <th>序號</th>
        <th>姓名</th>
        <th>年齡</th>
    </tr>

{% for info in Infos %}
    <tr align="center">
        <td>{{ forloop.counter }}</td>
        <td>{{ info.name }}</td>
        <td>{{ info.age }}</td>
    </tr>
{% endfor %}
</table>

image-20220914162916027

還可以結合if判斷

{% for info in Infos %}
    {% if forloop.first %}
        <tr align="center" class="pink">
        <td>{{ forloop.counter }}</td>
        <td>{{ info.name }}</td>
        <td>{{ info.age }}</td>
    </tr>
    {% else %}
        <tr align="center">
            <td>{{ forloop.counter }}</td>
            <td>{{ info.name }}</td>
            <td>{{ info.age }}</td>
        </tr>
    {% endif %}

{% endfor %}

image-20220914163318861

或者還可以

    {% elif info.age > 23 %}
        <tr align="center" >
            <td>{{ forloop.counter }}</td>
            <td class="blue">{{ info.name }}</td>
            <td>{{ info.age }}</td>
        </tr>

image-20220914164050224

迴圈中, 模板引擎提供的forloop對象,用於給開發者獲取迴圈次數或者判斷迴圈過程的.

屬性 描述
forloop.counter 顯示迴圈的次數,從1開始
forloop.counter0 顯示迴圈的次數,從0開始
forloop.revcounter0 倒數顯示迴圈的次數,從0開始
forloop.revcounter 倒數顯示迴圈的次數,從1開始
forloop.first 判斷如果本次是迴圈的第一次,則結果為True
forloop.last 判斷如果本次是迴圈的最後一次,則結果為True
forloop.parentloop 在嵌套迴圈中,指向當前迴圈的上級迴圈

3 嵌套繼承

傳統的模板分離技術,依靠{% include "模板文件名"%}實現,這種方式,雖然達到了頁面代碼復用的效果,但是由此也會帶來大量的碎片化模板,導致維護模板的成本上升.因此, Django框架中除了提供這種模板分離技術以外,還並行的提供了 模板繼承給開發者.

{% include "模板文件名"%}  # 模板嵌入
{% extends "base.html" %} # 模板繼承 

3.1 include

假設現在有兩個頁面公用一個同樣式的東西,即頁面底部有一個廣告~

image-20220914165809050

在每一個頁面里都添加一句

{% include "same.html" %}

image-20220914170307750

image-20220914170328853

此時兩個頁面就同時擁有了這一元素

3.2 extends繼承

因為一個頁面繼承的東西可能有很多,而且有很多的固定框架,不可能每一個都用include進行繼承,此時就需要extends關鍵字,首先我們來用bootstrap學習一下,然後在我們需要自己渲染的位置上添加區塊

 <div class="col-md-10">
   <div class="theme-showcase" role="main">
     {% block content %}
     <p>hello world!</p>
     {% endblock %}
   </div>
</div>

其中content是自定義的名字,在模板文件里也同樣要用這個名字,然後在其他文件里進行導入這個文件

{% extends "same.html" %}
.....
{% block content %}
原來渲染的內容
{% endblock %}

被extends的文件在未使用時是這樣的

image-20220915000327456

我們看到有兩個塊是要傳遞給模板文件渲染的,index.htmltest.html同時繼承了這一文件,效果如圖

image-20220915000446635

image-20220915000506977

  • 如果你在模版中使用 {% extends %} 標簽,它必須是模版中的第一個標簽。其他的任何情況下,模版繼承都將無法工作。
  • 在base模版中設置越多的 {% block %} 標簽越好。請記住,子模版不必定義全部父模版中的blocks,所以,你可以在大多數blocks中填充合理的預設內容,然後,只定義你需要的那一個。多一點鉤子總比少一點好。
  • 為了更好的可讀性,你也可以給你的 {% endblock %} 標簽一個 名字 。例如:{``% block content``%``}``...``{``% endblock content``%``},在大型模版中,這個方法幫你清楚的看到哪一個  {% block %} 標簽被關閉了。
  • 不能在一個模版中定義多個相同名字的 block 標簽。

在最開始的same頁面中,我們是添加了一句話的,雖然這句話並不重要,但是如果我們繼承的時候也想要這句話,就需要把語句改為

{% block content %}
{{ block.super }}
....

image-20220915001014323

此時原來same.html裡面的block內容也可以得到繼承

本文來自博客園,作者:ivanlee717,轉載請註明原文鏈接:https://www.cnblogs.com/ivanlee717/p/16695109.html


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 每日3題 1 以下代碼執行後,控制臺中的輸出內容為? var company = { address: "chengdu", }; var obj = Object.create(company); delete obj.address; console.log(obj.address); 2 以下 ...
  • 終於,在漫長的等待下,容器查詢(CSS Container Queries)將在 Chrome 105 版本得到正式的支持! 而目前,我們也能在 Chrome Canary 版本中,或者在 Chrome 93~104 通過開啟 Enable CSS Container Queries 特性搶先體驗。 ...
  • 基於全屏iframe的微前端框架--擎天,解決了iframe UI不同步、URL不同步、數據不共用的難題,並充分發揮了iframe作為頁面容器的優勢,實現了父子應用非同步載入、子應用瞬間切換的能力,從而將微前端項目達到單體應用的體驗。 ...
  • 不知不覺,掘金關註者人數已經超過 1000 人,因此特地做了這個頁面紀念一下,感謝大家關註 🙇‍ ,希望博客園的粉絲也漲漲。後續也將繼續努力,持續輸出一些有價值的文章。本文內容涉及的技術棧為 React + Three.js + Stulus,本文中主要包含的知識點包括:圓錐幾何體 ConeGeo... ...
  • 一、系統架構的演變 1、技術架構發展歷史時間軸 ①單機垂直拆分:應用間進行瞭解耦,系統容錯提高了,也解決了獨立應用發佈的問題,存在單機計算能力瓶頸。 ②集群化負載均衡可有效解決單機情況下併發量不足瓶頸。 ③服務改造架構 雖然系統經過了垂直拆分,但是拆分之後發現有重覆的功能,比如,用戶註冊、發郵件等等 ...
  • 外觀模式(Facade Pattern)隱藏系統的複雜性,並向客戶端提供了一個客戶端可以訪問系統的介面。這種類型的設計模式屬於結構型模式,它向現有的系統添加一個介面,來隱藏系統的複雜性。 ...
  • 什麼是統一建模語言,來看看百科中的介紹統一建模語言(Unified Modeling Language,UML)是一種為面向對象系統的產品進行說明、可視化和編製文檔的一種標準語言,是非專利的第三代建模和規約語言。UML是面向對象設計的建模工具,獨立於任何具體程式設計語言。簡單來說UML就是脫離於具體 ...
  • 在日常生產生活中,我們常說,“安全第一”、“安全無小事”。圍繞著安全問題,在各行各業都有對各類常見安全問題的解決方案和突發安全問題的應急預案。在互聯網、軟體開發領域,我們日常工作中對各類常見的安全問題又有哪些常見的解決方案呢?在此,結合經典架構圖做一個梳理。 ...
一周排行
    -Advertisement-
    Play Games
  • C#TMS系統代碼-基礎頁面BaseCity學習 本人純新手,剛進公司跟領導報道,我說我是java全棧,他問我會不會C#,我說大學學過,他說這個TMS系統就給你來管了。外包已經把代碼給我了,這幾天先把增刪改查的代碼背一下,說不定後面就要趕鴨子上架了 Service頁面 //using => impo ...
  • 委托與事件 委托 委托的定義 委托是C#中的一種類型,用於存儲對方法的引用。它允許將方法作為參數傳遞給其他方法,實現回調、事件處理和動態調用等功能。通俗來講,就是委托包含方法的記憶體地址,方法匹配與委托相同的簽名,因此通過使用正確的參數類型來調用方法。 委托的特性 引用方法:委托允許存儲對方法的引用, ...
  • 前言 這幾天閑來沒事看看ABP vNext的文檔和源碼,關於關於依賴註入(屬性註入)這塊兒產生了興趣。 我們都知道。Volo.ABP 依賴註入容器使用了第三方組件Autofac實現的。有三種註入方式,構造函數註入和方法註入和屬性註入。 ABP的屬性註入原則參考如下: 這時候我就開始疑惑了,因為我知道 ...
  • C#TMS系統代碼-業務頁面ShippingNotice學習 學一個業務頁面,ok,領導開完會就被裁掉了,很突然啊,他收拾東西的時候我還以為他要旅游提前請假了,還在尋思為什麼回家連自己買的幾箱飲料都要叫跑腿帶走,怕被偷嗎?還好我在他開會之前拿了兩瓶芬達 感覺感覺前面的BaseCity差不太多,這邊的 ...
  • 概述:在C#中,通過`Expression`類、`AndAlso`和`OrElse`方法可組合兩個`Expression<Func<T, bool>>`,實現多條件動態查詢。通過創建表達式樹,可輕鬆構建複雜的查詢條件。 在C#中,可以使用AndAlso和OrElse方法組合兩個Expression< ...
  • 閑來無聊在我的Biwen.QuickApi中實現一下極簡的事件匯流排,其實代碼還是蠻簡單的,對於初學者可能有些幫助 就貼出來,有什麼不足的地方也歡迎板磚交流~ 首先定義一個事件約定的空介面 public interface IEvent{} 然後定義事件訂閱者介面 public interface I ...
  • 1. 案例 成某三甲醫預約系統, 該項目在2024年初進行上線測試,在正常運行了兩天後,業務系統報錯:The connection pool has been exhausted, either raise MaxPoolSize (currently 800) or Timeout (curren ...
  • 背景 我們有些工具在 Web 版中已經有了很好的實踐,而在 WPF 中重新開發也是一種費時費力的操作,那麼直接集成則是最省事省力的方法了。 思路解釋 為什麼要使用 WPF?莫問為什麼,老 C# 開發的堅持,另外因為 Windows 上已經裝了 Webview2/edge 整體打包比 electron ...
  • EDP是一套集組織架構,許可權框架【功能許可權,操作許可權,數據訪問許可權,WebApi許可權】,自動化日誌,動態Interface,WebApi管理等基礎功能於一體的,基於.net的企業應用開發框架。通過友好的編碼方式實現數據行、列許可權的管控。 ...
  • .Net8.0 Blazor Hybird 桌面端 (WPF/Winform) 實測可以完整運行在 win7sp1/win10/win11. 如果用其他工具打包,還可以運行在mac/linux下, 傳送門BlazorHybrid 發佈為無依賴包方式 安裝 WebView2Runtime 1.57 M ...