Django模板詳解!如何利用Django寫出前端界面?Django全棧工程師必看系列! ✧*。٩(ˊᗜˋ*)و✧*。 Django初體驗


在這裏插入圖片描述

Django模板簡介

Django使用的是MVT模型,而模板就是MVT中的T: templates 模版,也是Django區別與常規的MVC模型不同的地方。模板是前後端交互的一個橋樑,Django就是依靠模板,將參數傳入前端頁面。下列我將介紹,模板一般放置於那些位置,如何讓.html和.py能相互交互。

模板路徑

模板所在路徑,並非絕對的規定,只是一種大部人人都遵守的守則。一般模板都會放在名爲templates的文件中,而這個文件,可以放在兩個位置,分別是項目根目錄中,或者放在APP的根目錄中(一般項目根目錄中的頁面優先級會大於APP中的)
(如果使用pycharm創建項目,根目錄中的templates會被自動創建,且os.path.join(BASE_DIR, 'templates')也會自行添加,但APP中的templates文件需要手動註冊,在列表INSTALLED_APPS添加APP名即可,不過前提是要確定'APP_DIRS': True,(True爲默認選項)
在這裏插入圖片描述

導入HTML

在Python中導入HTML也有兩種方式。下述信息不在包含如何路由等信息,如何路由可以在Django路由機制詳解中查看

  1. 方式一: 使用from django.template.loader import render_to_string
from django.template.loader import render_to_string
from django.http import HttpResponse


# 在此處創建視圖。
def home(request):
    html = render_to_string('home.html')
    return HttpResponse(html)

這種方式使用較少,暫不詳細講解了,在絕大部分情況下我們都會使用下列方式導入HTML
2. 方式二: 使用from django.shortcuts import render

from django.shortcuts import render


# 在此處創建視圖。
def home(request):
    return render(request, 'home.html')

相比於第一種方式,我們發現第二種方式會讓代碼顯得更加簡潔,可讀性更好。

模板變量

變量我們可以簡單看成傳值,使用模板進行傳值操作,在Python中,需要使用到context屬性,這是render與render_to_string都具有的屬性。在HTML中加入{{字典鍵}}
模板變量Python部分: 使用context=字典(context必須傳入字典dict的數據類型)的方式,如果你需要傳入列表或元組或者其他類型的值,將其當成字典鍵傳入。此處字典的鍵,甚至可以穿入一個類

from django.shortcuts import render


class MyName:
    def __init__(self, name):
        self.name = name

    def get_name(self):
        """"""
        return '我是類方法'


xunmi = MyName('我是類屬性')

data = {
    '暱稱': '尋覓',
    '字典': {
        '鍵1': 1,
        '鍵2': 2,
    },
    '列表': [
        'one',
        2,
        '三'
    ],
    '類': xunmi
}


# 在此處創建視圖。
def home(request):
    # html = render_to_string('home.html')
    return render(request, 'home.html', context=data)

模板變量HTML部分: 接收使用{{字典鍵}}的方式,如下(如果你是一個前端,你可以將需要後端接收變量的地方使用{{}}事先預留,然後想後端詢問字典鍵填入即可事先傳值)

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    <h1>這是{{暱稱}}首頁</h1>
    <h1>{{字典.keys}}{{字典.values}}可以使用keys和values等屬性</h1>
    <h1>這是列表:{{列表}}</h1>
    <h1>這是列表第一個元素:{{列表.0}}</h1>
    <h1>這是列表第二個元素:{{列表.1}}</h1>
    <h1>這是列表第三個元素:{{列表.2}}</h1>
    <h1>這是一個類屬性:{{類.name}}</h1>
    <h1>這是一個類方法:{{類.get_name}}</h1>
</body>
</html>

在這裏插入圖片描述

模塊語言(DTL)

在寫上述變量時候,我們如果需要取鍵爲列表或其他可迭代對象時會比較麻煩,如果能使用for語句那將會如虎添翼,

添加代碼模板

代碼模板純屬是方便之後使用,Django的模板在pycharm專業版中自行攜帶,如果你是用的並非是專業版,可以在設置中執行添加
在這裏插入圖片描述
我們可以添加幾個常用的模板,比如說if和for

# if模板
{% if $VARIABLE$ %}
$END$
{% endif %} 
# for模板
{% for $VAR$ in $COLLECTION$ %}
$END$
{% endfor %}

添加好模板後,我們如果需要使用只要輸入相應的縮寫,然後在按下tab鍵即會自動補齊

for與if標籤

for與if和Python使用方式大相徑庭,只是需要在使用時,用{% 標籤 %}進行包裹即可,使用比較簡單,這裏就合併一起進行講解。HTML和Python中唯一不同的是,在結束時候我們需要使用一個結束標籤來標記,其中if的結束標籤爲{% endif %}而for的結束標籤爲{% endfor %}
在for循環中,模板語言提供了一些變量可供使用

變量 作用
forloop.counter 當前循環的次數(從1開始計算)
forloop.counter0 當前循環的下標(從0開始計算)
forloop.revcounter 剩餘循環的次數(從總循環次數開始計算)
forloop.revcounter0 剩餘循環的次數(從總循環次數-1開始計算)
forloop.first 是否爲第一次循環
forloop.last 是否爲最後一次循環
forloop.parentloop 輸出父循環的信息(循環次數,剩餘次數,是否爲第一次、最後一次循環,如果其父循環存在父循環,則會一同輸出)
<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    {% for foo in 列表 %}
        {% for foo1 in 字典 %}
            {% for foo2 in 暱稱 %}
                <p>{{ forloop.parentloop }}</p>
                <p>{{ foo2 }}</p>
            {% endfor %}
            <p>{{ foo1 }}</p>
        {% endfor %}
        
        {% if foo == '2' %}
            <h3>我是加粗的二貨</h3>
        {% else %}
            <p>我是列表:{{ foo }}</p>
        {% endif %}
    {% endfor %}
</body>
</html>

再次需要注意的是for循環語句中的break與continue無法使用,且沒有whlie循環
在這裏插入圖片描述

url標籤

url標籤將會是我們非常常用的標籤之一,雖然我們可以將標籤寫死在頁面中,但聰明的程序員絕對不會這樣幹,因爲這樣既不利於後期的維護。
這裏url類似與Django路由中的反轉機制,需要我們現在path中寫入name,然後在基於此name進行跳轉,在跳轉同時,我們也可以攜參跳轉,兩種傳參方式下列代碼中也都有演示。
url標籤的Python代碼
(Django項目APP中urls.py文件中代碼):

from django.urls import path
from . import views

app_name = 'front'

urlpatterns = [
    path('home/', views.home, name='home'),
    path('home/<items>/', views.home, name='home'),
    path('index/', views.index, name='index'),
]

Django項目APP中views.py文件中代碼

from django.shortcuts import render


# 在此處創建視圖。
def home(request, items='默認值'):
    # html = render_to_string('home.html')
    data = {'參數': items}
    return render(request, 'home.html', context=data)


def index(request):
    uid = request.GET.get('id')
    data = {'參數': uid}
    return render(request, 'index.html', context=data)

url標籤的HTML中代碼
home.html:

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>

<h1>攜帶了"{{ 參數 }}"歸來了</h1>
<a href="{% url 'front:index' %}">立刻馬上來點我</a>
<br>
<a href="{% url 'front:index' %}?id=1">我是問號傳參</a>

</body>
</html>

index.html:

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>我就是一測試頁面</title>
</head>
<body>

    <p>我真的就是一個測試頁面,不要過來啊</p>
    {% if 參數 %}
        <h1>你居然將參數"{{ 參數 }}"插入了我</h1>
    {% endif %}
    <a href="{% url 'front:home' '位置參數' %}">快按我跳回去(位置參數)</a>
    <br>
    <a href="{% url 'front:home' items='關鍵字參數' %}">快按我跳回去(關鍵字參數)</a>
    
</body>
</html>

在這裏插入圖片描述

模板過濾器

過濾器的作用是在HTML頁面中將傳入的參數進行過濾,留下有用的,這個操作雖然可以在Python代碼中完成,但有時候我們會發現在HTML中放入過濾器效果會更好,下面我會簡單介紹一些常用的過濾器。如果你想了解全部的過濾器可以自行去from django.template import defaultfilters此庫中查看過濾器源碼。

add(拼接)

此拼接主要用於字符串(str)與整數(int),浮點型(float)會自動被轉換成整數(int),小數部分自動省去。
將傳入的值拼接到原值上,這個過濾器比較智能,如果兩個變量都爲數字,他會將其相加,無論是否爲整數類型(如果是字符串類型的數字會將其自動轉換爲整數)如果是字符串則會進行字符的拼接。這裏需要注意的是Python是強類型語言,所以不同字符類型的內容無法相加,比如說2+'億'爲空值,須寫成'2'+'億'!

<!--列表.1: '2' ; 字典.鍵2: 2-->
<p>我是add過濾器:'{{ 列表.1 | add:字典.鍵2 }}'或'{{ '3' | add:'億' }}'</p>

join(拼接)

將可迭代對象進行拼接(比如說列表,元組,字符串),用法類似與Python中的join

<!--列表=['one', '2', '三']-->
<p>我是join過濾器:{{ 列表 | join:' - ' }}</p>

silce(切片)

和Python中列表等可迭代對象切片方式類似,格式都爲(起始角標:結束角標:步長),比如下列切片就將其中的兩個逗號成功切分出來了

<!--'切片使用': '你好,我是,尋覓'-->
<p>我是slice過濾器:{{ 切片使用 | slice:'2:6:3' }}</p>

cut(移除)

移除值中所以指定的字符串,類似於Python中的reqlace(args,’’)

<!--暱稱: '尋覓'-->
<p>我是cut過濾器:'{{ 暱稱 | cut:'尋' }}'</p>

date(時間)

將一個日期按指定格式格式化成字符串

<!--'時間': datetime.now(), datetime.now()是Python內置庫中的方法,會讀取當前時間,格式樣式(/ :)可以自定義-->
<p>我是date過濾器:原始樣式-'{{ 時間 }}'過濾器轉換後-'{{ 時間 | date:'Y/m/d G:i:s' }}'</p>
常用格式字符 描述 示例
Y 四位數字年份 2020
m 兩位數字月份 01-12
n 一位或兩位數字月份 1-12
d 兩位數字天數 01-31
j 一位或兩位數字天數 1-31
g 帶前綴0的十二小時制小時 01-12
h 不帶前綴0的十二小時制小時 1-12
G 帶前綴0的二十四小時制小時 00-23
H 不帶前綴0的二十四小時制小時 0-23
i 帶前綴0的分鐘 00-59
s 帶前綴0的秒鐘 00-59

default(默認值)

當值被評估爲Falst時會使用default所提供的默認值([],{},None,Falst等都會被評估爲Falst)

<!--空值=None-->
<p>我是default過濾器:{{ 空值 | default:'此處無值' }}</p>

flast(返回首元素)與last(返回尾元素)

返回可迭代對象的第一個元素|最後一個元素

<!--列表=['one', '2', '三']-->
<p>我是first與last過濾器:列表第一個元素-{{ 列表 | first }} | 列表最後一個元素-{{ 列表 | last }}</p>

floatformat(移除)

使用四捨五入的方式格式化一個浮點類型(默認保留一位小數,如果小數部分全爲0則只保留整數,可在其後指定保留位數)

<p>我是floatformat過濾器:{{ 123.456 | floatformat }}或{{ 123.456 | floatformat:2 }}</p>

length(獲取長度)

獲取長度(可以看成可迭代對象的迭代次數),和Python中的len()作用相同

<!--暱稱='尋覓', 列表=['one', '2', '三']-->
<p>我是length過濾器:暱稱-{{ 暱稱 | length }} | 列表-{{ 列表 | length }}</p>

lower(強制轉換爲小心)與upper(強制轉換爲大寫)

移除值中所以指定的字符串,類似於Python中的reqlace(args,’’)

<!--'大小寫轉換': "AaBb"-->
<p>我是lower與upper過濾器:強制小寫-{{ 大小寫轉換 | lower }} | 強制大寫-{{ 大小寫轉換 | upper }}</p>

safe(標記安全字符串)

Django會默認將傳入的值進行轉義,以防SQL注入攻擊,如果傳入字符被標記爲安全字符串,則Django不會再將其轉義。

<!--'js腳本': '<script>alert(document.domain)</script>'-->
<p>我是safe過濾器:此腳本是{{ js腳本 }},在刷新網頁時會執行{{ js腳本 | safe }}</p>

striptags(刪除標籤)

刪除值中所帶的HTML標籤

<!--'js腳本': '<script>alert(document.domain)</script>'-->
<p>我是striptags過濾器:{{ js腳本 | striptags }}</p>

truncatechars(指定長度)

指定長度後只能顯示指定長度的內容,如果超過指定內容,則會已省略號代替(比如說指定字符長度爲5,如果傳入的字符串大於等於5,那麼第5個字將會被省略號代替,之後的字符將會被省略)

<!--'js腳本': '<script>alert(document.domain)</script>'-->
<p>我是truncatechars過濾器:{{ js腳本 | truncatechars:10 }}</p>

在這裏插入圖片描述

模板優化

引入模板

一個站點中的有頁眉和頁尾,爲了避免重複性導入,我們可以寫一個模板,在其他頁面引入即可,這樣可以避免重複寫大量代碼的同時,也增強了代碼的可維護性,如果進行繼承,這裏就需要用到{% include 'HTML頁面' %}將父類引入即可。
如果需要傳參,可以通過with進行{% include 'HTML頁面' with 參數名='參數' %}

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>我就是一測試頁面</title>
</head>
<body>
    {% include 'header.html' %}
    <p>我真的就是一個測試頁面,不要過來啊</p>
    {% include 'footer.html' with 暱稱='xunmi' %}
<!--footer.html中的代碼爲: <p>我是尾部footer.html文件{{ 暱稱 }}</p>-->   
</body>
</html>

繼承模板

繼承和上述的引用想要達成的目的大致相同,都是爲了減少重複代碼而出現的,不過繼承比引入更加適用,模板中的繼承和Python的繼承有異曲同工之處,在父模板中定義一些子模板需要用到的代碼,然後子模板自己繼承即可

父模板使用方式

在HTML中可以預留<% block 填充名 %> <% endblock %>標註子模板需要填充的區域。
列如:

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>父模板頁面</title>
</head>
<body>
    <h1>我是父模板</h1>
    {% block 填充一 %}
    <p>這裏的代碼默認會被覆蓋</p>
    {% endblock %}
    <h2>上方是第一個子模板</h2>
    {% block 填充二 %}
    <p>這裏的代碼默認會被覆蓋</p>
    {% endblock %}
    <h3>上方是第二個子模板填充區</h3>
</body>
</html>

子模板使用方式

子模板需要先導入父模板,使用{% extends '父模板名.html' %} 即可導入父模板。 導入父模板後,同樣是使用<% block 填充名 %> <% endblock %>方法即可在父模板中預留的位置填充內容(填充的內容會覆蓋父模板中block區域中的內容,可以使用{{ block.super }}方法放在填充區中防止覆蓋),填充名除了可以在block中寫入,在endblock中也可以寫入,此功能在大項目中可以增強代碼的可讀性。
例如:

{% extends 'inherit.html' %}

{% block 填充一 %}
<p>我是在父模板的填充一區</p>
{% endblock %}

{% block 填充二 %}
    {{ block.super }}
    <p>我是獲得了填充二區內容的區域</p>
{% endblock 填充二 %}

引入靜態文件

一個網站中除了有HTML,一些靜態文件也是不可或缺的,比如css、js、圖片等。這些今天文件我們可以直接寫絕對路徑,或相對路徑來表示,但這種做法並不是明智的,如果一個靜態文件被多次引入,在其後修改時就會造成巨大的工程量,而且可能會出現漏改的情況。

settings.py文件設置

下方設置都在settings.py下完成:

  1. 確定是否在INSTALLED_APPS中安裝了'django.contrib.staticfiles',(高版本Django默認安裝)
  2. 確保已經指定STATIC_URL = '/static/'(static爲文件夾名,可以自定義,此設定在settings.py文件最下方,同樣在高版本Django會默認設置)
    確保有上述兩部,我們就可以正常使用靜態文件了,但是在使用過程會較爲麻煩,我們可以在進行接下來幾部操作進行優化:
  3. 當前設置我們只能APP目錄下的static文件夾中的內容,但有些靜態文件是公用的,我們可能想把它放入根目錄中,這時候就需要手動寫入(推薦放在settings.py最下方STATIC_URL = '/static/'之後,方便查看)
STATICFILES_DIRS = [
    os.path.join(BASE_DIR, 'static')
]
  1. 默認情況下,我們在HTML中每次使用靜態文件都需要在HTML中寫入{% load static %}引入靜態文件夾。比較麻煩,不過可以在設置中的TEMPLATES裏的OPTIONS屬性內添加'builtins': ['django.templatetags.static'],
    在這裏插入圖片描述
    操作完成上述步驟,我們使用{% static '靜態文件名' %}的方式即可引入文件

引入示例

我現在項目的APP與根目錄中的static文件夾中分別放入了一張圖片與一個css(其中設置背景顏色爲猛男色)
在這裏插入圖片描述

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <link rel="stylesheet" href="{% static 'css.css' %}">
</head>
<body>
    <img src="{% static '炮姐.png' %}" alt="" width="200">
</body>
</html>

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章