Django框架
Django是一個功能強大的web框架,
博客中缺少知識流程解釋圖,后期我會一一補充回來,因為博客園插圖片比較麻煩,請諒解,
前言:框架模式簡介
1、MVC和MTV框架模式:分層級進行管理
說到框架模式我們有必要簡單的說下設計模式,了解下設計模式這個概念,因為有人對設計模式和框架模式的概念經常混淆
設計模式:
是一套被反復使用,多數人知道并經過分類的代碼設計經驗總結,是為了解決一些通用性問題的
目的:重用代碼并保證代碼的可靠性
設計模式分類:單例,抽象工廠 等等 23種模式
一句話總結:解決某一些特殊問題的一種思想和思路
框架模式:
代碼重用,框架模式是解決如何設計程式框架的代碼,在框架模式中會包含多種設計模式,與設計模式是一種包含關系,
舉例來說:比如要蓋樓,那怎么蓋樓屬于框架模式,樓里面的電梯怎么設計,樓梯怎么設計,屬于設計模式,所以框架模式在
蓋樓中屬于如何把樓蓋起來,那么他里面會包含多種設計模式,具體的細節碰到不同的東西,會采用不同的設計模式來解決,
因此在一種框架模式中會包含多種設計模式,
目前流行的框架模式:
-
MVC(適用于多種編程語言,單在python中不常用):
Web服務器開發領域里著名的MVC模式,所謂MVC就是把Web應用分為模型(M),控制器(C)和視圖(V)三層
M:Models 模型層,在程式中用于處理資料邏輯的部分,(主要是處理資料),主要負責在資料庫中對資料的存取操作,其實就是對資料庫的增刪改查的操作 V:Views 視圖層 ,在應用程式中處理顯示部分的內容(html,jsp),也就是業務邏輯相關操作 C: Controllers 控制層 ,處理用戶互動的部分,主要作用于M和V之間做協調,通常是負責從模型層中抽取資料,再進行業務處理,最后將資料傳給視圖層,并將視圖傳給客戶端,(控制器,也就是通過路徑找到對應視圖函式) 詳解:用戶首先打開瀏覽器,輸入網址,然后瀏覽器向服務器發送請求,到了服務器之后,由控制層接收這個請求,接收完請求就知道用戶想要做什么,了解了用戶的意圖,如果需要用到一些資料,比如想查看某某商品的資訊,那么控制器就需要找到商品的資訊,所以控制器就找模型層了,模型層會根據資料庫創建模型(注意模型層不是資料庫)一般情況資料庫有多少張表,那么模型層就有多少個類,每個表中有多少個欄位,模型層中的類就有多少個變(屬性),在模型層里還會提供增刪改查的操作,那么這個執行結構再反饋給控制器,到此,控制層和模型層的互動完成了,接下來,控制層就會把接收到的資料發送給視圖,視圖會把資料顯示在網頁里,反饋給瀏覽器,這樣用戶就看到了
?
-
MTV(django)
Django的MTV模式本質上和MVC是一樣的,也是為了各組件間保持松耦合關系,只是定義上有些許不同,
M:模型層,功能同上,資料庫相關操作 T:templates:模板層,用于處理用戶顯示部分的內容,和MVC中的V是一樣的,通過html展示(模板渲染等) V:views 視圖層,在MTV中視圖層是處理用戶互動的部分,從模型層中獲取資料,再將資料交給模板層,再先是給用戶和MVC中的控制層用法一樣,也就是業務邏輯相關操作 加上一個url控制器,也就是通過路徑找到對應視圖函式 詳解:用戶打開瀏覽器,瀏覽器發送請求,視圖層接收用戶請求,接受完請求呼叫模型層,模型層根據資料庫創建模型,進行增刪改查等操作,模型層處理完資料回傳給視圖層,視圖層接收完資料呼叫模板層,模板層里存放HTML等頁面,模板層會把HTML模板頁面回傳給視圖層,視圖層填充資料到模板上,然后再回傳給瀏覽器
2、WSGI
WSGI(Web Server Gateway Interface)就是一種規范,它定義了web應用程式與web服務器程式之間的介面格式,實作web應用程式與web服務器程式間的解耦,
開發的專案分為兩個部分的程式
1 服務器程式 socket相關功能的模塊,wsgiref、uwsgi等等,負責接收網路請求并決議網路請求相關資料,分裝加工成一些可用的資料格式,格式大家都是統一的,方便應用程式的開發
2 應用程式 就是使用接收到的網路請求相關資料,進行邏輯代碼的開發,比如資料庫相關操作,資料結構的調整、檔案操作等等,,,
一、基本使用
1、下載的三種方式:
- 直接在pycharm中的setting中進行下載
- 在cmd中通過命令下載:pip install django==版本
- 在pycharm的Terminal控制臺中進行下載(下載時要注意路徑問題)
2、創建專案
(1)通過cmd或pycharm控制臺的命令創建專案
? 先切換到要創建專案的目錄下,然后執行創建專案命令:
django-admin startproject mysite # mysite是專案名稱
? 創建專案后會生成如下的目錄,當前目錄下會生成mysite的工程,里面有個主目錄和我們創建的專案目錄同名,在專案目錄下有個manage.py檔案,在主目錄下有settings.py\urls.py\wsgi.py,每個檔案的功能介紹如下:
manage.py ----- Django專案里面的工具,通過它可以呼叫django shell和資料庫,啟動關閉專案與專案互動等,不管你將框架分了幾個檔案,必然有一個啟動檔案,其實他們本身就是一個檔案,
settings.py ---- 包含了專案的默認設定,包括資料庫資訊,除錯標志以及其他一些作業的變數,
urls.py ----- 負責把URL模式映射到應用程式,
wsgi.py ---- runserver命令就使用wsgiref模塊做簡單的web server,后面會看到renserver命令,所有與socket相關的內容都在這個檔案里面了,目前不需要關注它,
? 一個django專案中可以有多個應用,每個應用完成專案的部分功能,這些功能相對于其他功能來說是相對獨立的,但又同時存在于同一個專案中,每個應用的邏輯資料庫等也都是相對獨立的,每個應用都有屬于自己的模塊單位;開發的時候,都是通過應用來寫邏輯
(2)通過pycharm創建django專案
-
點擊File --》New Project 選擇第二項 Django
-
在Location中選擇選專案創建的地址和專案名
-
Project Interpreter:
Project Interpreter中的Newenvironment using是創建專案執行的虛擬環境
Project Interpreter中的Existing interpreter是使用本地的環境,也可以使用已創建好的虛擬環境
-
More Settings
Template language:模板引擎;默認是Django的Template模板引擎
如若下載jinja2模板引擎可進行切換,或者其他模板引擎
注:django中的模板引擎未單獨封裝成模塊;jinja2是模仿的的django的Template
Templates folder:存放html檔案的檔案夾名
Application name:是創建的應用的應用名
-
create創建完成后執行即可,通過控制臺顯示的鏈接即可訪問
3、運行專案
啟動專案命令:
python manage.py runserver 127.0.0.1:8080
ip和port可以不用寫,不寫時默認是 127.0.0.1:8000
運行成功后,會看到一個專案鏈接,在瀏覽器中輸入此鏈接即可訪問到創建的專案
4、創建應用Application
(1)創建專案時直接通過Application name創建應用
(2)pycharm中手動創建應用
- cmd或pycharm控制器Terminal中創建應用
要在專案目錄下執行命令進行創建應用
python manage.py startapp 應用名
經常用到的三個檔案
models.py 資料庫相關內容
views.py 視圖,業務邏輯代碼相關內容
tests.py 用來寫一些測驗代碼,用來測驗我們自己寫的視圖的,目前用不到
-
手動創建檔案夾(也可復制其它應用的檔案,要注意修改配置)
- 創建應用檔案夾(滑鼠右鍵使用python package創建)
- 在settings.py中找到
INSTALLED_APPS在其下面添加應用的配置資訊 - 應用名.apps.應用名Config(后面的應用名的首字母大寫)
-
最后一點可能需要配置一下template的路徑
-
在settings.py中找到
TEMPLATES在其下面的'DIRS':[]中添加os.path.join(BASE_DIR, 'templates') -
結果顯示: 'DIRS': [os.path.join(BASE_DIR, 'templates')],
-
-
注意
- 手動創建應用的時候要把應用指定給當前專案
- 在settings檔案的
INSTALLED_APPS的下面- 方式一:應用名.apps.應用名Config(后面的應用名的首字母大寫)
- 方式二:應用名 ( 這是簡寫方式)
- 如若不指定應用,Django中的某些方法將無法使用
5、django專案的匯入
請看博客:django專案匯入
6、windows中安裝不同版本的python解釋器
在python3.7及以上版本中,使用django框架的時候,django的版本要在2.0或以上,否則會出現問題;python3.6使用django的1.0版本,
當想即使用python3.7和python3.6針對django的不同版本進行創建專案時,python解釋器的安裝要注意,
解釋器安裝請參考博客:windows中安裝不同版本的python解釋器
二、url路由系統
? 在django中,url中的路徑寫法是正則,正則里面有無名分組正則,有有名分組正則,那么對應django中的功能,我們稱之為無名分組路由和有名分組路由
? 在django的1.0版本中路由組態檔urls.py中使用的是url(),里面可以直接使用正則匹配路徑的方式
? 而在django的2.0版本中路由組態檔urls.py中使用的是path(),里面不能直接使用正則匹配路徑,如需使用正則路徑進行匹配就要使用re_path(),使用前要先匯入
1、無命名分組路由
看寫法,urls.py檔案中內容如下
urlpatterns = [
...
url(r'^books/(\d+)/(\d+)/', views.book),
#正則里面()分組正則,會將分組中的正則匹配到的內容作為回傳值回傳
]
簡單分析,偽代碼
'''
當用戶請求的路徑是它: /books/2019/8/
url(r'^books/(\d+)/(\d+)/', views.book), 里面做的事情如下
re.match(^books/(\d+)/,/books/2019/)
2019 和 8 作為位置引數交給了要執行的book視圖函式
視圖函式book的寫法
def book(request,xx,oo):
xx = 2019
oo = 8
pass
'''
視圖views.py檔案中函式的寫法
#位置傳參,url中正則^books/(\d+)/(\d+)/,那么第一個()分組匹配到的資料,作為book函式的第二個引數,第二個()分組匹配到的資料,作為book的第三個引數
def book(request, year, month):
print('year', year, 'month', month) #year 2020
# return HttpResponse('%s所有書籍' % year)
return HttpResponse('%s年%s月所有書籍' % (year, month))
使用url路由系統時需要注意幾個點
1. urlpatterns中的元素按照書寫順序從上往下逐一匹配正則運算式,一旦匹配成功則不再繼續,
2. 若要從URL中捕獲一個值,只需要在它周圍放置一對圓括號(正則分組匹配),
3. 不需要添加一個前導的反斜杠(也就是寫在正則最前面的那個/),因為每個URL 都有,例如,應該是^articles 而不是 ^/articles,
4. 每個正則運算式前面的'r' 是可選的但是建議加上,
5. ^articles$ 以什么結尾,以什么開頭,嚴格限制路徑
2、有名分組路由
其實就玩得正則的有名分組,看示例
Urls.py檔案中的寫法
urlpatterns = [
url(r'^admin/', admin.site.urls),
# /books/2020/6/
url(r'^books/(?P<year>\d+)/(?P<month>\d+)/', views.book),
# {'year':2020,'month':6},url類將有名分組正則匹配出來的資料,交給了book視圖函式作為關鍵字引數來使用]
View.py檔案中函式的寫法如下
# ^books/(?P<year>\d+)/(?P<month>\d+)/
#獲取到url中的有名分組正則匹配到的資料,那么函式形參名稱必須和有名分組正則的那個名稱相同才可以,也就是按照上面的url來看的話,函式的形參必須是year和month這兩個名稱,并且關鍵字傳參不需要考慮函式形參的位置
def book(request, month, year):
# print('year', year, 'month', month) #year 2020
print(request.path) #/books/2020/6/
# return HttpResponse('%s所有書籍' % year)
return HttpResponse('%s年%s月所有書籍' % (year, month))
3、路徑中的尾部斜杠問題
當用戶通過瀏覽器訪問django框架完整的專案中的某個路徑時,如果用戶在輸入網址路徑的最后,沒有加上/斜杠,比如http://127.0.0.1:8000/test,那么django會發將用戶輸入的網址路徑加上一個后置的/,也就會將路徑變成這樣http://127.0.0.1:8000/test/,然后給瀏覽器發送一個重定向的回應操作,狀態碼為301,那么瀏覽器拿到這個重定向操作之后,就會自動發起一個這樣的路徑請求http://127.0.0.1:8000/test/,所以當我們打開瀏覽器控制臺的network功能查看請求程序時,會看到兩個請求,一個沒有后置的斜杠的,一個是有后置斜杠的,第二個請求才會走到我們的urs.py檔案中的路徑配合和分發對應視圖的地方,
我們可以通過一個配置項,告訴django,不要自動加路徑后面的斜杠了,但是需要注意的就是你自己寫的url中的正則,也別加后面的斜杠,不然正則匹配不到,
配置項直接寫在settings組態檔中,任意位置
APPEND_SLASH = False #False表示告訴Django,不加路徑后面的斜杠,默認值是True
5、視圖函式中指定默認值
views.py檔案:
# 在路由沒有匹配任何引數的時候,num使用自己的默認值
# 當路由中有分組匹配資料的動作,比如url(r'^test/(\d+)/', views.test),用戶輸入網址:http://127.0.0.1:8000/test/22/,那么22就被匹配到了,會作為引數傳給我們的test函式,那么num的值就變成了22
def test(request, num=10):
print('number>>>',num)
return HttpResponse('test')
urls.py檔案
# url(r'^test/', views.test),
url(r'^test/(\d+)/', views.test),
6、url反向決議
? 由于將來專案中的不同功能對應的url路徑可能會發生變化,所以我們在每個url路徑上加上一個別名,將來通過別名反向決議來使用這個別名對應的路徑,那么不管路徑將來發生什么變化,只要別名不變,那么邏輯中使用這個路徑的地方,都可以通過別名獲取到
(1)url別名用法
urlpatterns = [
...
url(r'^add_book/', views.add_book, name='add_book'), #name屬性對應的值,就是這個路徑的別名
]
(2)views視圖中使用url反向決議的方式
# 首先在視圖中引入反向決議的方法
from django.urls import reverse #url別名反向決議,通過name別名對應的資料,決議出我們的url路徑
1 針對沒有引數的別名 url(r'^add_book/', views.add_book, name='add_book'),
反向決議:reverse('book_list')
2 針對含有無名分組的url:url(r'^book_list/v2/(\d+)/(\d+)/', views.book_list, name='book_list'),
反向決議:reverse('book_list',args=(11,22))
3 針對含有有名分組的url:url(r'^book_list/v2/(?P<year>\d+)/(?P<month>\d+)/', views.book_list, name='book_list'),
反向決議:reverse('book_list',kwargs={'year':2022,'month':11})
(3)html檔案中使用url別名反向決議
- 無引數:{% url 'add_book' %}
- 有引數:{% url 'add_book' 2020 12 %}
針對無引數的路徑:url(r'^add_book/', views.add_book, name='add_book'),
反向決議:<a href=https://www.cnblogs.com/wylshkjj/p/"{% url'add_book'%}" class="btn btn-primary">添加書籍</a>
這對有引數的路徑:url(r'^add_book/(\d+)/(\d+)/', views.add_book, name='add_book'),
url(r'^add_book/(?P<year>\d+)/(?P<month>\d+)/', views.add_book, name='add_book'),
反向決議: <a href=https://www.cnblogs.com/wylshkjj/p/"{% url'add_book' 2020 12 %}" class="btn btn-primary">添加書籍</a>
7、路由分發和命名空間 namespace
1 創建app
python manage.py startapp app02
2 配置app,在settings.py檔案中
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'app01.apps.App01Config',
'app02'
]
路由分發步驟
1 在專案主目錄下的urls.py(以后我們稱之為總路由)檔案中,寫上如下內容
from django.conf.urls import url, include
from django.contrib import admin
# 路由分發功能
urlpatterns = [
url(r'^admin/', admin.site.urls),
# /app01/index/ -- 去掉/app01/ -- index/拿到app01應用下面的urls.py檔案中進行路徑匹配
url(r'^app01/', include('app01.urls')),
# 當訪問路徑是以/app01/開頭的,那么django主目錄下面的urls.py檔案會自動幫我們去找app01下面的urls.py檔案進行路徑匹配
url(r'^app02/', include('app02.urls')), #include引數格式 '應用名稱.urls'
]
2 在每個應用檔案夾下面創建一個叫做urls.py的檔案,里面寫上如下內容
from django.conf.urls import url, include
from app01 import views
# 路由分發功能
urlpatterns = [
#' index/'
# 寫上自己應用中的每個路徑對應的函式
url(r'^index/', views.index),
]
出現一個問題,當兩個應用中的某個url的別名相同了,那么使用url反向決議的時候,發現都是決議出來的都是最后一個應用的對應路徑,這叫做別名沖突,
看示例:
app01下的urls.py
from django.conf.urls import url, include
from app01 import views
# 路由分發功能
urlpatterns = [
url(r'^index/', views.index),
url(r'^home/', views.home, name='home'),
]
App02下的urls.py
from django.conf.urls import url, include
from app02 import views
# 路由分發功能
urlpatterns = [
url(r'^index/', views.index),
url(r'^home/', views.home, name='home'),
]
App01的views.py檔案中進行別名發現決議,代碼:
def index(request):
print('app01>>>',reverse('home'))
#app01>>> /app02/home/
return HttpResponse('app01-index')
App02的views.py檔案中進行別名發現決議,代碼:
def index(request):
print('app02>>>',reverse('home'))
#app02>>> /app02/home/
return HttpResponse('app02-index')
發現別名沖突,導致反向決議出錯了,
解決方法,命名空間
示例:總路由寫法
from django.conf.urls import url, include
from django.contrib import admin
# 路由分發功能
urlpatterns = [
url(r'^admin/', admin.site.urls),
# 路由分發時,給每個應用的路由進行了空間劃分,使用namespace
url(r'^app01/', include('app01.urls', namespace='app01')),
url(r'^app02/', include('app02.urls', namespace='app02')),
]
views.py檔案寫法
def index(request):
# 在進行反向決議時,需要用到命名空間:別名,來進行決議
print('app02>>>',reverse('app02:home'))
# app02>>> /app02/home/
return HttpResponse('app02-index')
三、視圖
1、request的物件
常用的屬性和方法
print(request) # wsgirequest物件
print(request.path) # 請求路徑 #/index/
print(request.method) # 請求方法
print(request.POST) # post請求提交的資料 <QueryDict: {'username': ['root']}>
print(request.GET) # 獲取url中的查詢引數 <QueryDict: {'a': ['1'], 'b': ['2']}> #不是針對get請求的
print(request.body) #獲取http請求訊息格式的請求資料部分的內容 b''
print(request.META) #請求頭資訊
print(request.get_full_path()) # 獲取完整路徑(包含查詢引數的) /index/?a=1&b=3
print(request.FILES) # 上傳的檔案物件資料
print(request.FILES.get('file')) # 上傳的檔案名
#<QueryDict: {'username': ['root'], 'sex': ['female'], 'hobby': ['2', '3']}>
print(request.POST.get('username')) # 前端中傳輸的username的值
print(request.POST.get('sex')) # 前端中單選傳輸的sex值
# 多選提交來的資料通過getlist來獲取
print(request.POST.getlist('hobby')) # ['2', '3']
2、response的回應
(1)常用方法
from django.shortcuts import render, HttpResponse, redirect
return HttpResponse('你好') #回復字串
return render(request,'home.html') #回復html頁面
#重定向方法,引數是個路徑
return redirect('/home/') #封裝了302狀態碼,以及瀏覽器要重定向的路徑
(2)添加回應頭鍵值對
ret = render(request,'home.html')
ret['a'] = 'b' #添加回應頭鍵值對
return ret
(3)添加回應狀態碼
ret = render(request,'home.html', status=202) #render修改狀態碼還可以這樣改
#ret['a'] = 'b' #添加回應頭鍵值對
ret.status_code = 201 #添加回應狀態碼
return ret #回復html頁面
3、CBV和FBV
兩種視圖邏輯的寫法方法
FBV:全稱function based view,就是基于函式來寫視圖邏輯
CBV:全稱class based view,就是基于類來寫視圖
基于類的視圖CBV寫法,如下,views.py檔案
from django.views import View
#登錄需求
class LoginView(View):
# get請求 獲取login頁面
def get(self,request):
return render(request,'login.html')
# post請求,獲取post請求提交的資料,并校驗等等
def post(self,request):
print(request.POST)
#<QueryDict: {'uname': ['chao'], 'pwd': ['123']}>
return render(request,'login.html')
url路徑的寫法:urls.py檔案
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^index/', views.index),
url(r'^home/', views.home),
# 類視圖的url寫法
url(r'^login/', views.LoginView.as_view()),
]
4、cbv原始碼重點(反射)
from django.views import View
View里面的dispatch方法中的反射邏輯,實作了不同的請求方法,找到我們視圖類中的對應方法執行
5、FBV和CBV加裝飾器
FBV和普通函式加裝飾器方式一樣
示例:
#裝飾器函式
def outer(f):
def inner(request, *args ,**kwargs):
print('前面')
ret = f(request, *args ,**kwargs)
print('后面')
return ret
return inner
#使用裝飾器
@outer
def books(request):
print('FBV執行了')
return HttpResponse('book.html--ok')
CBV加裝飾器
#裝飾器函式
def outer(f):
def inner(request, *args ,**kwargs):
print('前面')
ret = f(request, *args ,**kwargs)
print('后面')
return ret
return inner
#使用裝飾器
#1 引入django提供的裝飾器方法method_decorator來配合裝飾器函式的使用
from django.utils.decorators import method_decorator
@method_decorator(outer,name='get') #CBV加裝飾器方式3
class BookView(View):
#給類方法統一加裝飾器,借助dispatch方法(父類的dispatch方法,就是通過反射來完成不同的請求方法找到并執行我們自己定義的視圖類的對應方法)
# 重寫dispatch方法,dispatch方法是在其他請求方法對應的類方法執行之前執行的
# @method_decorator(outer) #加裝飾器方式2
def dispatch(self, request, *args, **kwargs):
# print('xxxxxx')
ret = super().dispatch(request, *args, **kwargs)
# print('oooooo')
return ret
#CBV加裝飾器的方式1,給單獨的方法加裝飾器
# @method_decorator(outer)
def get(self, request, xx):
print('CBV的get方法')
return render(request, 'book.html')
# @method_decorator(outer)
def post(self,request, xx):
print('CBV的post方法')
return HttpResponse('ok')
四、Template模板
1、Template的基本使用
(1)通過{{ 變數 }}:獲取單個變數值
(2)通過{% 邏輯 %}:獲取邏輯渲染結果
2、變數的使用
Number資料型別,容器資料型別和物件都可以直接進行渲染
(1)回傳前端頁面的資料格式
-
在return回傳的時候可以直接寫入引數,區別在于html中渲染的時候直接通過元素直接獲取(使用原引數沒有作用),容器資料型別才有效,number型別無效
return render(request, "index.html", info)
-
在return回傳的時候也可以使用字典的方式,使用字典時,就是直接通過字典的鍵來進行相應的操作
return render(request, "index.html", {'info': info})
(2)句點號的使用:
? 在字典資料型別中需要使用句點號和索引搭配才能獲取到相應的值
? 同理物件的方法和屬性的呼叫也是通過句點號,而且要注意呼叫方法不能加()
# views.py
from django.shortcuts import render
import datetime
# Create your views here.
class obj():
pass
def index(request):
pdd = '1234'
info = {
'name': '旋風奧利奧',
'age': '18',
'hobby': "girl",
'dict': {'drink': '飲品', 'milk': '牛奶'},
'list': ['面包', '包子'],
'object': obj(),
'size': 123456,
'time': datetime.datetime.now()
}
return render(request, "index.html", info)
# return render(request, "index.html", {'info': info})
# html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h3>{{ name }}</h3>
<p>{{ dict }}</p>
<p>{{ list }}</p>
<p>{{ pdd }}</p>
<hr>
{% for foo in list %}
<p>{{ foo }}</p>
{% endfor %}
<hr>
{% for k,v in dict.items %}
<p>{{ k }} : {{ v }}</p>
{% endfor %}
<hr>
{{ object.obk }}
</body>
</html>
# url.py
from app01 import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^index/', views.index)
]
3、Template過濾器
- 通過過濾器對資料進行過濾處理顯示
- 使用方式:{{ 變數|過濾器:引數 }}
- 過濾器支持鏈式操作,通過多個管道符和過濾器相配合實作層級過濾
- 過濾器可以接收引數
- 注意事項:管道符左右兩遍不能留空格,否則不能識別;還有引數和:間也不能留空格;
3.1、內置過濾器
(1)default:默認值
? 當變數獲取的到值的時候顯示獲取的值,獲取不到值或者獲取的是一個布爾型別的False時就使用默認的default值:{{ value|default:"沒有值"}}
(2)length:長度
? 回傳的是字串或串列的長度:{{ value|length }}
(3)filesizeformat:檔案大小的顯示處理
? 將值格式化為一個 “人類可讀的” 檔案尺寸 (例如 13 KB, 4.1 MB, 102 bytes, 等等),
(4)slice:切片:{{ value|slice:"2:-1" }}
(5)date:時間顯示處理
? 對獲取的時間進行過濾處理:{{ value|date:"Y-m-d H:i:s"}}
(6)safe:宣告此變數值(或代碼段)不轉義
{'a_tag':'<a href=https://www.cnblogs.com/wylshkjj/p/"">百度',}
渲染
<p>
{{ a_tag|safe }} #生成標簽效果
</p>
(7)truncatechars:指定字串長度,超出部分以 ... 顯示
{{ value|truncatechars:9}}:指定九個字符長度,也包括 ... 這三個字符
(8)truncatewords:以單詞的形式指定字串長度,超出部分以 ... 顯示
? {{ value|truncatewords:3}}:指三個單詞長度,不包括 ... 部分
(9)cut:過濾字串
? {{ value|cut:' ' }}:過濾掉value變數中和引數中的空格相同的字符
(10)join:字串拼接
? {{ hobby|join:'+' }}:把串列資料通過加號拼接成一個字串
3.2、自定義過濾器
- 在應用檔案夾中創建一個名為templatetags的檔案夾(檔案夾的名字必須是templatetags)
- 在templatetags檔案夾中創建任意 .py 檔案,如:mytag.py
- 在mytag.py檔案中寫上如下內容
from django import template
register = template.Library() # 制作注冊器,名字必須叫register
#過濾最多兩個引數
@register.filter # 注冊過濾器,需要兩個引數的
def add(v1, v2): # v1表示管道符前面的,v2表示冒號后面的引數
print(v1,v2) # 100 50
return v1 + v2
@register.filter # 注冊過濾器,需要一個引數的
def xxx(v1): # v1表示管道符前面的
print(v1)
return 'xxx'
- 在html檔案中匯入
{% load mytag %} <!-- 首先通過load來加載一下mytag檔案,不一定放在檔案的開頭,但是一定要放在使用過濾器的前面先進行參考 -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>base頁面</h1>
<!-- {% load mytag %} 放這里也是可以的 -->
<div>
{{ num|add:50}} <!-- 使用過濾器,和django內置過濾器用法一樣,這里生成的是add函式的回傳值 -->
</div>
<div>
{{ num|xxx }}
</div>
<!-- {% load mytag %} 放這里不行 -->
</body>
</html>
4、Template標簽
? 使用方式:{% 標簽 %} {%end標簽%}
4.1、內置標簽
(1)for 回圈標簽
? {% for xx in hobby %}{% endfor %}
forloop的使用
? 注:回圈序號可以通過{{forloop}}顯示,必須在回圈內部用
-
forloop.counter 當前回圈的索引值(從1開始),forloop是回圈器,通過點來使用功能
-
forloop.counter0 當前回圈的索引值(從0開始)
-
forloop.revcounter 當前回圈的倒序索引值(從1開始)
-
forloop.revcounter0 當前回圈的倒序索引值(從0開始)
-
forloop.first 當前回圈是不是第一次回圈(布林值)
-
forloop.last 當前回圈是不是最后一次回圈(布林值)
-
forloop.parentloop 本層回圈的外層回圈的物件,再通過上面的幾個屬性來顯示外層回圈的計數等
for回圈的反向回圈:
? 可以利用{% for obj in list reversed %}反向完成回圈,
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{% for i in dict %}
<p>{{ i }}</p>
{% endfor %}
<hr>
{% for i in dict.values %}
<p>{{ i }}</p>
{% endfor %}
<hr>
{% for k,v in dict.items %}
<p>{{ k }} : {{ v }}</p>
{% endfor %}
<hr>
{% for foo in list %}
<p>{{ forloop }} : {{ foo }}</p>
{% endfor %}
<hr>
{% for foo in list %}
<p>{{ forloop.counter }} : {{ foo }}</p>
{% endfor %}
<hr>
{% for foo in list %}
<p>{{ forloop.counter0 }} : {{ foo }}</p>
{% endfor %}
<hr>
{% for foo in list %}
<p>{{ forloop.revcounter }} : {{ foo }}</p>
{% endfor %}
<hr>
{% for foo in list %}
<p>{{ forloop.revcounter0 }} : {{ foo }}</p>
{% endfor %}
<hr>
{% for foo in list %}
<p>{{ forloop.first }} : {{ foo }}</p>
{% endfor %}
<hr>
{% for foo in list %}
<p>{{ forloop.last }} : {{ foo }}</p>
{% endfor %}
<hr>
{% for foo in list %}
{% for foo in list %}
<p>{{ forloop.parentloop.counter }} : {{ forloop.revcounter0 }} : {{ foo }}</p>
{% endfor %}
{% endfor %}
<hr>
# 反向回圈串列
{% for foo in list reversed %}
<p>{{ foo }}</p>
{% endfor %}
</body>
</html>
(2)if 判斷標簽
? {% if 判斷條件 %}{% endif %}
- if陳述句支持 and 、or、==、>、<、!=、<=、>=、in、not in、is、is not判斷,注意條件兩邊都有空格,
- 但是不支持連續判斷操作:{% if a > b > c %}{% endif %}
- {% if %}會對一個變數求值,如果它的值是“True”(存在、不為空、且不是boolean型別的false值),對應的內容塊會輸出,
{% if num > 100 or num < 0 %}
<p>無效</p> <!--不滿足條件,不會生成這個標簽-->
{% elif num > 80 and num < 100 %}
<p>優秀</p>
{% else %} <!--也是在if標簽結構里面的-->
<p>炊訓吧</p>
{% endif %}
?
(3)with 起別名標簽
? 使用一個簡單地名字快取一個復雜的變數,多用于給一個復雜的變數起別名,當你需要使用一個“昂貴的”方法(比如訪問資料庫)很多次的時候是非常有用的;注意:等號左右不要加空格,
方式一:
{% with total=business.employees.count %}
{{ total }} <!--只能在with陳述句體內用-->
{% endwith %}
方式二:
{% with business.employees.count as total %}
{{ total }}
{% endwith %}
(4)for empty聯合使用的情況
? 當回圈的hobby沒有資料或為空的時候,就顯示empty下面的內容
<ul>
{% for xx in hobby %}
<li>{{ xx }}</li>
{% empty %}
<h2>抱歉,沒有查詢到相關資料</h2>
{% endfor %}
</ul>
(5)Django的模板語言中屬性的優先級大于方法
? 處理的字典資料中不要出現以方法名為鍵的鍵值對,因為默認會獲取該鍵值對資料,而不是走方法去處理資料,導致得不到想要的資料結果,
def xx(request):
d = {"a": 1, "b": 2, "c": 3, "items": "100"}
return render(request, "xx.html", {"data": d})
? 如上,我們在使用render方法渲染一個頁面的時候,傳的字典d有一個key是items并且還有默認的 d.items() 方法,此時在模板語言中:{{ data.items }}
? 默認會取d的items key的值,
4.2、自定義標簽
- 在應用檔案夾中創建一個名為templatetags的檔案夾(檔案夾的名字必須是templatetags)
- 在templatetags檔案夾中創建任意 .py 檔案,如:mytag.py
- 在mytag.py檔案中寫上如下內容
from django import template
register = template.Library() # 制作注冊器,名字必須叫register
@register.simple_tag
def atag(v1,v2): # 沒有引數個數限制
print(v1,v2)
return v1 + v2
- 在html檔案中匯入
{% load mytag %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>base頁面</h1>
{% load mytag %}
<div>
{% atag a b %} <!-- 注意,是{%%} 來包裹使用,先是標簽名稱然后空格寫引數,引數之間也是空格分隔的 -->
</div>
</body>
</html>
5、Templete模板繼承
將一些頁面公共的部分,可以抽離出來單獨做成一個html頁面,使用這些公用部分的其他html檔案,只需要繼承一下它就可以了,具體使用流程如下:
(1) 創建公用模板,比如內容如下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
body{
padding: 0;
margin: 0;
}
{% block css %}
.nav{
height: 60px;
background-color: green;
}
{% endblock %}
.nav a{
color:white;
text-decoration: none;
}
.left-menu{
width: 30%;
background-color: rgba(0,0,0,0.5);
float:left;
}
.menu .menu-title{
text-align: center;
}
.main{
float: right;
width: 65%;
height: 300px;
border: 1px solid red;
}
</style>
</head>
<body>
<div class="nav">
<a href=https://www.cnblogs.com/wylshkjj/p/"/xx1/">首頁
個人中心
詳情頁
