1. 程式人生 > >Django:模板template(一)

Django:模板template(一)

views att 添加模板 cor return 創建工程 執行 auto 文本

把模板的過程、語法、標簽、反向地址解析、過濾器、模板繼承與HTML轉義記下筆記

1、概述及demo

動態生成HTML

模板的設計實現業務邏輯(View)和顯示內容(template)的分離

一個模板可以給多個視圖去使用,模板所使用的語法稱為DTLDjango Template Language)定義在django.template

如果要調用模板,則需要如下步驟:

  1. 加載模板。通過loaderget_template方法指定一個模板
  2. 渲染模板。
    1.   指定一個上下文對象,RequestContext()
    2.   用模板的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、模板語法

  • 變量。兩個大括號括起來的 {{變量名}}
  • 標簽。代碼段 {% 代碼塊 %}
  • 過濾器。就是一個豎線(|
  • 註釋。{# 這裏是註釋 #}

變量

模板碰到變量的時候,計算這個變量的值,然後將結果輸出

變量名有字母、數字、下劃線組成。必須以字母或下劃線開頭

當模板引擎碰到圓點的時候,會按照如下的順序進行查詢:

  1. 字典。把圓點前面的內容理解為一個字典,圓點後面的內容理解為鍵
  2. 屬性或方法查詢。把圓點前面的內容理解為一個對象,圓點後面的內容理解為對象裏面的屬性或方法(訪問方法不能加括號,方法也不能定義參數)
  3. 數字索引查詢。把圓點前面的內容理解為列表或元組。圓點後面的內容理解為下標(下標只能為數字,不能為字符串)

比如訪問{{book.id}},會按照如下順序解析:

  1. book當做字典。訪問book[‘id’],如果book字典中有id的鍵,則查詢成功,並返回,如果沒有id的鍵,或者甚至沒有book字典,查詢失敗,往下
  2. book當做對象,把id當做屬性或方法,嘗試訪問book.idbook.id()如果book對象中有id的屬性或方法,則查詢成功,調用並返回,否則往下
  3. book當做列表或元組,把id當做索引,訪問book[id],如果訪問成功,則輸出,否則往下
  4. 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

bookherosql語句插入到數據庫中

修改視圖類 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、使用標簽

語法:{% 標簽 %}。註意標簽中寫的是代碼

作用:

  1. 在輸出中創建文本
  2. 循環或條件判斷等邏輯
  3. 加載外部信息

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(一)