轉載請註明來源地址和原做者(CFishHome)html
本篇文章將介紹模板相關的內容,例如:DTL模板語法(變量、模板標籤、過濾器、自定義過濾器)。只要一步一步跟着一塊兒操做,我相信模板這一塊的內容毫無難度,就好像學習MarkDown同樣好學好用。在此,由於前不久學校有不少事要處理,因此學習筆記耽擱了幾天,趁國慶好好補補落下的內容,還有本篇DTL語法涉及衆多,因此決定分上中下篇來說解和總結。html5
咱們先建立一個名爲my_template的新Django項目。由於這篇內容涉及的是模板內容,跟app關係不大,因此在這裏我就不建立一個app來進行URL映射了,而是直接在my_template主包
裏添加一個views.py文件進行URL映射。總體框架以下圖所示:
(1)爲views.py添加如下代碼:python
from django.http import HttpResponse def index(request): return HttpResponse("首頁")
(2)修改urls.py代碼以下:django
from django.urls import path from . import views urlpatterns = [ path('', views.index, name="index") ]
運行項目,能成功訪問127.0.0.1:8000,好了學前工做準備完畢,下面正式進入模板的學習。瀏覽器
在前面的學習中,咱們編寫的視圖函數只是直接返回文本,例如:HttpResponse("首頁"),而在實際生產環境中其實不多這樣用,由於實際的頁面大可能是帶有樣式的HTML代碼,這可讓瀏覽器渲染出很是漂亮的頁面。目前市面上有很是多的模板系統,其中最知名最好用的就是DTL和Jinja2。 DTL 是 Django Template Language 三個單詞的縮寫,也就是Django自帶的模板語言。固然也能夠配置Django支持Jinja2等其餘模板引擎,可是做爲Django內置的模板語言,和Django能夠達到無縫銜接而不會產生一些不兼容的狀況。所以建議你們學習好DTL。
如今總結下概念,爲後面的學習作準備:app
DTL(Django Template Language )名叫Django模板語言,用DTL編寫的是一個DTL模板文件,這個文件是一個帶有特殊語法的HTML文件,利用pycharm建立一個Django項目,那麼會自動生成一個template文件夾,這個文件夾就是存放項目的DTL模板文件(也就是帶有特殊語法的HTML文件)。在視圖函數裏面能夠利用render_to_string方法將指定的DTL模板文件編譯後渲染成Python的字符串格式,而後用HttpResponse方法打包返回給客戶端,或者在視圖函數裏面直接利用render方法將指定的DTL模板文件渲染接着自動打包成HttpResponse,而後視圖函數返回給客戶端。框架
渲染模板有多種方式。這裏講下兩種經常使用的方式。
(1) render_to_string:該函數會自動在templates文件夾搜尋DTL模板文件,找到後接着將DTL模板文件編譯後渲染成Python的字符串格式。最後再經過HttpResponse類包裝成一個HttpResponse 對象返回回去。
1.修改views.py代碼以下:ide
from django.template.loader import render_to_string from django.http import HttpResponse def index(request): html = render_to_string("index.html") # 該函數在templates文件夾搜尋是否含有index.html文件,找到後將該文件(DTL模板文件)編譯後渲染成Python的字符串格式 return HttpResponse(html) # 而後將html經過HttpResponse包裝後返回給瀏覽器進行顯示
2.templates文件夾就是專門存放DTL模板文件的,在工程目錄中能夠找到這個文件夾。而後在templates文件夾下添加index.html文件,以下圖所示:
3.添加index.html後,默認會生成一些html5的代碼,接着咱們修改該文件,在瀏覽器中顯示一段文字:
4.運行Django項目,而後輸入127.0.0.1:8000,顯示結果以下(成功訪問到了咱們渲染的模板文件index.html):
(2)以上方式雖然已經很方便了。可是django還提供了一個更加簡便的方式-render方法(推薦該方式),直接將模板渲染成字符串和包裝成 HttpResponse 對象一步到位完成。
1.在前一個測試render_to_string方法的代碼基礎上,修改views.py文件代碼以下:函數
from django.shortcuts import render from django.http import HttpResponse def index(request): return render(request, "index.html") # render方法很方便,只要第一個參數指定request對象,第二個參數指定模板文件的路徑,而後它會自動在templates文件夾下搜尋該文件,而後自動渲染再用HttpResponse包裝返回。
按下Ctrl+S保存,輸入127.0.0.1:8000,顯示結果以下(再次成功訪問到了咱們渲染的模板文件index.html):
2.分析render函數的內部實現,源代碼以下圖:
從上圖能夠看出,其實render方法內部也是調用render_to_string渲染、HttpResponse包裝再返回,直接使用render方法減輕了咱們對代碼的編寫,而且讓代碼更美觀簡潔,嗯~的確不錯。學習
上一小節我介紹瞭如何渲染模板,其中render或render_to_string方法有一個參數是指定DTL模板文件,而後在templates文件夾下查找指定的DTL模板文件。其實,對於DTL模板文件有一個專門的查找路徑,允許我一一道來。在項目的 settings.py 文件中。有一個 TEMPLATES 配置,這個配置包含了模板引擎的配置,模板查找路徑的配置等。以下圖所示:
這個TEMPLATES配置裏面有兩個重要的屬性:DIRS、APP_DIRS。DTL模板文件查找路徑能夠經過這兩個屬性配置。
(1) DIRS :這是一個列表,在這個列表中能夠存放全部的DTL模板文件路徑,之後在視圖中使用 render 或者 render_to_string 渲染模板的時候,會在這個列表的路徑中查找模板。通常狀況下是「os.path.join(BASE_DIR, 'templates')」,os.path.join()函數是將BASE_DIR和‘templates’拼接,其中BASE_DIR是當前項目的路徑,注意,不論項目被移動到哪一個目錄下,BASE_DIR都會動態修改當前項目的路徑,怎麼實現動態?同樣定位到settings.py文件前面的代碼,以下圖:
意思是說不管將項目放到哪裏,利用render等函數渲染模板時,均可以找到templates目錄下的DTL模板文件,由於BASE_DIR和‘templates’拼接起來其實就是templates文件夾的絕對路徑。
(2)APP_DIRS :默認爲 True ,這個設置爲 True 後,若是在DIRS指定的模板查找路徑不能找到模板文件,那麼就會在 INSTALLED_APPS 安裝了的APP下的 templates 文件加中查找模板。同樣定位到settings.py文件前面的代碼,以下圖(默認安裝了一些Django項目必須的app):
這個APP_DIRS的做用是當DIRS不能找到模板文件時,就在其餘app上查找模板,須要進行如下兩步:1.在INSTALLED_APPS添加app的名字。例如:"front"。2.在app目錄下建立一個名爲templates的文件夾(必須是這個名字,其餘不容許),而後添加DTL模板文件。那麼當DIRS找不到時就跑這個app裏的templates目錄找模板。
DTL模板文件查找順序:好比代碼 render('list.html') 。先會在 DIRS 這個列表中依次查找路徑下有沒有這個模板,若是有,就返回。若是 DIRS 列表中全部的路徑都沒有找到,那麼會先檢查當前這個視圖所處的 app (什麼叫當前這個視圖所在的app?其實就是假如views.py在front這個app目錄下,那麼front就是當前這個視圖所處的app。) 是否已經安裝,若是已經安裝了,那麼就先在當前這個 app 下的 templates 文件夾中查找模板,若是沒有找到,那麼會在其餘已經安裝了的 app 中查找。若是全部路徑下都沒有找到,那麼會拋出一個 TemplateDoesNotExist 的異常。
模板中能夠包含變量, Django 在渲染模板的時候,能夠傳遞變量對應的值過去進行替換。變量的命名規範和 Python 很是相似,只能是阿拉伯數字和英文字符以及下劃線的組合,不能出現標點符號等特殊字符。變量須要經過視圖函數渲染,視圖函數在使用 render 或者 render_to_string 的時候能夠傳遞一個 context 的參數,這個參數是一個字典類型。之後在模板中的變量利用{{變量名}}從這個字典中讀取值的。
舉個變量的栗子:
(1)修改views.py代碼以下(添加context參數來爲DTL模板文件傳遞變量):
from django.shortcuts import render from django.http import HttpResponse def index(request): context = { "username": "CFishHome學習" } return render(request, "index.html", context=context) # 函數指定關鍵字參數context來傳遞變量
(2)修改index.html模板的代碼以下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>CFishHome</title> </head> <body> {{ username }} </body> </html>
按下Ctrl+S保存,注意要在python文件保存,在index.html下保存不能自動從新運行。運行結果以下:
事實上,context字典鍵通常爲變量名(字符串類型),而值有多種類型,其中包括前面列舉的字符串、字典、元組、列表、類對象、函數名等。下面一一舉例測試經常使用的幾種變量類型的使用,字符串類型前面已列舉,這裏再也不演示:
(1)字典
與Python語法不一樣的是,DTL語法不容許經過中括號的形式訪問字典或列表中的值,好比dict['key']和list[1]是不支持的!不要問爲何,規則是那些大牛們定下來的,咱們只能遵循他們定下的規則。
修改views.py代碼以下:
from django.shortcuts import render from django.http import HttpResponse def index(request): context = { "book": { "book_id": "A001", "book_name":"人民的名義", "book_price":1000 } } return render(request, "index.html", context=context)
修改index.html代碼以下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>CFishHome</title> </head> <body> <p>{{ book.book_id }}</p> <p>{{ book.book_name }}</p> <p>{{ book.book_price }}</p> </body> </html>
按下Ctrl+S保存,運行結果以下(成功訪問字典的鍵所對應的值):
由於字典可使用點(.)語法獲取字典鍵所對應的值,而且也可使用點(.)語法調用字典內置的方法,因此在給這個字典添加key的時候,千萬不能和字典中的一些屬性或方法重複。好比items,items是字典的方法,那麼若是給這個字典添加一個items做爲key,那麼之後就不能再經過item來訪問這個字典的鍵值對了,而是變成訪問咱們自定義的items鍵所對應的自定義的值了。下面舉個栗子:
1.經過{{ 變量名.函數名 }}就能夠調用該變量對應的函數了,修改index.html代碼以下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>CFishHome</title> </head> <body> <p>{{ book.book_id }}</p> <p>{{ book.book_name }}</p> <p>{{ book.book_price }}</p> <p>{{ book.keys }}</p> </body> </html>
運行結果以下,經過字典內置的keys方法,成功訪問到了該字典含有的全部鍵:
2.修改views.py文件的context內容,添加與字典內置函數Keys衝突的keys鍵和對應的值,代碼以下:
from django.shortcuts import render from django.http import HttpResponse def index(request): context = { "book": { "book_id": "A001", "book_name": "人民的名義", "book_price": 1000, "keys": 200 } } return render(request, "index.html", context=context)
按下Ctrl+S保存,運行結果以下:
從上圖能夠看出,咱們自定義的與字典內置函數keys衝突的keys鍵被解析顯示在頁面上,可是字典內置函數keys永遠都執行不到了,由於被覆蓋了。因此在此提個建議:給字典添加key的時候,千萬不能和字典中的一些屬性或方法重複,否則會被覆蓋。
(2)列表或者元組
若是book是一個列表或者元組,是不能經過中括號的形式訪問列表和元組中的值,好比list[1]是不支持的!只可以經過'.'來訪問。
1.修改views.py文件的context內容,代碼以下:
from django.shortcuts import render from django.http import HttpResponse def index(request): context = { "book": ["水滸傳", "人民的名義", "魯迅自傳", "鋼鐵是怎樣煉成的"], "price": (100, 200, 300, 400) } return render(request, "index.html", context=context)
2.經過{{ 變量名.下表 }}就能夠訪問該變量對應的元素值了,修改index.html代碼以下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>CFishHome</title> </head> <body> <p>{{ book.0 }}</p> <p>{{ book.1 }}</p> <p>{{ book.2 }}</p> <p>{{ book.3 }}</p> <p>{{ price.0 }}</p> <p>{{ price.1 }}</p> <p>{{ price.2 }}</p> <p>{{ price.3 }}</p> </body> </html>
按下Ctrl+S保存,運行結果以下:
(3)類對象
若是book是一個對象,那麼就會能夠在模板訪問這個對象的屬性,或者是方法。
1.修改views.py文件的context內容,代碼以下:
from django.shortcuts import render from django.http import HttpResponse class A: def __init__(self, count): self.count=count def show(self): print("我是一個類") def index(request): a = A(100) context = { "book": a } return render(request, "index.html", context=context)
2.經過{{ 變量名.屬性或者函數名 }}就能夠訪問該對象對應的屬性或調用對應的函數了,修改index.html代碼以下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>CFishHome</title> </head> <body> <p>{{ book.show }}</p> <p>{{ book.count }}</p> </body> </html>
按下Ctrl+S保存,運行結果以下:
由上可得出,在DTL模板文件成功訪問到對象的屬性,第一個輸出的是None,由於只是單純的調用(輸出信息在下圖所示控制檯)。
(4)函數
book也能夠是一個函數名(例如:show或show()),表明這個函數,在DTL模板文件中引用時也是{{ 變量名 }}方式調用函數,須要注意的是這種方式是沒法傳遞函數參數的,因此這個函數在定義時寫參數也沒用。
1.修改views.py文件的context內容,代碼以下:
from django.shortcuts import render from django.http import HttpResponse def show(): print("我是一個簡單的函數") def index(request): context = { "book": show } return render(request, "index.html", context=context)
2.經過{{ 變量名.函數名 }}就能夠訪問該函數了,修改index.html代碼以下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>CFishHome</title> </head> <body> <p>{{ book.show }}</p> </body> </html>
按下Ctrl+S保存,運行結果以下:
建立了一個Django項目,可是運行時報錯可能會報下面這個錯誤:
爲何會報這個錯誤?其實就是端口被佔用了,那以我目前這個電腦程序運行狀況舉例,我開機->打開酷狗(聽音樂)->打開pycharm->建立Django項目(默認使用8000端口)->運行項目->報端口占用錯誤。
咱們打開CMD執行如下命令:
第一條命令找出8000端口對應的PID進程爲2032,第二條命令經過進程ID找出進程對應的詳細信息,能夠看到這個進程對應的是酷狗服務。問題找到了,就是由於咱們先開啓了酷狗,酷狗服務佔用了咱們的測試端口。因此解決辦法有兩個:
1.關閉酷狗再從新運行Django項目。
2.將Django項目的測試端口改成其餘,例如:9000