Django:模板template(一)
把模板的過程、語法、標簽、反向地址解析、過濾器、模板繼承與HTML轉義記下筆記
1、概述及demo
動態生成HTML
模板的設計實現業務邏輯(View)和顯示內容(template)的分離
一個模板可以給多個視圖去使用,模板所使用的語法稱為DTL(Django Template Language)定義在django.template包
如果要調用模板,則需要如下步驟:
- 加載模板。通過loader的get_template方法指定一個模板
- 渲染模板。
- 指定一個上下文對象,RequestContext()
- 用模板的render()方法接收上下文對象。作為HttpResponse()的參數
demo示例的過程:創建工程 - 添加數據庫 - 創建應用 - 添加模板路徑 - 設置路由 - 編寫urls.py - 編輯視圖 - 添加模板
添加模板路徑:修改settings.py配置,在TEMPLATES中修改DIRS。指定TEMPLATES的目錄
TEMPLATES = [ { ‘BACKEND‘: ‘django.template.backends.django.DjangoTemplates‘, ‘DIRS‘: [os.path.join(BASE_DIR, ‘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‘, ], }, },
添加模板:
booktest/views.py
from django.http import HttpResponse from django.template import loader, RequestContext
def resp(request): t1 = loader.get_template(‘booktest/resp.html‘) context = RequestContext(request, {"text":"helloworld"}) return HttpResponse(t1.render(context))
templates/booktest/resp.html
<body> {{text}} </body>
實際上上面的代碼通過會被封裝到一個函數render()中,所以我們一般簡寫為
from django.shortcuts import render from django.http import HttpResponse def resp(request): context = {"text":"helloworld"} return render(request, "booktest/resp.html", context)
2、模板語法
- 變量。兩個大括號括起來的 {{變量名}}
- 標簽。代碼段 {% 代碼塊 %}
- 過濾器。就是一個豎線(|)
- 註釋。{# 這裏是註釋 #}
變量
模板碰到變量的時候,計算這個變量的值,然後將結果輸出
變量名有字母、數字、下劃線組成。必須以字母或下劃線開頭
當模板引擎碰到圓點的時候,會按照如下的順序進行查詢:
- 字典。把圓點前面的內容理解為一個字典,圓點後面的內容理解為鍵
- 屬性或方法查詢。把圓點前面的內容理解為一個對象,圓點後面的內容理解為對象裏面的屬性或方法(訪問方法不能加括號,方法也不能定義參數)
- 數字索引查詢。把圓點前面的內容理解為列表或元組。圓點後面的內容理解為下標(下標只能為數字,不能為字符串)
比如訪問{{book.id}},會按照如下順序解析:
- 把book當做字典。訪問book[‘id’],如果book字典中有id的鍵,則查詢成功,並返回,如果沒有id的鍵,或者甚至沒有book字典,查詢失敗,往下
- 把book當做對象,把id當做屬性或方法,嘗試訪問book.id或book.id()如果book對象中有id的屬性或方法,則查詢成功,調用並返回,否則往下
- 把book當做列表或元組,把id當做索引,訪問book[id],如果訪問成功,則輸出,否則往下
- 把book.id作為空字符串’’來輸出
3、引入模型
在models.py中定義類HeroInfo
booktest/models.py
from django.db import models # Create your models here. class BookInfo(models.Model): btitle = models.CharField(max_length = 20) bpub_date = models.DateTimeField(db_column = ‘pub_date‘) bread = models.IntegerField() bcomment = models.IntegerField() isDelete = models.BooleanField() class Meta(): db_table = ‘bookinfo‘ class HeroInfo(models.Model): hname = models.CharField(max_length = 10) hgender = models.BooleanField() hcontent = models.CharField(max_length = 1000) isDelete = models.BooleanField() book = models.ForeignKey(‘BookInfo‘, on_delete = models.CASCADE) def showname(self): return self.hname
生成遷移,數據庫中生成bookinfo和booktest_heroinfo的表
>>>python manage.py makemigrations
>>>python manage.py migrate
把book和hero的sql語句插入到數據庫中
修改視圖類 booktest/views.py
from django.shortcuts import render from booktest.models import BookInfo, HeroInfo # Create your views here. def index(request): hero = HeroInfo.objects.get(pk=1) context = {‘hero‘: hero} return render(request, ‘booktest/index.html‘, context)
模型中,既可以訪問屬性,也可以訪問方法(訪問方法不能加括號)
booktest/index.html
<body> {{hero.hname}} {{hero.showname}} </body>
4、使用標簽
語法:{% 標簽 %}。註意標簽中寫的是代碼
作用:
- 在輸出中創建文本
- 循環或條件判斷等邏輯
- 加載外部信息
for標簽
{% for ... in ... %}
{{ forloop.counter }} 表示當前是第幾次循環
{% empty %}
列表是空或不存在的時候,執行這裏
{% endfor %}
修改views.py booktest/views.py
# Create your views here. def index(request): heroList = HeroInfo.objects.filter(isDelete=False) context = {‘heroList‘: heroList} return render(request, ‘booktest/index.html‘, context)
模板的代碼中添加for標簽 templates/booktest/index.html
<ul> {% for hero in heroList %} <li>{{ forloop.counter }}: {{hero.showname}}</li> {% empty %} <li>找不到</li> {% endfor %} </ul>
if標簽
{% if ... %}
邏輯1
{% elif ... %}
邏輯2
{% else %}
邏輯3
{% endif %}
比如,想奇數行顯示紅色,偶數行顯示藍色
<ul> {% for hero in heroList %} {% if forloop.counter|divisibleby:"2" %} <li style="color:red">{{ forloop.counter }}: {{hero.showname}}</li> {% else %} <li style="color:blue">{{ forloop.counter }}: {{hero.showname}}</li> {% endif %} {% empty %} <li>找不到</li> {% endfor %} </ul>
4、反向地址解釋
{% url name p1 p2 ... %}
先創建一個頁面
路由: booktest/urls.py
urlpatterns = [ url(‘^$‘,views.index), # 路由到views.py中的index()函數 url(‘^(\d+)$‘,views.show), ]
視圖: booktest/views.py
urlpatterns = [ url(‘^$‘,views.index), # 路由到views.py中的index()函數 url(‘^(\d+)$‘,views.show), ]
模板:templates/booktest/show.html
<body> {{id}} </body>
接下來考慮在index中,添加一個鏈接,點擊後可以跳轉到123。一般是這樣寫
<a href="/booktest/123">跳轉</a>
但是萬一路由被改變了
urlpatterns = [ url(r‘^admin/‘, include(admin.site.urls)), url(‘booktest1/‘, include(‘booktest.urls‘)) ]
此時,鏈接的地址就發生了改變。如果要隨時去修改鏈接的地址,就有點麻煩了
因此考慮使用地址的反向解釋:
正向:在瀏覽器中輸入url後,用該url去匹配規則(URL_PATTERNS)
反向:根據URL規則,生成一個地址
首先,在urls的根中,使用namespace
django4/urls.py
urlpatterns = [ url(r‘^admin/‘, include(admin.site.urls)), url(‘booktest/‘, include(‘booktest.urls‘, namespace=‘booktest‘)) ]
在子urls中,添加name
booktest/urls.py
urlpatterns = [ url(‘^$‘,views.index), # 路由到views.py中的index()函數 url(‘^(\d+)$‘,views.show, name="show"), ]
在模板中使用反向地址解釋
{% url name p1 p2 ... %}
其中,這裏的name是指namspace:name
<a href="{% url ‘booktest:show‘ 123 %}">跳轉</a>
5、過濾器
# 語法: {{ 變量|過濾器 }} # 比如: {{ name|lower }} # 表示將變量name的值全部變成小寫 # 豎線|可以理解為python中的圓點(.) # 可以在if標簽中,使用過濾器,並結合運算符一起使用 {% if name|length > 2 %} # 過濾器可以用來串聯,構成過濾器鏈 name | lower | upper # 過濾器可以傳遞參數 list | join:”,” # 設置默認值的過濾器 value | default:”0” #設置日期 value | date:”YYYY-mm-dd”
常用的django過濾器參考:https://www.cnblogs.com/huangxm/p/6286144.html
6、模板繼承
很多網站的頭部(頁頭)、底部(頁腳)都是一樣的。
把多個頁面通用的部分抽取出來,做成父模板。然後在子模板中繼承父模板,再實現各自的差異。
相關的概念:
block標簽。在父模板中預留區域,在子模板中進行填充
定義父模板base.html
{% block block_name %}
這裏可以定義默認值。如果不定義默認值,表示默認值為空
{% endblock block_name %}
extends繼承。寫在子模板文件的第一行
定義子模板index.html
{% extends ‘base.html’ %} {% block block_name %} 實際填充內容 {% endblock block_name %}
如下例子:
定義父模板
在templates/booktest目錄下創建base.html
templates/booktest/base.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>標題</title> {% block head %} {% endblock head %} </head> <body> <h1>頁頭:logo</h1> <hr/> {% block content %} <h1>默認的內容</h1> {% endblock content %} <hr/> <h1>頁腳:聯系我們</h1> </body> </html>
子模板
templates/booktest/index2.html
{% extends ‘booktest/base.html‘ %}
路由和視圖略寫了。
如果要修改中間的內容:
可以在index2.html中添加
{% extends ‘booktest/base.html‘ %} {% block content %} <h1>修改後的內容</h1> {% endblock content %}
7、HTML轉義
通過視圖往模板輸出帶html標簽的內容的時候
booktest/views.py
def htmlTest(request): context = {‘text1‘:‘<h2>123</h2>‘} return render(request, ‘booktest/htmlTest.html‘, context)
對應的模板捕獲
templates/booktest/htmlTest.html
<body>
{{text1}}
</body>
其實這裏是做了html的轉義。當我們給一段html格式的字符串的時候,到了模板中會自動的轉義成特殊字符。最終原封不動的輸出
實際上它使用的就是escape過濾器進行自動轉義,所以下面兩句是一樣的效果
{{text1}}
{{text1 | escape }}
當需要按照它指定的格式輸出的時候,考慮使用safe過濾器,目的是關閉轉義
{{text1 | safe }}
如果有一整塊代碼都需要轉義,考慮使用autoescape,並通過設置on打開轉義,設置off關閉轉義
{% autoescape off %}
{{text1}}
{% endautoescape %}
如果是在模板代碼中直接寫html字符串
{{ text2 | default:‘<h2>456</h2>‘ }}
則直接輸出456,不需要轉義
Django:模板template(一)