整合營(yíng)銷服務(wù)商

          電腦端+手機(jī)端+微信端=數(shù)據(jù)同步管理

          免費(fèi)咨詢熱線:

          小白必看!Django 模板語(yǔ)言基礎(chǔ)來(lái)啦

          者 | 單雨

          責(zé)編 | 胡巍巍

          出品 | CSDN(ID:CSDNnews)

          前言

          為了實(shí)現(xiàn)模板封裝和復(fù)用,提高HTML界面調(diào)試便捷性以及前后端解耦等目標(biāo),Django定義了自己的網(wǎng)絡(luò)模板語(yǔ)言。

          當(dāng)前介紹模板語(yǔ)言的官方文檔已經(jīng)非常完備,幾乎涵蓋了開發(fā)中需要用到的知識(shí)點(diǎn)和需要注意的問(wèn)題,但同時(shí)官方文檔也存在一些問(wèn)題:

          • 翻譯不夠完善,帶來(lái)閱讀的困難;

          • 一些知識(shí)點(diǎn)的介紹過(guò)于簡(jiǎn)短,存在大量的頁(yè)內(nèi)鏈接,閱讀時(shí)需要跳轉(zhuǎn)到不同的頁(yè)面,閱讀不連貫。

          本文基于官方文檔系統(tǒng)介紹了Django模板語(yǔ)言的基礎(chǔ)知識(shí)點(diǎn),方便快速了解Django模板語(yǔ)言。

          模板系統(tǒng)設(shè)計(jì)哲學(xué)

          Django的模板系統(tǒng)不是簡(jiǎn)單的把Python嵌入到HTML中。

          它的設(shè)計(jì)宗旨是:模板系統(tǒng)旨在展示內(nèi)容, 而不是程序邏輯,因此不在HTML頁(yè)面中嵌入Python。

          簡(jiǎn)單的說(shuō),模板只負(fù)責(zé)渲染數(shù)據(jù),大多數(shù)邏輯應(yīng)該交給視圖(view)進(jìn)行處理。

          模板簡(jiǎn)介

          模板是一個(gè)簡(jiǎn)單的文本文件。它可以生成任何基于文本的格式(如 HTML,XML,CSV等)。除了基本的HTML標(biāo)簽外,模板還包含兩種額外的元素——變量和標(biāo)簽。

          模板中包含的變量可以被替換為變量的值,標(biāo)簽則被替換為相應(yīng)的模板控制邏輯。示例:

          django

          {% extends "base_generic.html" %}

          {% block title %}{{ section.title }}{% endblock %}

          {% block content %}

          <h1>{{ section.title }}</h1>

          {% for story in story_list %}

          <h2>

          <a href="{{ story.get_absolute_url }}">

          {{ story.headline|upper }}

          </a>

          </h2>

          <p>{{ story.tease|truncatewords:"100" }}</p>

          {% endfor %}

          {% endblock %}

          `{{ section.title }}`在模板渲染時(shí)將會(huì)被變量的值替換,for標(biāo)簽可以實(shí)現(xiàn)模板的循環(huán)渲染。

          基礎(chǔ)語(yǔ)法

          變量

          變量實(shí)現(xiàn)從模板上下文字典(返回HTTP響應(yīng)時(shí)傳遞過(guò)來(lái)的字典)中輸出一個(gè)值,這是一個(gè)類似于dict的對(duì)象,包含鍵值對(duì)。當(dāng)模板引擎遇到一個(gè)變量時(shí),它會(huì)計(jì)算該變量,并用結(jié)果替換它。

          變量名由字母、數(shù)字字符和下劃線("_")組成,但不能以下劃線開頭。點(diǎn)(".")也出現(xiàn)在變量中,代表屬性調(diào)用,變量名中不能有空格或標(biāo)點(diǎn)符號(hào)。

          示例:

          django

          My first name is {{ first_name }}. My last name is {{ last_name }}.

          當(dāng)傳入一個(gè)上下文字典`{'first_name': 'John', 'last_name': 'Doe'}`時(shí),將會(huì)渲染得到:

          django

          My first name is John. My last name is Doe.

          模板中的變量被字典中的值替換了。

          變量還可以使用點(diǎn)表示法實(shí)現(xiàn)字典查找、屬性查找和列表索引查找等操作:

          django

          {{ my_dict.key }}

          {{ my_object.attribute }}

          {{ my_list.0 }}

          點(diǎn)表示法底層原理

          當(dāng)模板系統(tǒng)遇到一個(gè)點(diǎn),它會(huì)按順序嘗試下面的動(dòng)作:

          1. 字典查詢

          2. 屬性或方法查找

          3. 數(shù)字索引查詢

          如果結(jié)果值是可調(diào)用的,則調(diào)用該值時(shí)將不帶參數(shù),調(diào)用的結(jié)果成為新的模板值。

          當(dāng)進(jìn)行能覆蓋字典查找的操作時(shí),這種查找順序可能會(huì)造成一些意想不到的行為。例如:如果試圖循環(huán)一個(gè)collection .defaultdict字典對(duì)象:

          django

          {% for k, v in defaultdict.items %}

          {其他操作}

          {% endfor %}

          因?yàn)樽值洳檎沂鞘紫劝l(fā)生的,所以這個(gè)行為會(huì)先提供一個(gè)默認(rèn)值,而不是使用預(yù)期的.items方法。在這種情況下,應(yīng)該首先考慮使用字典查找,而不是使用字典的屬性調(diào)用。

          注意

          屬性通常被解釋為一個(gè)文本字符串,防止和同名的變量沖突。例如{{foo.bar}}中的屬性“bar”將被解釋為一個(gè)文本字符串,如果模板上下文中存在變量“bar”,則不會(huì)使用該變量的值。

          以下劃線開頭的變量屬性可能不能訪問(wèn),因?yàn)樗鼈兺ǔ1徽J(rèn)為是私有的。

          如果引用不存在的變量,模板系統(tǒng)將插入string_if_invalid選項(xiàng)的值,該選項(xiàng)默認(rèn)設(shè)置為“”(空字符串)。

          標(biāo)簽

          標(biāo)簽在模板渲染過(guò)程中提供任意邏輯。標(biāo)簽可以輸出內(nèi)容,作為控制結(jié)構(gòu),例如“if”語(yǔ)句或“for”循環(huán),從數(shù)據(jù)庫(kù)獲取內(nèi)容,甚至允許訪問(wèn)其他模板標(biāo)簽。

          (1)標(biāo)簽聲明

          標(biāo)簽的一般形式為:

          django

          {% tag %}

          示例:

          django

          {% csrf_token %}

          (2)傳入?yún)?shù)

          django

          {% cycle 'odd' 'even' %}

          (3)成對(duì)使用的標(biāo)簽

          有些標(biāo)簽需要開始和結(jié)束標(biāo)簽:

          django

          {% if user.is_authenticated %}Hello, {{ user.username }}.{% endif %}

          (4)常用標(biāo)簽

          for:循環(huán)數(shù)組中的每個(gè)元素. 比如, 顯示列表 `athlete_list` 中每個(gè)元素的 `name` 屬性。

          django

          <ul>

          {% for athlete in athlete_list %}

          <li>{{ athlete.name }}</li>

          {% endfor %}

          </ul>

          if 、elif和else:在上面,如果athlete_list不為空,則{{athlete_list|length}}變量將顯示運(yùn)動(dòng)員的數(shù)量。

          否則,如果athlete_in_locker_room_list不為空,則會(huì)顯示“Athletes should be out…”消息。如果兩個(gè)列表都為空,則顯示“No athletes”。

          也可以在if標(biāo)簽里使用過(guò)濾器和各種操作符:

          django

          {% if athlete_list|length > 1 %}

          Team: {% for athlete in athlete_list %} ... {% endfor %}

          {% else %}

          Athlete: {{ athlete_list.0.name }}

          {% endif %}

          注意

          雖然上面的示例可以工作,但是要注意,大多數(shù)模板過(guò)濾器都返回字符串,因此使用過(guò)濾器進(jìn)行數(shù)學(xué)比較通常不會(huì)正常工作,而長(zhǎng)度是個(gè)例外。

          (5)更多

          Django有很多內(nèi)置標(biāo)簽,更多關(guān)于內(nèi)置標(biāo)簽的信息請(qǐng)參考官方文檔:

          https://docs.djangoproject.com/zh-hans/2.2/ref/templates/builtins/ref-templates-builtins-tags

          如果需要編寫自定義標(biāo)簽,請(qǐng)參考官方文檔

          https://docs.djangoproject.com/zh-hans/2.2/howto/custom-template-tags/howto-writing-custom-template-tags

          如果需要對(duì)使用的標(biāo)簽和自定義的標(biāo)簽做一份說(shuō)明文檔,可以使用Django提供的文檔工具,詳情請(qǐng)參考:

          https://docs.djangoproject.com/zh-hans/2.2/ref/contrib/admin/admindocs/

          過(guò)濾器

          簡(jiǎn)介

          過(guò)濾器可以對(duì)變量做一些操作,例如給變量賦值,改變變量的值等。

          修改變量顯示

          過(guò)濾器可以修改變量的顯示。例如:

          django

          {{ name|lower }}

          通過(guò)過(guò)濾器lower變量{{ name }}變?yōu)榱诵懽址ㄟ^(guò)管道符(|)間隔變量和過(guò)濾器來(lái)使用過(guò)濾器。

          鏈?zhǔn)秸{(diào)用過(guò)濾器

          一個(gè)過(guò)濾器的輸出可以作為下一個(gè)過(guò)濾器的輸入。

          {{ text|escape|linebreaks }}是一種常用的轉(zhuǎn)換方式, 在這之后換行符被替換為了 <p> 標(biāo)簽。

          轉(zhuǎn)換變量和標(biāo)簽參數(shù)

          過(guò)濾器轉(zhuǎn)換變量和標(biāo)簽參數(shù)的值。示例:

          django

          {{ django|title }}

          傳入`{'django': 'the web framework for perfecalist With deadline '}`上下文字典時(shí),該模板呈現(xiàn)為:

          django

          The Web Framework For Perfectionists With Deadlines

          傳入?yún)?shù)給過(guò)濾器

          示例1:

          django

          {{ my_date|date:"Y-m-d" }}

          my_date將會(huì)被替換為當(dāng)前日期。

          示例2:

          django

          {{ bio|truncatewords:30 }}

          將會(huì)會(huì)顯示 `bio` 變量的前30個(gè)字符

          注意

          過(guò)濾器參數(shù)中如果包含空格和標(biāo)點(diǎn)符號(hào),必須使用引號(hào)“”括起來(lái),例如,要用逗號(hào)和空格連接列表,可以使用{{list|join:", "}}。

          Django提供了大約60個(gè)內(nèi)置模板過(guò)濾器,請(qǐng)參考官方文檔:

          https://docs.djangoproject.com/zh-hans/2.2/ref/templates/builtins/ref-templates-builtins-filters

          下面列舉一些常用的過(guò)濾器:

          default

          如果變量為false或空,則使用給定的默認(rèn)值。否則,使用變量的值。例如:

          django

          {{ value|default:"nothing" }}

          如果 `value` 沒(méi)有提供或者為空,那么將它顯示為 "`nothing`" 。

          length

          返回值的長(zhǎng)度。這對(duì)字符串和列表都適用。例如:

          django

          {{ value|length }}

          如果 `value` 為 `['a', 'b', 'c', 'd']`, 那么他將被顯示為 `4`。

          filesizeformat

          將值格式化為“人類可讀的”文件大小(即“13kb”、“4.1 MB”、“102字節(jié)”等)。例如:

          django

          {{ value|filesizeformat }}

          如果值為123456789,則輸出為117.7 MB。

          如果需要自定義過(guò)濾器,請(qǐng)參考請(qǐng)官方文檔:

          https://docs.djangoproject.com/zh-hans/2.2/howto/custom-template-tags/

          注釋

          示例:

          單行注釋

          django

          { this won't be rendered }

          多行注釋:{% comment %} 和{% endcomment %}

          django

          <p>Rendered text with {{ pub_date|date:"c" }}</p>

          {% comment "Optional note" %}

          <p>Commented out text with {{ create_date|date:"c" }}</p>

          {% endcomment %}

          注意:Comment標(biāo)簽不能嵌套使用。

          作者簡(jiǎn)介:?jiǎn)斡辏?0后工科男,偽文藝青年。目前就讀于北京理工大學(xué)宇航系,喜歡研究AI,網(wǎng)絡(luò)爬蟲,微信小程序以及機(jī)器人,癡迷于Coding,睡前必?cái)]碼。

          【END】

          前話

          Hello,小伙伴們大家新年好,本篇是今年第一篇,也籌劃許久,本篇主題為美食,系html5網(wǎng)站模板,div加css布局,網(wǎng)頁(yè)資源分開存儲(chǔ)以便管理,網(wǎng)頁(yè)結(jié)構(gòu)清晰簡(jiǎn)單,希望本篇能夠助力各位萌新

          主題

          《周末の食記》

          美食能撫平一切的憂傷

          簡(jiǎn)介

          文件結(jié)構(gòu)包含了css、fonts、images、js和html,運(yùn)用html5技術(shù),包括nav標(biāo)簽、header標(biāo)簽和footer標(biāo)簽等,采用bootstrap進(jìn)行布局

          圖摘

          目錄

          編碼

          <div class="ftco-46-row d-flex flex-column flex-lg-row">
              <div class="ftco-46-text ftco-46-arrow-right">
                  <h4 class="ftco-46-subheading">Food</h4>
                  <h3 class="ftco-46-heading">揚(yáng)州炒飯</h3>
                  <p class="mb-5">一碗不一樣的炒飯,讓你難以拒絕.</p>
                  <p><a href="#" class="btn-link">更多 <span class="ion-android-arrow-forward"></span></a></p>
                  </div>
                  <div class="ftco-46-image" style="background-image: url(images/img_3.jpg);"></div>
                  <div class="ftco-46-text ftco-46-arrow-up">
                  <h4 class="ftco-46-subheading">Food</h4>
                  <h3 class="ftco-46-heading">藍(lán)莓酸奶冰激凌</h3>
                  <p class="mb-5">觸動(dòng)您的心靈,令人甜蜜至極,難以忘懷,心曠神怡的味覺(jué)享受,精選一級(jí)的夏威夷果仁,入口絲滑</p>
                  <p><a href="#" class="btn-link">更多 <span class="ion-android-arrow-forward"></span></a></p>
              </div>
          </div>

          結(jié)語(yǔ)

          如果人的一生總的能量是固定的話,那就節(jié)省開支,延長(zhǎng)時(shí)間,喜怒哀樂(lè)不溢于言表,不困于心智,保持樂(lè)觀心態(tài)

          源于公眾號(hào):Python野路子

          一、模板介紹


          我們之前學(xué)習(xí)的,都是在視圖函數(shù)直接返回文本,在實(shí)際中我們更多的是帶有樣式的HTML代碼,這樣可以讓瀏覽器渲染出非常漂亮的頁(yè)面,目前市面上有非常多的模板系統(tǒng),其中最常用的是DTLJinja2DTL(Django Template Language),也就是Django自帶的模板語(yǔ)言,當(dāng)然也可以配置Django支持Jinja2,但是作為Django內(nèi)置的模板語(yǔ)言,不會(huì)產(chǎn)生一些不兼容的情況,最好還是使用內(nèi)置的。

          1. DTL與普通的HTML文件區(qū)別

          DTL模板是一種帶有特殊語(yǔ)法的HTML文件,這個(gè)HTML文件可以被Django編譯,可以傳遞參數(shù)進(jìn)去,實(shí)現(xiàn)數(shù)據(jù)動(dòng)態(tài)化,在編譯完成后,生成一個(gè)普通的HTML文件,然后發(fā)送給客戶端。

          2. 模板渲染

          可以使用render函數(shù)進(jìn)行渲染,將數(shù)據(jù)渲染到指定的HTML模板中。

          我們?cè)谥暗幕A(chǔ)上,再新建一個(gè)articleapp,除了剛開始第一個(gè)應(yīng)用,我們?cè)?span style="color: #1E6BB8; --tt-darkmode-color: #1E6BB8;">pycharm創(chuàng)建項(xiàng)目的時(shí)候,填了app名字,pycharm會(huì)自動(dòng)幫我們創(chuàng)建應(yīng)用,后續(xù)如果還要再新建應(yīng)用,我們都要使用命令方式才能新建app


          應(yīng)用創(chuàng)建完成了,接下來(lái)我們需要在配置文件settings.py里面注冊(cè)應(yīng)用app

          INSTALLED_APPS = [
              'django.contrib.admin',
              'django.contrib.auth',
              'django.contrib.contenttypes',
              'django.contrib.sessions',
              'django.contrib.messages',
              'django.contrib.staticfiles',
              'user.apps.UserConfig',   # 使用pycharm創(chuàng)建的應(yīng)用,pycharm會(huì)自動(dòng)注冊(cè)
              'article'  # 手工命令方式創(chuàng)建的應(yīng)用app,需要手工在這注冊(cè)應(yīng)用!
          ]
          

          路由和視圖代碼:

          # 主urls.py
          path('article/', include('article.urls', namespace='article'))
              
          # 應(yīng)用urls.py,創(chuàng)建的應(yīng)用這個(gè)文件不會(huì)自動(dòng)生成,需要我們新建
          
          from django.urls import path
          from . import views
          
          app_name = 'article'
          urlpatterns = [
              path('index/', views.index, name='index')
          
          ]
          
          # 視圖views.py
          from django.shortcuts import render
          
          def index(request):
              return render(request, 'index.html')  # 使用render渲染模板
          

          模板文件,項(xiàng)目根目錄下templates目錄(若沒(méi)有自動(dòng)生成,則手工新建此文件夾)下新建index.html模板文件。

          <!DOCTYPE html>
          <html lang="en">
          <head>
              <meta charset="UTF-8">
              <title>文章首頁(yè)</title>
          </head>
          <body>
              <h2>文章首頁(yè)</h2>
          </body>
          </html>
          

          查看效果:

          使用render函數(shù)將模板成功渲染出來(lái)了。

          3. 模板文件查找路徑

          在項(xiàng)目的settings.py配置文件中,有一個(gè)TEMPLATES配置。

          TEMPLATES = [
              {
                  # 模板引擎,就是Django內(nèi)置的模板引擎,
                  # 若要配置為Jinja2:django.template.backends.jinja2.Jinja2
                  'BACKEND': 'django.template.backends.django.DjangoTemplates',
                  # BASE_DIR,項(xiàng)目根目錄路徑下的templates查找
                  #'DIRS': [os.path.join(BASE_DIR, 'templates')] # Django2中使用
                  'DIRS': [BASE_DIR / 'templates'],  #  Django3中使用
                  ,
                  # 是否從app應(yīng)用下的templates下查找模板文件
                  'APP_DIRS': True,
                  'OPTIONS': {
                      # 模板中間件
                      'context_processors': [
                          'django.template.context_processors.debug',
                          'django.template.context_processors.request',
                          'django.contrib.auth.context_processors.auth',
                          'django.contrib.messages.context_processors.messages',
                      ],
                  },
              },
          ]
          

          這個(gè)配置包含了模板引擎的配置,這個(gè)配置包含了模板引擎的配置,模板查找路徑的配置,模板上下文的配置等,模板路徑可以2個(gè)地方配置。

          1. DIRS:這是一個(gè)列表,在這個(gè)列表中可以存放所有的模板路徑,以后在視圖中使用render渲染模板時(shí),就會(huì)從這個(gè)列表的路徑中查找模板。
          2. APP_DIRS:默認(rèn)為True,這個(gè)表示已經(jīng)在INSTALLED_APPS文件中注冊(cè)過(guò)的應(yīng)用app下的templates目錄下查找模板文件。
          3. 查找順序:比如代碼render(request,'index.html'),先會(huì)在DIRS這個(gè)列表中依次查找路徑下有沒(méi)有這個(gè)模板,如果有,就返回,如果沒(méi)有,則會(huì)先檢查當(dāng)前視圖所處的app是否已經(jīng)安裝,那么就先在當(dāng)前app下的templates目錄下查找模板,如果沒(méi)有找到,就會(huì)去其他注冊(cè)的app中繼續(xù)查找,如果所有路徑下都沒(méi)有找到,則會(huì)拋出TemplateDoesNotExist

          二、DTL模板語(yǔ)法

          1. 模板變量

          我們想要將后臺(tái)數(shù)據(jù)渲染到頁(yè)面上,這就需要用到模板變量。

          # 主urls.py
          path('article/', include('article.urls', namespace='article'))
          
          # 應(yīng)用urls.py
          path('index/', views.index, name='index')
          
          
          
          # 視圖views.py
          from django.shortcuts import render
          
          class Article:
              def __init__(self, title):
                  self.title = title
          
          
          def index(request):
              context = {
                  'msg': '模板變量',    # 字符串,
                  'article': Article('Django框架之模板文件'),    # 實(shí)例一個(gè)對(duì)象,
                  'author': {'name': 'admin'},    # 一個(gè)字典
                  'tag': ['python入門', 'python進(jìn)階', '數(shù)據(jù)庫(kù)']  # 列表或元組
              }
          
              return render(request, 'index.html', context=context)  # 傳入一個(gè)字典
          

          模板文件:

          <!DOCTYPE html>
          <html lang="en">
          <head>
              <meta charset="UTF-8">
              <title>文章首頁(yè)</title>
          </head>
          <body>
              <h2>文章首頁(yè)</h2>
              <p>{{ msg }}</p> <!-- 在模板中使用變量,需要將變量放到 {{ 變量 }} 中 -->
              <h3>{{ article.title }}</h3>  <!-- 要訪問(wèn)對(duì)象的屬性,通過(guò)"對(duì)象.屬性名" 訪問(wèn) -->
              <p>作者:{{ author.name }}</p>  <!-- 要訪問(wèn)字典key對(duì)應(yīng)值value,通過(guò)"字典.key" 訪問(wèn),不能[]形式 -->
              <ul>
                  <li>{{ tag.0 }}</li>  <!-- 要訪問(wèn)列表或者元組的元素,通過(guò)"列表.索引" 訪問(wèn) -->
                  <li>{{ tag.1 }}</li>
                  <li>{{ tag.2 }}</li>
              </ul>
          </body>
          </html>
          

          效果:


          在模板中使用變量:語(yǔ)法:{{變量名}} 1)命名由字母和數(shù)字以及下劃線組成,不能有空格和標(biāo)點(diǎn)符號(hào)。2)不要和python或django關(guān)鍵字重名。原因:如果data是一個(gè)字典,那么訪問(wèn)data.items將會(huì)訪問(wèn)data這個(gè)字典的key名為items的值,而不會(huì)訪問(wèn)字典的items方法。

          2. 模板標(biāo)簽

          標(biāo)簽語(yǔ)法:{% 標(biāo)簽名稱 %} {% 結(jié)束標(biāo)簽名稱 %}

          例:{%tag%} {%endtag%}

          2.1 if標(biāo)簽

          if標(biāo)簽相當(dāng)于python中的if語(yǔ)句,有elifelse相對(duì)應(yīng),可以使用and、or、in、not、==、!=、<=、>=、is、is not,來(lái)進(jìn)行判斷。

          視圖views.py

          def index(request):
              age = random.randint(6, 20)  # 隨機(jī)生成6-20的整數(shù)
          
              context = {
                  'age': age
              }
          
              return render(request, 'index.html', context=context)
          

          模板文件:

          <!DOCTYPE html>
          <html lang="en">
          <head>
              <meta charset="UTF-8">
              <title>文章首頁(yè)</title>
          </head>
          <body>
              <p>
                  <span>年齡:<strong>{{ age }}</strong>,</span>
                  <span>適合讀</span>
                  <span>
                      {% if age >= 18 %}
                          【大學(xué)】書籍
                      {% elif 12 < age and age < 18 %}
                          【高中】書籍
                      {% else %}
                          【小學(xué)】書籍
                      {% endif %}
                  </span>
              </p>
          </body>
          </html>
          


          再刷新一次:


          我們還可以使用ifequal/ifnotequal來(lái)比較兩個(gè)值是否相等,如:

          {% ifequal price 0 %}
              <span class="publicimg"><img src="/images/public.png"></span>
          {% else %}
              <span class="publicimg"><img src="/images/vip.png"></span>
          {% endifequal %}
          
          
          

          2.2 for...in...標(biāo)簽

          for標(biāo)簽相當(dāng)于python中的for循環(huán),可以遍歷列表、元組、字符串、字典等一切可以遍歷的對(duì)象。

          # 視圖views.py
          def index(request):
              context = {
                  'articles': [              # 列表
                      '21天學(xué)會(huì)Python',
                      'C++從入門到入土',
                      'Mysql從入門到跑路'
                  ],
                  'author': {             # 字典
                      'name': '老P',
                      'age': 18,
                      'sex': 'boy'
                  },
                  'artile_details': [
                      {'title': '21天學(xué)會(huì)Python', 'author': '小P', 'words': 1000},
                      {'title': 'C++從入門到入土', 'author': '中P', 'words': 2000},
                      {'title': 'Mysql從入門到跑路', 'author': '老P', 'words': 3000}
                  ]
              }
          
              return render(request, 'index.html', context=context)
          

          模板文件:

          <!DOCTYPE html>
          <html lang="en">
          <head>
              <meta charset="UTF-8">
              <title>文章首頁(yè)</title>
          </head>
          <body>
              <ul>
                  {% for article in articles %}
                      <li>{{ article }}</li>
                  {% endfor %}
              </ul>
              <p>獲取字典鍵:</p>
              <ul>
                  {% for key in author.keys %}
                      <li>{{ key }}</li>
                  {% endfor %}
              </ul>
              <p>獲取字典值:</p>
              <ul>
                  {% for value in author.values %}
                      <li>{{ value }}</li>
                  {% endfor %}
              </ul>
              <p>獲取字典鍵值對(duì):</p>
              <ul>
                  {% for key, value in author.items %}
                      <li>{{ key }}:{{ value }}</li>
                  {% endfor %}
              </ul>
          
              <p>文章信息列表:</p>
              <table border="1">
                  <thead>
                      <tr>
                          <th>序號(hào)</th>
                          <th>標(biāo)題</th>
                          <th>作者</th>
                          <th>字?jǐn)?shù)</th>
                      </tr>
                  </thead>
                  <tbody>
                      {% for article_detail in artile_details %}
                          {% if forloop.first %}   <!-- 是否第一次遍歷 -->
                              <tr style="background: red;">
                          {% elif forloop.last %}   <!-- 是否最后一次遍歷 -->
                              <tr style="background: pink;">
                          {% else %}
                              <tr>
                          {% endif %}
                              <td>{{ forloop.counter }}</td>  <!-- 當(dāng)前迭代的次數(shù),下標(biāo)從1開始。-->
                              <td>{{ article_detail.title }}</td>
                              <td>{{ article_detail.author }}</td>
                              <td>{{ article_detail.words }}</td>
                          </tr>
                      {% endfor %}
                  </tbody>
              </table>
          
          </body>
          </html>
          
          <!-- 
              forloop.counter:當(dāng)前迭代的次數(shù),下標(biāo)從1開始。
              forloop.counter0:當(dāng)前迭代的次數(shù),下標(biāo)從0開始。
              forloop.first:返回bool類型,如果是第一次迭代,返回true,否則返回false。
              forloop.last:返回bool類型,如果是最后一次迭代,返回True,否則返回False。
          
          	forloop.revcounter         反向循環(huán)位置(列表的最后一位是l ,列表第一位是n )
          	forloop.revcounter0        反向循環(huán)位置(列表的最后一位是0 , 列表第一位是n- 1 )
          -->
          


          還有個(gè)for...in...empty,在遍歷的時(shí)候如果需要遍歷的對(duì)象沒(méi)有為空,則執(zhí)行empty下的操作。

              {% for comment in comments %}  
                  {{ comment }}
              {# 在for循環(huán)之前檢查列表大小是常見(jiàn)的,當(dāng)列表為空的時(shí)候給出特別提示,這是常見(jiàn)的,所以for支持可選empry來(lái)當(dāng)為空時(shí)輸出 #}    
              {% empty %}   <!-- comments沒(méi)有或?yàn)榭眨瑒t執(zhí)行empty下的。-->
                  還沒(méi)有評(píng)論~~~
              {% endfor %}
          

          有時(shí)候可能在頁(yè)面上要用上循環(huán)幾次,可以用:

          {% for item in  'x'|ljust:'4' %}  循環(huán)四次
          {%endfor %}
          

          2.3 with標(biāo)簽

          使用一個(gè)簡(jiǎn)單地名字緩存一個(gè)復(fù)雜的變量,當(dāng)你需要使用一個(gè)代價(jià)較大的方法(比如訪問(wèn)數(shù)據(jù)庫(kù))很多次的時(shí)候這是非常有用的。

          <!DOCTYPE html>
          <html lang="en">
          <head>
              <meta charset="UTF-8">
              <title>文章首頁(yè)</title>
          </head>
          <body>
              {{ title }}
          
              {% with t1=title %}  <!-- 使用= -->
                  {{ t1 }}
              {% endwith %}
          
              {% with title as t2%} <!-- 使用as 取別名 -->
                  {{ t2 }}
              {% endwith %}
          </body> 
          </html>
          


          注意:定義的變量只能在with語(yǔ)句塊中使用,在with語(yǔ)句塊外面使用取不到這個(gè)變量。

          2.4 url標(biāo)簽

          在模板中,經(jīng)常要寫一些超鏈接,比如a標(biāo)簽中需要定義href屬性,當(dāng)然如果通過(guò)硬編碼的方式直接將這個(gè)url寫死也是可以,但是不便于以后維護(hù),比如需要修改url地址,那涉及到的地方都要修改,因此建議使用這種反轉(zhuǎn)的方式來(lái)實(shí)現(xiàn),類似于django中的reverse一樣。

          # 應(yīng)用urls.py
          from django.urls import path
          from . import views
          
          app_name = 'article'
          urlpatterns = [
              path('index/', views.index, name='index'),
              path('book/', views.book, name='book'),
              path('movie/', views.movie, name='movie'),
              path('city/', views.city, name='city'),
              path('book/hot/<int:book_id>', views.hot_book, name='hot_book')
          ]
          
          # 視圖views.py
          from django.shortcuts import render, HttpResponse
          
          def index(request):
              return render(request, 'index.html')
          
          def book(request):
              return HttpResponse('讀書頁(yè)面')
          
          def movie(request):
              return HttpResponse('電影頁(yè)面')
          
          def city(request):
              return HttpResponse('同城頁(yè)面')
          
          def hot_book(request, book_id):
              return HttpResponse('最熱門文章:%d'%book_id)
          

          模板文件:

          <!DOCTYPE html>
          <html lang="en">
          <head>
              <meta charset="UTF-8">
              <title>文章首頁(yè)</title>
              <style>
                  li{
                      list-style: none;
                      display: inline-block;
                      margin-right: 20px ;
                  }
              </style>
          </head>
          <body>
              <ul>
                  <li><a href="">首頁(yè)</a></li>
                  <li><a href="/article/book/">讀書</a></li>  <!-- url硬編碼的方式 -->
                  <li><a href="{% url 'article:movie' %}">電影</a></li> <!-- url標(biāo)簽 -->
                  <li><a href="{% url 'article:city' %}">同城</a></li>
                  <li><a href="{% url 'article:hot_book' book_id=1 %}">最火文章</a></li> <!-- url標(biāo)簽 傳遞參數(shù),這個(gè)參數(shù)需要于url映射的參數(shù)名一樣,如果傳遞多個(gè)參數(shù),則空格隔開 -->
              </ul>
          </body>
          </html>
          


          2.5 autoescape標(biāo)簽

          DTL中默認(rèn)已經(jīng)開啟了自動(dòng)轉(zhuǎn)義,會(huì)將哪些特殊字符進(jìn)行轉(zhuǎn)義,比如會(huì)將<轉(zhuǎn)義成<等。

          def index(request):
              comment_info = '個(gè)人博客網(wǎng)站:<a href="http://www.qmpython.com"> 全民python</a>'
              context = {
                  'info': comment_info
              }
              return render(request, 'index.html', context=context)
          

          模板文件:

           <p>個(gè)人博客網(wǎng)站:<a href="http://www.qmpython.com"> 全民python</a></p>
           <p>
                {{ info }}   <!-- DTL默認(rèn)on開啟了自動(dòng)轉(zhuǎn)義,轉(zhuǎn)換成普通字符串 -->
           </p>
           <p>
               {% autoescape off %}   <!-- off關(guān)閉自動(dòng)轉(zhuǎn)義,解析html標(biāo)簽 -->
                  {{ info }}
               {% endautoescape %}
           </p>
          


          如果你不知道自己在干什么,最好是使用自動(dòng)轉(zhuǎn)義,這樣網(wǎng)站才不容易出現(xiàn)XSS漏洞(比如有些網(wǎng)站進(jìn)行評(píng)論的時(shí)候,發(fā)一些含惡意的js代碼,如果不進(jìn)行自動(dòng)轉(zhuǎn)義會(huì)進(jìn)行渲染,而不會(huì)做成普通的字符串),比如我個(gè)人博客的評(píng)論就處理了。如果是可信用的,可以關(guān)閉自動(dòng)轉(zhuǎn)義,比如我的文章內(nèi)容是只允許我個(gè)人發(fā)表,是可信任的,所以我直接關(guān)閉。后面可以通過(guò)過(guò)濾器safe類似處理。

          2.6 verbatim標(biāo)簽

          默認(rèn)在DTL模板中是會(huì)去解析那些特殊字符的,比如{% %}{{ }}等,如果我們?cè)谀硞€(gè)代碼片段不想使用DTL的解析,那么我們可以將這段代碼放在verbatim標(biāo)簽中。

          # 視圖
          def index(request):
              return render(request, 'index.html')
          
          # 模板
          <body>
              {% if msg %}
                  {{ msg }}
              {% else %}
                  沒(méi)消息
              {% endif %}
              <br>
              {% verbatim %}
                  {% if msg %}
                      {{ msg }}
                  {% endif %}
              {% endverbatim %}
          </body>
          


          這個(gè)主要是用在,有些前端模板語(yǔ)法layui還有vue中也使用{{}}來(lái)表示變量,這些與DTL類似,這樣就容易引起混淆,我們可以使用這個(gè)標(biāo)簽,來(lái)屏蔽掉DTL的解析,而讓前端模板去解析。

          2.7 注釋標(biāo)簽

          我們?cè)贖TML中經(jīng)常使用<!-- 注釋內(nèi)容 -->來(lái)進(jìn)行注釋,在Django模板中,我們還可以使用其他注釋。

          {# 被注釋的內(nèi)容 #}:將中間的內(nèi)容注釋掉。只能單行注釋。
          {% comment %}被注釋的內(nèi)容{% endcomment %}:可以多行注釋。
          

          這種注釋,當(dāng)我們查看網(wǎng)頁(yè)元素的時(shí)候是看不到的,即沒(méi)有被渲染,而<!-- -->還是可以看到原樣字符串的。

          2.8 自定義簡(jiǎn)單標(biāo)簽

          1)首先,需要添加一個(gè)templatetags的文件夾, 自定義標(biāo)簽必須處在已經(jīng)安裝了的app(INSTALLED_APPS注冊(cè)了)中的一個(gè)名叫templatetags的包中。

          templatetags 文件夾名字不能修改,這是django規(guī)定的。

          myproject
              |——myproject
               |——__init__.py
               |——asgi.py
               |——settings.py
               |——urls.py
               |——wsgi.py
              |——templates
              |——myapp
               |——migrations
               |——templatetags
                |——__init__.py
                |——custom_tags.py
              |——manage.py
          
          

          2)在templatetags下添加一個(gè)python文件,如我這里創(chuàng)建一個(gè)custom_tags.py文件,在文件中添加對(duì)應(yīng)的自定義標(biāo)簽。

          from django import template
          
          # register的名字是固定的,不可改變
          register = template.Library()
          
          #使用裝飾器注冊(cè)自定義標(biāo)簽  
          @register.simple_tag
          def curr_date(args):#args可傳參數(shù),根據(jù)實(shí)際需求而定
              return datetime.datetime.now().strftime(args)
          

          3)在要使用自定義標(biāo)簽的HTML模板中導(dǎo)入和使用自定義標(biāo)簽文件:

          {# 加載自定義標(biāo)簽所在的文件名,由于templatetags的文件名是固定的,django可以直接找到過(guò)自定義標(biāo)簽文件所在的位置 #}
          {% load custom_tags %}
          
          <h3>自定義標(biāo)簽</h3>
          時(shí)間日期:{% curr_date "%Y-%m-%d"%}
          

          我們?cè)賮?lái)定義簡(jiǎn)單標(biāo)簽article/templatetags/menu_tags.py

          from django import template
          
          # register的名字是固定的,不可改變
          register = template.Library()
          @register.simple_tag
          def my_menu():
              menu_list = ['首頁(yè)','項(xiàng)目實(shí)戰(zhàn)','每日一練']  
            
              return menu_list
          
          

          模板文件templates/article/my_menu.html

          <!DOCTYPE html>
          <html lang="en">
          <head>
              <meta charset="UTF-8">
              <title>自定義簡(jiǎn)單標(biāo)簽</title>
          </head>
          <body>
          <h1>-----------菜單欄--------------</h1>
          <br/>
          {% load menu_tags %}	<!-- 導(dǎo)入自定義的標(biāo)簽文件 -->
          
          {% my_menu as menus %}  <!-- 注意:這里需要使用as將標(biāo)簽文件返回的值賦給一個(gè)變量,然后再引用!!!-->
          
          <ul>
              {% for menu in menus %}  {# 企圖使用 {% for menu in my_menu %} 是沒(méi)效果的 #}
                  <li>{{menu}}</li>
              {% endfor %}
          </ul> 
          
          </body>
          </html>
          

          視圖渲染views.py

          def test(request):
              return render(request, 'article/my_menu.html')
          


          2.9 自定義包含標(biāo)簽inclusion_tag

          一種比較普遍的tag類型只是渲染其他模塊顯示下的內(nèi)容,這樣的類型叫做inclusion_tag,常用的模板標(biāo)簽是通過(guò)渲染其他模板顯示數(shù)據(jù)的。

          inclusion_tag作用:創(chuàng)建一個(gè)動(dòng)態(tài)頁(yè)面文件a.html,這個(gè)頁(yè)面可以在另外一個(gè)頁(yè)面b.html中被調(diào)用,實(shí)現(xiàn)這個(gè)頁(yè)面a中有的功能。

          例如,上面一個(gè)導(dǎo)航頁(yè)面my_menu.html,基本在每個(gè)頁(yè)面中都要包含導(dǎo)航,如我的個(gè)人博客一樣:



          那要怎么樣呢?

          例如,我們?cè)谑醉?yè)模板中,先試下用include來(lái)引入導(dǎo)航模板看看(include這個(gè)后面具體學(xué)習(xí),這里只演示作用)。

          與上面自定義簡(jiǎn)單標(biāo)簽類似,在自定義標(biāo)簽文件里面自定義包含標(biāo)簽:

          from django import template
          
          from article.models import Column
          
          # register的名字是固定的,不可改變
          register = template.Library()
          #使用裝飾器注冊(cè)自定義包含標(biāo)簽
          @register.inclusion_tag('article/my_menu.html') #將返回值傳給my_menu.html去,可以定義name,否則使用函數(shù)名
          def my_menu():
              # menus = ['首頁(yè)','項(xiàng)目實(shí)戰(zhàn)','每日一練']
              menus = Column.objects.all()
              
              return {'menus':menus}  
          
          

          my_menu.html

          <!DOCTYPE html>
          <html lang="en">
          <head>
              <meta charset="UTF-8">
              <title>自定義包含標(biāo)簽</title>
          </head>
          <body>
          <ul>
              {% for menu in menus %}
                <li> {{menu}} </li>
              {% endfor %}
          </ul>
          </body>
          </html>
          

          調(diào)用的html頁(yè)面文件:

          <!DOCTYPE html>
          <html lang="en">
          <head>
              <meta charset="UTF-8">
              <title>首頁(yè)</title>
          </head>
          <body>
          
          {% load menu_tags %}   <!-- 必須要先加載創(chuàng)建標(biāo)簽的文件-->
          
          {% my_menu %}    <!-- 調(diào)用my_menu.html頁(yè)面文件,這里使用該標(biāo)簽的函數(shù)名來(lái)調(diào)用-->
          
          <h1>首頁(yè)</h1>
          
          </body>
          </html>
          

          視圖渲染:

          def test(request):
          
              return render(request, 'article/index.html')
          

          2.10 人性化語(yǔ)義標(biāo)簽

          除了上述功能性標(biāo)簽外, Django 還提供了很多輔助性標(biāo)簽,這些標(biāo)簽只是為了使變量輸 出變得更加可讀,下面對(duì)這些標(biāo)簽進(jìn)行簡(jiǎn)單介紹。首先為了使用這些標(biāo)簽,需要在INSTALLED_APPS 中注冊(cè)django .contrib.humanize, 然后在模板中引用humanize:{% raw %}{% load humanize % }{% endraw %}

          apnumber

          將數(shù)字1 ~ 9 轉(zhuǎn)換為英文單詞,但是其他數(shù)字不轉(zhuǎn)換,如數(shù)字10 將被原樣輸出。示例:

          數(shù)字1 被轉(zhuǎn)換為one ;
          數(shù)字2 被轉(zhuǎn)換為two ;
          數(shù)字10 仍顯示10 ;
          

          如果當(dāng)前工程語(yǔ)言是中文的話,數(shù)字將會(huì)被轉(zhuǎn)換為對(duì)應(yīng)的漢字,例如:

          {% raw %}
          {{ 1|apnumber }}
          {{ 2|apnumber }}
          {{ 5|apnurnber }}
          {% endraw %}
          

          如果當(dāng)前工程語(yǔ)言是中文的話,數(shù)字將會(huì)被轉(zhuǎn)換為對(duì)應(yīng)的漢字,例如:

          輸出:

          一
          二
          五
          

          intcomma

          輸出以逗號(hào)分隔的數(shù)字,如4500 輸出4,500, 4500.2 輸出4,500.2 。

          intword

          以文字形式輸出數(shù)字,如1000000 輸出“ 1.0 million ”, 1200000 輸出“ 1,2 Million ” 。對(duì)于中文系統(tǒng),將會(huì)輸出對(duì)應(yīng)的中文,如1200000 輸出" 1.2 百萬(wàn)” 。

          naturalday

          將當(dāng)前日期以及前后一天輸出為today 、yesterday 和tomorrow ,而中文系統(tǒng)分別輸出 “今天”“昨天”和“明天” 。

          naturaltime

          對(duì)于日期時(shí)間格式,時(shí)間值與系統(tǒng)當(dāng)前時(shí)間比較,然后輸出結(jié)果。如當(dāng)前時(shí)間輸出 “ now ”, 29 秒前輸出“ 29 sec onds ago ” 。如果使用naturaltime 輸出今天、昨天、明天的話, 就會(huì)變成“現(xiàn)在”“ 23 小時(shí)·以后”“ 1 日之前” 。

          ordinal

          將數(shù)字轉(zhuǎn)換為序數(shù),如l 輸出“ 1 st ”;2 輸出“ 2nd ”;3 輸出“ 3rd ” 。注意此時(shí)中文與 英文的輸出一樣。

          3. 模板過(guò)濾器

          在模板中,有時(shí)候需要對(duì)一些數(shù)據(jù)進(jìn)行處理以后才能使用,一般在Python中我們是通過(guò)函數(shù)的形式來(lái)完成的,因?yàn)樵?span style="color: #1E6BB8; --tt-darkmode-color: #1E6BB8;">DTL中,不支持函數(shù)的調(diào)用形式(),因此在模板中,則是通過(guò)過(guò)濾器來(lái)實(shí)現(xiàn)的,過(guò)濾器使用的是|來(lái)使用。語(yǔ)法:

          {{ 變量名|過(guò)濾器名:傳給過(guò)濾器的參數(shù)}}
          

          3.1 常用過(guò)濾器

          比如使用date過(guò)濾器。

          # 視圖
          from datetime import datetime
          
          def index(request):
              now_time = datetime.now()
              context = {
                  'now_time': now_time
              }
              return render(request, 'index.html', context=context)
          
          
          # 模板文件
          <!DOCTYPE html>
          <html lang="en">
          <head>
              <meta charset="UTF-8">
              <title>文章首頁(yè)</title>
          </head>
          <body>
              {{ now_time }} <!-- 原始渲染 -->
              <br>
              {{ now_time | date:'Y-m-d H:i:s' }}  <!-- 通過(guò)過(guò)濾器,先將日期格式化,再渲染出-->
          </body>
          </html>
          


          date時(shí)間過(guò)濾器格式:

          格式字符描述示例Y4位數(shù)的年1999y2位數(shù)的年99m2位數(shù)的月01,09n1位數(shù)的月1,9,12d2位數(shù)的日01,09,31j1位數(shù)的日1,9,31g12小時(shí)制的一位數(shù)的小時(shí)1,9,12G24小時(shí)制的一位數(shù)小時(shí)0,8,23h12小時(shí)制的兩位數(shù)的小時(shí)01,09,12H24小時(shí)制的兩位數(shù)的小時(shí)01,13,24i分鐘00-59s秒00-59

          django常用過(guò)濾器:

          add:字符串相加,數(shù)字相加,列表相加,如果失敗,將會(huì)返回一個(gè)空字符串。default:提供一個(gè)默認(rèn)值,在這個(gè)值被django認(rèn)為是False的時(shí)候使用。比如:空字符串、None、[]、{}等。區(qū)別于default_if_none,這個(gè)只有在變量為None的時(shí)候才使用默認(rèn)值。first:返回列表中的第一個(gè)值。last:返回列表中的最后一個(gè)值。date:格式化日期和時(shí)間。time:格式化時(shí)間。join:跟python中的join一樣的用法。length:返回字符串或者是數(shù)組的長(zhǎng)度。length_is:字符串或者是數(shù)組的長(zhǎng)度是否是指定的值。lower:把所有字符串都編程小寫。truncatechars:根據(jù)后面給的參數(shù),截?cái)嘧址绻^(guò)了用表示。{{value|truncatechars:5}},如果value是等于北京歡迎您,那么輸出的結(jié)果是北京...,為啥不是北京歡迎您...呢?因?yàn)槿齻€(gè)點(diǎn)也占了三個(gè)字符,所以北京 + 三個(gè)點(diǎn)的字符長(zhǎng)度就是5。truncatewords:類似truncatechars,不過(guò)不會(huì)切割html標(biāo)簽,{{value|truncatewords:5}},如果value是等于<p>北京歡迎您</p>,那么輸出的結(jié)果是<p>北京...</p>capfirst:首字母大寫。slice:切割列表。用法跟python中的切片操作是一樣的,區(qū)間是前閉合后開放。striptags:去掉所有的html標(biāo)簽。safe:關(guān)閉變量的自動(dòng)轉(zhuǎn)義,解析html標(biāo)簽。floatformat:浮點(diǎn)數(shù)格式化。更多可以查詢官方文檔:https://yiyibooks.cn/xx/Django_1.11.6/ref/templates/builtins.html英文:https://docs.djangoproject.com/en/1.11/ref/templates/builtins/

          過(guò)濾器總結(jié):1、作用:對(duì)變量進(jìn)行過(guò)濾。在真正渲染出來(lái)之前,過(guò)濾器會(huì)根據(jù)功能處理好變量,然后得出結(jié)果后再替換掉原來(lái)的變量展示出來(lái)。2、語(yǔ)法:{{greeting|lower}},變量和過(guò)濾器中間使用管道符號(hào)”|”進(jìn)行使用。3、可以通過(guò)管道符號(hào)進(jìn)行鏈?zhǔn)秸{(diào)用,比如實(shí)現(xiàn)一個(gè)功能,先把所有字符變成小寫,把第一個(gè)字符轉(zhuǎn)換成大寫,如{{message|lower|capfirst}}

          4、過(guò)濾器可以使用參數(shù),在過(guò)濾器名稱后面使用冒號(hào)”:”再加上參數(shù),比如要把一個(gè)字符串中所有的空格去掉,則可以使用cut過(guò)濾器,代碼如下{{message|cut:" "}},冒號(hào)和參數(shù)之間不能有任何空格,一定要緊挨著。

          3.2 自定義過(guò)濾器

          雖然DTL給我們內(nèi)置了許多好用的過(guò)濾器,但是有些時(shí)候還是不能滿足我們的需求,因此Django給我們提供了一個(gè)接口,可以讓我們自定義過(guò)濾器,實(shí)現(xiàn)自己的需求。

          步驟:

          1、首先在某個(gè)應(yīng)用app中,創(chuàng)建一個(gè)python包,叫做templatetags,注意名字不能改動(dòng),不然找不到。

          2、在這個(gè)templatetags包下創(chuàng)建一個(gè)python文件用來(lái)存儲(chǔ)過(guò)濾器。

          3、在新建的python文件中,定義過(guò)濾器(也就是函數(shù)),這個(gè)函數(shù)的第一個(gè)參數(shù)永遠(yuǎn)是被過(guò)濾器的那個(gè)值,并且如果在使用過(guò)濾器的時(shí)候傳遞參數(shù),那么還可以定義另外一個(gè)參數(shù),但是過(guò)濾器最多只能有2個(gè)參數(shù)。

          4、自定義完過(guò)濾器,要使用django.template.Library.filter進(jìn)行注冊(cè)。

          5、過(guò)濾器所在app所在app需要在settings.py中進(jìn)行注冊(cè)。

          6、在模板中使用load標(biāo)簽加載過(guò)濾器所在的python包。

          7、在模板中使用自定義的過(guò)濾器。

          我們來(lái)實(shí)現(xiàn)一個(gè)朋友圈,或者文章發(fā)表時(shí)間顯示的過(guò)濾器:

          # 自定義過(guò)濾器 date_filter.py
          from django import template
          
          from datetime import datetime, timedelta
          
          # 將注冊(cè)類實(shí)例化為register對(duì)象
          # register = template.Library() 創(chuàng)建一個(gè)全局register變量,它是用來(lái)注冊(cè)你自定義標(biāo)簽和過(guò)濾器的,只有向系統(tǒng)注冊(cè)過(guò)的tags,系統(tǒng)才認(rèn)得你。
          # register 不能做任何修改,一旦修改,該包就無(wú)法引用
          register = template.Library()
          
          # 使用裝飾器注冊(cè)自定義過(guò)濾器
          @register.filter
          def date_filter(value):
              # 判斷一下,是不是時(shí)間日期類型
              if not isinstance(value, datetime):
                  return value
          
              now = datetime.now() + timedelta(hours=8)  # 將UTC時(shí)間轉(zhuǎn)為本地時(shí)間
          
              # total_seconds()是獲取兩個(gè)時(shí)間之間的總差
              timestamp = (now - value).total_seconds()
          
              if timestamp < 60:
                  return '剛剛'
              elif 60 <= timestamp < 60*60:   # sec >= 60 and sec < 60*60
                  mint = int(timestamp / 60)
                  return '{}分鐘前'.format(mint)
              elif 60*60 <= timestamp < 60*60*24:
                  hour = int(timestamp / 60 / 60)
                  return '{}小時(shí)前'.format(hour)
              elif 60*60*24 <= timestamp < 60*60*24*2:
                  return '昨天'
              else:
                  return timestamp.strftime('%Y-%m-%d %H:%M:%S')
          
          
          # 視圖views.py
          from django.shortcuts import render, HttpResponse
          
          from datetime import datetime
          
          def index(request):
              context = {
                  'public_time': datetime(year=2020, month=3, day=23, hour=23, minute=0, second=0)
              }
              print(context)
              return render(request, 'index.html', context=context)
          
          
          
          # 模板文件
          {% load date_filter %}
          <!DOCTYPE html>
          <html lang="en">
          <head>
              <meta charset="UTF-8">
              <title>文章首頁(yè)</title>
          </head>
          <body>
              {{ public_time|date_filter }}
          
          </body>
          </html>
          


          4. 模板結(jié)構(gòu)化優(yōu)化

          4.1 引入模板

          有時(shí)候一些代碼是在許多模板中都用到的,如果每次都重復(fù)的去拷貝代碼那肯定不符合項(xiàng)目的規(guī)范,一般我們可以把這些重復(fù)性的代碼抽取出來(lái),就類似于Python的函數(shù)一樣,以后想要使用這些代碼的時(shí)候,就通過(guò)include包含進(jìn)來(lái),這個(gè)標(biāo)簽就是include。比如大多數(shù)網(wǎng)頁(yè)都有頂部,中間,底部,可能進(jìn)入任何頁(yè)面頂部和底部都是一樣的,只有中間部分內(nèi)容不同,這個(gè)時(shí)候頂部和底部,我們就可以通過(guò)include包含起來(lái)。


          # 頂部,header.html
          <header>
              <ul>
                  <li>首頁(yè)</li>
                  <li>Python教程</li>
                  <li>Python Web開發(fā)</li>
                  <li>Python爬蟲</li>
              </ul>
              <p>用戶名:{{ username }}</p> <!-- 用于測(cè)試是否傳參 -->
          </header>
          
          # 底部,footer.html
          <footer>
              <div>?2019<a href="/">全民python</a> | 
                  <a href="http://beian.miit.gov.cn" rel="nofollow">粵ICP備18143893號(hào)</a> | 
              </div>
          </footer>
          
          # 首頁(yè),index.html
          <!DOCTYPE html>
          <html lang="en">
          <head>
              <meta charset="UTF-8">
              <title>文章首頁(yè)</title>
              <style>
                  div{
                      margin: 10px;
                  }
              </style>
          </head>
          <body>
            {% include 'header.html' with username='全民python' %}  <!-- 引入模板,并用with傳遞參數(shù) -->
            <div>
              這是中間內(nèi)容
            </div>
            {% include 'footer.html' %}
          </body>
          </html>
          

          視圖:

          def index(request):
              return render(request, 'index.html')
          


          我們使用include標(biāo)簽時(shí),如果引入的html代碼中需要傳入變量,則需要在所引入的view視圖中獲取變量,如果引入的html代碼中的變量是一個(gè)公共變量,則需要重復(fù)獲取N次,使用自定義包含標(biāo)簽inclusion_tag,可以在定義文件中獲取一次即可。

          templates/article/my_menu.html

          <!DOCTYPE html>
          <html lang="en">
          <head>
              <meta charset="UTF-8">
              <title>自定義簡(jiǎn)單標(biāo)簽</title>
          </head>
          <body>
          <h1>-----------菜單欄--------------</h1>
          <br/>
          {% load menu_tags %}	<!-- 導(dǎo)入自定義的標(biāo)簽文件 -->
          
          {% my_menu as menus %}  <!-- 注意:這里需要使用as將標(biāo)簽文件返回的值賦給一個(gè)變量,然后再引用!!!-->
          
          <ul> 
              {% for menu in menus %} {# 企圖使用 {% for menu in my_menu %} 是沒(méi)效果的 #}
                  <li>{{menu}}</li>
              {% endfor %}
          </ul> 
          
          </body>
          </html>
          

          article/templatetags/menu_tags.py

          from django import template
          from article.models import Column
          
          # register的名字是固定的,不可改變
          register = template.Library()
          @register.simple_tag
          def my_menu():
              #menu_list = ['首頁(yè)','項(xiàng)目實(shí)戰(zhàn)','每日一練']  
              menu_list = Column.objects.all()
            
              return menu_list
          

          templates/article/index.html

          <!DOCTYPE html>
          <html lang="en">
          <head>
              <meta charset="UTF-8">
              <title>首頁(yè)</title>
          </head>
          <body>
          
          {% include 'article/my_menu.html' %}
          
          <h1>首頁(yè)</h1>
          
          </body>
          </html>
          


          兩者感覺(jué)效果一樣。

          4.2 模板繼承

          對(duì)于模板的重復(fù)利用,除了使用include標(biāo)簽引入,還有另外種方式來(lái)實(shí)現(xiàn),那就是模板繼承。模板繼承類似于Python中的類,在父類中可以先定義好一些變量和方法,然后在子類中實(shí)現(xiàn),模板繼承也可以在父模板中先定義好一些子模板需要用到的代碼,然后子模板直接繼承就可以了,并且因?yàn)樽幽0蹇隙ㄓ凶约旱牟煌a,因此可以在父模板中定義一個(gè)block接口,然后子模板再去實(shí)現(xiàn)。

          我們將上面那個(gè)例子,使用模板繼承改寫下,將固定不變的頂部和底部,放在父模板中,中間變動(dòng)的部分,子模板去實(shí)現(xiàn)。

          <!-- 父模板-->
          
          <!DOCTYPE html>
          <html lang="en">
          <head>
              <meta charset="UTF-8">
              <title>{% block title %}全民python{% endblock %}</title>
              <style>
                  *{
                      margin: 0;
                      padding: 0;
                  }
                  header,footer{
                      background: black;
                      height: 60px;
                      width: 100%;
                      color: white;
                      text-align: center;
                      line-height: 40px;
                  }
                  footer{
                      height: 90px;
                      line-height: 90px;
                      position: absolute;
                      bottom: 0;
                  }
                  ul li{
                      list-style: none;
                      float: left;
                      margin: 20px;
                  }
                  #loginbox{
                      width: 400px;
                      height: 200px;
                      border: 1px solid red;
                      margin: 90px auto;
                      text-align: center;
                  }
              </style>
          </head>
          <body>
              <header>
                 <ul>
                     <li>首頁(yè)</li>
                     <li>編程語(yǔ)言</li>
                     <li>項(xiàng)目實(shí)戰(zhàn)</li>
                     <li>每日一學(xué)</li>
                  </ul>
              </header>
              <div class="content">
                  {% block content %}
                      這是子模板自己實(shí)現(xiàn)的部分
                  {% endblock %}
              </div>
              <footer >
                  這是footer部分
              </footer>
          </body>
          </html>
          
          
          <!-- 子模板-->
          {% extends 'base.html' %}  <!-- extends必須是模板中的第一個(gè)出現(xiàn)的標(biāo)簽 -->
          {% block title %}{{ block.super }}-登錄界面{% endblock %} <!-- block.super繼承父類的內(nèi)容,否則會(huì)覆蓋父類內(nèi)容 -->
          {% block content %}
              <div id="loginbox">
                  <br/>
                  <h2>登錄界面</h2>
                  <br/>
                  <form>
                      帳 號(hào):<input type="text">
                      <br/>
                      <br/>
                      密 碼:<input type="password">
                      <br/>
                      <br/>
                      <input type="submit" value="登錄">
                          
                      <input type="button" value="注冊(cè)">
                  </form>
              </div>
          {% endblock %}
          

          視圖函數(shù):

          def index(request):
              return render(request, 'index.html')
          

          效果展示:


          總結(jié):

          1. 模板繼承使用extends標(biāo)簽實(shí)現(xiàn),通過(guò)使用block來(lái)給子模板開放接口;
          2. extends必須是模板中第一個(gè)出現(xiàn)的標(biāo)簽;
          3. 子模板中的內(nèi)容必須放在父模板定義好的block中,否則將不會(huì)被渲染;
          4. 如果在某個(gè)block中需要使用父模板的內(nèi)容,那么可以使用{{ block.super }}來(lái)繼承;
          5. 子模板決定替換的block塊,無(wú)須關(guān)注其它部分,沒(méi)有定義的塊即不替換,直接使用父模板的block塊;
          6. 除了在開始的地方定義名字,我們還可以在結(jié)束的時(shí)候定義名字,如{% block title %}{% endblock %},這樣在大型模板中顯得尤其有用,能讓我們快速看到block所包含的開始和結(jié)束。

          模板引入與自定義inclusion_tag的區(qū)別:模板導(dǎo)入的頁(yè)面內(nèi)容是靜態(tài)的、不變的,而通過(guò)自定義inclusion_tag導(dǎo)入的頁(yè)面文件可以是動(dòng)態(tài)的,可動(dòng)性自己掌控。

          5. 加載靜態(tài)文件

          在一個(gè)網(wǎng)頁(yè)中,不僅僅只有一個(gè)html,還需要css樣式,js腳本以及一些圖片,因此在DTL中加載靜態(tài)文件是一個(gè)必須要解決的問(wèn)題,在DTL中,使用static標(biāo)簽來(lái)加載靜態(tài)文件,要使用static標(biāo)簽,首先需要{% load static %}

          1、首先,settings.py文件中,確保django.contrib.staticfiles已經(jīng)添加到INSTALLED_APPS中。

          INSTALLED_APPS = [
              ...
              'django.contrib.staticfiles',
              ...
          ]
          

          2、設(shè)置DEBUG調(diào)試模式。

          # 在settings.py中,默認(rèn)值是DEBUG = True
          DEBUG = True
          

          當(dāng)我們?cè)陂_發(fā)django應(yīng)用時(shí)如果設(shè)置了 DEBUG = True,那么django便會(huì)自動(dòng)幫我們對(duì)靜態(tài)文件進(jìn)行路由;但是當(dāng)我們?cè)O(shè)置DEBUG = False后,靜態(tài)文件找不到了,「img、css、js」都提示404,無(wú)法準(zhǔn)確的訪問(wèn) static 靜態(tài)文件。

          3、在開發(fā)模式下(Debug=True)時(shí),訪問(wèn)靜態(tài)文件有下面兩種情況:1)在已注冊(cè)的應(yīng)用app下創(chuàng)建一個(gè)靜態(tài)文件夾名稱static,然后再再這個(gè)static目錄下創(chuàng)建于app同名的 文件夾用于存放靜態(tài)文件(避免不同應(yīng)用app,靜態(tài)文件名字一樣,造成沖突)。

          Django將通過(guò) django.contrib.staticfiles在每個(gè)appstatic文件夾中為我們自動(dòng)查找這些靜態(tài)文件。

          2)如果有些靜態(tài)文件和應(yīng)用沒(méi)什么太大的關(guān)系,我們可以在項(xiàng)目根目錄下再創(chuàng)建static目錄,這個(gè)時(shí)候我們還需要在settings.py文件配置添加STATICFILES_DIRS,以后DTL就會(huì)在這個(gè)列表的路徑中查找靜態(tài)文件。

          # django2.x方式
          # STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')]  # 這里指靜態(tài)文件保存哪個(gè)目錄下,這個(gè)“static”指目錄名
          
          # django3.x方式
          # 一般用來(lái)設(shè)置通用的靜態(tài)資源,對(duì)應(yīng)的目錄不放在APP下,而是放在Project下,例如:
          STATICFILES_DIRS = [BASE_DIR / 'static']
          
          

          然后再像上面一樣加載靜態(tài)文件使用,一般直接在根項(xiàng)目下新建static,然后在下面新建不同以應(yīng)用名稱命名的目錄。

          STATICFILES_DIRS告訴django,首先到STATICFILES_DIRS里面尋找靜態(tài)文件,其次再到各個(gè)appstatic文件夾里面找(注意,django查找靜態(tài)文件是惰性查找,查找到第一個(gè),就停止查找了)。

          4、只有在生產(chǎn)模式(Debug=False)時(shí),STATIC_ROOT設(shè)置才生效。

          STATIC_ROOT 是在部署靜態(tài)文件時(shí)(pyhton manage.py collectstatic)所有的靜態(tài)文靜聚合的目錄,STATIC_ROOT要寫成絕對(duì)地址,如下例子STATIC_ROOT設(shè)為根目錄下的static_new文件,而STATICFILES_DIRS使用根目錄下的static目錄。

          #STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')]  # 這里指靜態(tài)文件保存哪個(gè)路徑,這個(gè)“static”指目錄名
          STATICFILES_DIRS = [BASE_DIR / 'static']
          
          if not DEBUG:
              #STATIC_ROOT = os.path.join(BASE_DIR, "static_new") #使用 collectstatic后收集的靜態(tài)文件的存放絕對(duì)路徑
              STATIC_ROOT = [BASE_DIR / 'static_new']
          

          當(dāng)部署項(xiàng)目時(shí),在終端輸入:

          # django會(huì)把所有的static文件都復(fù)制到STATIC_ROOT文件夾下
          python manage.py collectstatic
          


          然后可以看到根目錄下有創(chuàng)建了一個(gè)static_new文件夾,里面有STATICFILES_DIRS里設(shè)置的文件夾里的靜態(tài)文件,同時(shí)也有各appstatic文件夾里的靜態(tài)文件。

          在部署模式(Debug=False)時(shí),Django會(huì)從STATIC_ROOT設(shè)置的文件夾讀取靜態(tài)文件,而不再?gòu)?span style="color: #1E6BB8; --tt-darkmode-color: #1E6BB8;">STATICFILES_DIRS設(shè)置的文件夾或app下的static文件夾。所以在(Debug=False)時(shí)需要先python manage.py collectstatic同步一下靜態(tài)文件。

          說(shuō)明:真實(shí)上生產(chǎn),靜態(tài)文件可能就交給nginx了,配置好即可,就不會(huì)再?gòu)膁jango里面讀取靜態(tài)文件了。具體后續(xù)我們會(huì)細(xì)說(shuō)

          5、上面我們已經(jīng)配置好靜態(tài)文件了,那怎么樣訪問(wèn)呢?

          如果在瀏覽器是訪問(wèn),不可能輸入你的靜態(tài)文件的本地絕對(duì)地址吧,比如我的一種圖片的本地地址為 /root/src/project/QmpythonBlog/static/image/article/article_cover.png,那我們不可能

          在瀏覽器上直接輸入:http://127.0.0.1:5044/root/src/project/QmpythonBlog/static/image/article/article_cover.png 這樣子,瀏覽器會(huì)報(bào)錯(cuò), 沒(méi)有該頁(yè)面,那么django是如何讓瀏覽器也可以訪問(wèn)服務(wù)器上的靜態(tài)文件呢?

          上面已經(jīng)說(shuō)了,直接訪問(wèn)服務(wù)器本地的地址是不行的,那就需要一個(gè)映射。

          django利用STATIC_URL來(lái)讓瀏覽器可以直接訪問(wèn)靜態(tài)文件。

          settings.py文件中確保配置了STATIC_URLSTATIC_URL用于引用STATICFILES_DIRSSTATIC_ROOT所指向的靜態(tài)文件。

          當(dāng)我們創(chuàng)建Django項(xiàng)目的時(shí)候,在setting.py中默認(rèn)就已經(jīng)設(shè)置了。

          # 靜態(tài)文件存儲(chǔ),一般是我們的JS、css、系統(tǒng)的圖片文件等。
          # 這個(gè)“static”指訪問(wèn)靜態(tài)文件,引入時(shí)用的別名
          # 通過(guò)http://127.0.0.1/static/***就可以訪問(wèn)相關(guān)的靜態(tài)文件了。
          
          STATIC_URL = '/static/'
          

          例如:在應(yīng)用user下新建static目錄,再在static下新建user目錄:


          視圖:

          # user應(yīng)用下的視圖views.py
          
          def index(request):
              return render(request, 'user/index.html')
          

          模板文件:

          <!DOCTYPE html>
          <html lang="en">
          <head>
              <meta charset="UTF-8">
              <title>用戶登錄首頁(yè)</title>
          </head>
          <body>
              <p>用戶界面</p>
              <img src="/static/user/img/logo.png">  <!-- 如果配置文件是 STATIC_URL = '/abc/',則這里url:/abc/user/img/logo.png-->
          </body>
          </html>
          

          但是上面要寫絕對(duì)路徑不方便,那我們可以通過(guò)static標(biāo)簽來(lái)加載靜態(tài)文件:

          {% load static %}
          <!DOCTYPE html>
          <html lang="en">
          <head>
              <meta charset="UTF-8">
              <title>用戶登錄首頁(yè)</title>
          </head>
          <body>
              <p>用戶界面</p>
          {#    <img src="/static/user/img/logo.png">#}
          
              <img src="{% static '/user/img/logo.png' %}"> <!-- 通過(guò)static標(biāo)簽,django會(huì)去static目錄下尋找 -->
          </body>
          </html>
          

          {% static %}這個(gè)模板變量使用的就是STATIC_URL的值,例如默認(rèn)的STATIC_URL值為/static/,那么上面模板變量引用后的值便為/static/開頭的地址。

          那么STATIC_URL又是怎么能正確的找到靜態(tài)文件地址的呢。

          1)在開發(fā)模式下(Debug=True)時(shí),使用的是STATICFILES_DIRSapp下的static中的靜態(tài)文件,Django有默認(rèn)的對(duì)STATIC_URL路由能自動(dòng)找到放在里面的靜態(tài)文件。

          2)在部署模式(Debug=False)時(shí),使用的是STATIC_ROOT中的靜態(tài)文件,此時(shí)則沒(méi)有了默認(rèn)的對(duì)STATIC_URL的路由,需要自己在projecturls.py中寫一個(gè),將STATIC_URL開頭的請(qǐng)求轉(zhuǎn)發(fā)到STATIC_ROOT中進(jìn)行查找。

          from django.views.static import serve
          from django.conf.urls.static import static
          urlpatterns = [
              re_path(r'^static/(?P<path>.*)$', serve, {'document_root': settings.STATIC_ROOT}, name='static'),
          ]
          

          在部署生產(chǎn)環(huán)境時(shí)(Debug=False),通常使用另外一種方法就是使用Nginx來(lái)實(shí)現(xiàn)。

          如果你在項(xiàng)目中用到了static這個(gè)模板標(biāo)簽,那一定要將nginx(或其他)服務(wù)器的/static配置到與STATIC_ROOT一致!(如果執(zhí)行了收集的話)

          可以參考django部署配置:Centos7中使用Nginx+uWSGI+Django部署Web項(xiàng)目

          此時(shí)我們?cè)趹?yīng)用中加載靜態(tài)文件的話就只需要這么來(lái)寫了,需要將STATIC_URL設(shè)為/static/,以img加載為例:

          <img src="/static/images/good.png" alt="My image"/>
          

          額外知識(shí)點(diǎn):

          1、如果不想在模板文件中每次都通過(guò){% load static %}加載靜態(tài)文件。

          TEMPLATES = [
              {
                  'BACKEND': 'django.template.backends.django.DjangoTemplates',
                  #'DIRS': [os.path.join(BASE_DIR, 'templates')]  # django2寫法
                   'DIRS': [BASE_DIR / 'templates'],  # django3寫法
                  ,
                  'APP_DIRS': True,
                  'OPTIONS': {
                      'context_processors': [
                          'django.template.context_processors.debug',
                          'django.template.context_processors.request',
                          'django.contrib.auth.context_processors.auth',
                          'django.contrib.messages.context_processors.messages',
                      ],
                      'builtins': ['django.templatetags.static']  # 添加這一行,就會(huì)將static當(dāng)作內(nèi)置的標(biāo)簽,無(wú)需再手動(dòng)load
                  },
              },
          ]
          

          備注:一般個(gè)人傾向于,直接將static文件放到項(xiàng)目根目錄下,下面再根據(jù)app名字進(jìn)行分門別類。



          #Django#


          主站蜘蛛池模板: 国产自产V一区二区三区C| 一区二区三区在线观看视频| 日本高清天码一区在线播放| 精品视频无码一区二区三区| 久久国产三级无码一区二区| 一区高清大胆人体| 国产一区二区三区无码免费 | 制服中文字幕一区二区| 亚洲熟妇av一区| 久久婷婷色综合一区二区| 亚洲一区二区三区91| 国产凸凹视频一区二区| 中文字幕亚洲乱码熟女一区二区| 亚洲综合一区二区| 国产高清不卡一区二区| 亚洲国产精品一区二区第一页免 | 亚洲国模精品一区| 亚洲AV无码一区二区三区牲色 | 欧美成人aaa片一区国产精品 | 国内精品无码一区二区三区| 日本免费一区二区在线观看| 日本亚洲成高清一区二区三区| 夜夜高潮夜夜爽夜夜爱爱一区| 精品一区二区三区自拍图片区| 香蕉久久AⅤ一区二区三区| 国产一区二区三区在线电影| 日本一道高清一区二区三区| 亚洲日本乱码一区二区在线二产线 | 亚洲AV日韩AV天堂一区二区三区 | 亚洲一区二区三区免费视频| 国产丝袜无码一区二区三区视频| 一区二区不卡视频在线观看 | 精品一区狼人国产在线| 国产成人av一区二区三区不卡 | 久久人做人爽一区二区三区| 国产精品熟女一区二区| 无码国产精品一区二区免费I6| 在线观看日韩一区| 国产一区二区三区91| 精品国产福利一区二区| 色多多免费视频观看区一区|