Django框架的基本使用 Django是一個功能強大的web框架 框架模式 1、MVC和MTV框架 MVC:Web伺服器開發領域里著名的MVC模式,所謂MVC就是把Web應用分為模型(M),控制器(C)和視圖(V)三層,結構說明如下: M: models 資料庫相關操作 V: views 視圖,也 ...
Django框架
Django是一個功能強大的web框架
前言:框架模式簡介
1、MVC和MTV框架
MVC:Web伺服器開發領域里著名的MVC模式,所謂MVC就是把Web應用分為模型(M),控制器(C)和視圖(V)三層,結構說明如下:
M: models 資料庫相關操作
V: views 視圖,也就是業務邏輯相關操作
C: controller 控制器,也就是通過路徑找到對應視圖函數
MTV:Django的MTV模式本質上和MVC是一樣的,也是為了各組件間保持松耦合關係,只是定義上有些許不同。
M: models 資料庫相關操作
T: templates html文件相關操作(模板渲染等)
V: views 視圖,也就是業務邏輯相關操作
加上一個url控制器,也就是通過路徑找到對應視圖函數
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(後面的應用名的首字母大寫)
- 註意
- 手動創建應用的時候要把應用指定給當前項目
- 在settings文件的
INSTALLED_APPS
的下麵- 方式一:應用名.apps.應用名Config(後面的應用名的首字母大寫)
- 方式二:應用名 ( 這是簡寫方式)
- 如若不指定應用,Django中的某些方法將無法使用
5、django項目的導入
請看博客:https://www.cnblogs.com/wylshkjj/p/11983596.html
6、windows中安裝不同版本的python解釋器
在python3.7及以上版本中,使用django框架的時候,django的版本要在2.0或以上,否則會出現問題;python3.6使用django的1.0版本。
當想即使用python3.7和python3.6針對django的不同版本進行創建項目時,python解釋器的安裝要註意,
解釋器安裝請參考博客:https://www.cnblogs.com/wylshkjj/p/13122349.html
二、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),
三、視圖
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="">百度</a>',}
渲染
<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="/xx1/">首頁</a>
<a href="/person/">個人中心</a>
<a href="/detail/">詳情頁</a>
</div>
<div class="left-menu">
<div class="menu">
<div class="menu-title">菜單1</div>
<div class="menu-body">
<div class="item">局部按摩</div>
<div class="item">全身按摩</div>
<div class="item">足底按摩</div>
<div class="item">頭部按摩</div>
</div>
<div class="menu-title">菜單2</div>
<div class="menu-body">
<div class="item">盲人按摩</div>
<div class="item">推背</div>
<div class="item">刮痧</div>
<div class="item">精油、火罐</div>
</div>
</div>
</div>
<div class="main">
{% block content %}
公共頁面
{% endblock %}
</div>
</body>
{% block js %}
{% endblock %}
</html>
(2)將來如果說繼承公用模板的html文件中需要修改公用模板中的一些內容,那麼需要在公用模板中預留一些鉤子,鉤子的寫法如下
{% block content %} #block 後面的塊名稱隨便起
公共頁面
{% endblock %}
#也可以這樣寫 {% endblock content %} #endblock指定名稱
(3)繼承公用模板需要在html文件中寫如下內容:
{% extends 'xx.html' %} <!-- 需要先繼承一下公用模板,寫法就是extends '公用模板文件名稱',註意,必須寫在第一行 -->
{% block css %}
.nav{
height: 60px;
background-color: pink;
}
{% endblock %}
{% block content %}
<h1>首頁</h1>
{% endblock %}
(4) 在使用公用模板的其他html文件中,如果需要更改公用模板裡面的內容,只需要在html文件中寫上相同的鉤子,鉤子裡面寫上自定義的內容,寫法如下
{% block css %}
.nav{
height: 60px;
background-color: pink;
}
{% endblock %}
{% block content %}
<h1>首頁</h1>
{% endblock %}
(5)註意事項:
-
如果你在模版中使用 {% extends %} 標簽,它必須是模版中的第一個標簽。其他的任何情況下,模版繼承都將無法工作,模板渲染的時候django都不知道你在幹啥。
-
在base模版中設置越多的
{% block %}
標簽越好。子模版不必定義全部父模版中的blocks,所以,可以在大多數blocks中填充合理的預設內容,然後,只定義你需要的那一個。多一點鉤子總比少一點好。 -
如果你發現你自己在大量的模版中複製內容,那可能意味著你應該把內容移動到父模版中的一個
{% block %}
中。 -
{{ block super }}的使用,在子模板中也展示出父模板原來鉤子中的內容
{% block content %} <h1>首頁</h1> {{ block.super }} {% endblock %}
-
為了更好的可讀性,你也可以給你的 {% endblock %} 標簽一個 名字 。例如:
{% block content %}
...
{% endblock content %}
在大型模版中,這個方法幫你清楚的看到哪一個 {% block %}
標簽被關閉了。
-
不能在一個模版中定義多個相同名字的
block
標簽。#兩個block都叫content,這種寫法是不對的 {% block content %} <h1>首頁</h1> {{ block.super }} {% endblock %} {% block content %} <h1>首頁</h1> {{ block.super }} {% endblock %}
6、要註意Template模板渲染實在瀏覽器解釋之前執行的,模板渲染後才輪到瀏覽器器來執行解釋
與safe處理效果相同的mark_safe方法,mark_safr方法需要導入模塊
- mark_safr的使用方法
- 導入模塊:from django.utils.safestring import mark_safe
- mark_safe(html代碼)
- safe的使用方法:
- 通過管道符safe:變數|safe
mark_safe與|safe的優缺點:
- mark_safe可直接返回大量的html標簽,可用於自定義標簽中,通過後端python代碼返回實現
- |safe每次只能解決一個變數的問題,在自定義標簽中不能使用,通過前端模板渲染實現
7、拓展:XSS攻擊(上面過濾|safe的拓展)
xss攻擊:,全稱跨站腳本攻擊
Django的模板中在進行模板渲染的時候會對HTML標簽和JS等語法標簽進行自動轉義,原因顯而易見,這樣是為了安全,django擔心這是用戶添加的數據,比如如果有人給你評論的時候寫了一段js代碼,這個評論一提交,js代碼就執行啦,這樣你是不是可以搞一些壞事兒了,寫個彈窗的死迴圈,瀏覽器就不能用了,瀏覽器會一直彈出彈窗,這叫做xss攻擊,所以瀏覽器中進行了一些轉義處理。但是有的時候我們需要這些HTML元素不被轉義,比如我們做一個內容管理系統,後臺添加的文章中是經過修飾的,這些修飾可能是通過一個類似於FCKeditor編輯加註了HTML修飾符的文本,如果自動轉義的話顯示的就是保護HTML標簽的源文件。為了在Django中關閉HTML的自動轉義有兩種方式,如果是一個單獨的變數我們可以通過過濾器“|safe”的方式告訴Django這段代碼是安全的不必轉義。
8、django的UTC格林威治時間的處理
在settings.py文件中,具體情況集體分析,主要修改settings配置文件的參數。
9、Template模板註意事項
在引入的javastript文件中使用模板渲染是不會生效的
Django對於html的Template渲染時是以字元串的形式先讀取所有的html文件中的內容,然後執行模板渲染,此實javascript的導入部位代碼還是字元串,文件還沒有被引入,當模板渲染結束後返回給瀏覽器的時候,瀏覽器解析時非同步執行javascript文件,而此時無法再進行模板渲染了,因為模板渲染是由後臺執行的。瀏覽器並不會,也沒有此功能。
若想在javascript中使用模板渲染,那就不能使用文件引入的方式,只能在html文件中寫javascript,併在裡面使用模板渲染規則
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True
10、組件與動態組件的應用
(1)組件
組件就是一個html文件,其中封裝了一些特定功能,比如就是一個導航欄,或者就是一個左側菜單,相當我們將一些特定功能封裝成了一個組件,將來任何其他html文件中如果使用這部分功能,可以直接引入使用。
在django模板渲染系統中使用組件的步驟
第一步:創建組件的html文件,名字隨便取,比如叫做zujian.html,比如內容如下,做一個頂部導航欄組件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>zujian</title>
<style>
.nav{
background-color: blue;
height: 100px;
}
.nav a{
color:white;
}
</style>
</head>
<body>
<div class="nav">
<a href="">百度</a>
<a href="">京東</a>
<a href="">個人中心</a>
</div>
</body>
</html>
第二步:使用組件,需要藉助下麵這個標簽語法
{% include '組件文件名稱.html' %}
示例:比如我們需要某個html文件中使用,比如show.html文件中使用,show.html文件內容如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!-- <style> -->
<!-- 可以修改樣式,但是註意權重問題 -->
<!-- .nav{
background-color: yellow!important;#}
}
-->
<!-- </style> -->
</head>
<body>
<h1>這是show頁面</h1>
<!-- include 'zujian.html' --> <!-- 在哪裡引入組件,組件就生成在頁面的對應位置上 -->
</body>
</html>
(2)動態組件的應用
註意:在settings中的INSTALLED_APPS配置當前app,不然django無法找到自定義的標簽
-
在app中創建templatetags文件夾(文件夾名只能是templatetags)
-
在templatetags文件夾中創建任意 .py 文件,如:mytag.py
-
在mytag.py文件中寫上如下內容
from django import template
register = template.Library() #製作註冊器,名字必須叫register
@register.inclusion_tag('zujian2.html')
def xiaolin(v1):
#v1 = [11,22,33]
return {'data': v1}
- 使用inclusion_tag,比如在show2.html文件中使用:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{% load mytag %}
{% xiaolin d %}
<h1>這是show2頁面</h1>
</body>
</html>
- 需要後臺給show2.html傳遞數據,比如views.py文件寫法如下
def show2(request):
d = ['國產', '歐美', '日韓']
return render(request,'show2.html',{'d': d})
五、靜態文件配置
Django的常用的三種靜態文件的配置方式
(1)settings配置引入靜態文件
-
在settings.py中配置
STATICFILES_DIRS = [ os.path.join(BASE_DIR, 'statics'), # statics為創建的靜態文件夾 ]
-
在前端文件導入的時候使用settings.py中的STATIC_URL = '/static/'的static路徑引入
<!-- html代碼 -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="/static/css/index.css">
</head>
<body>
<div class="c">hello world!</div>
</body>
</html>
<!-- inde.css代碼 -->
.c{
height: 100px;
width: 100px;
border: 1px solid black;
background-color: aqua;
color: aliceblue;
}
# settings中的配置
STATIC_URL = '/static/'
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'statics'),
]
(2)template渲染模式static引入靜態文件
- 通過模板渲染在html文件頭部引入{% load static %}
- 引入文件方式:<link rel="stylesheet" href="{% static "文件路徑" %}">
<!-- html代碼 -->
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="{% static "css/index.css" %}">
</head>
<body>
<div class="c">hello world!</div>
</body>
</html>
<!-- inde.css代碼 -->
.c{
height: 100px;
width: 100px;
border: 1px solid black;
background-color: aqua;
color: aliceblue;
}
(3)template渲染模式get_static_prefix引入靜態文件
- 通過模板渲染在html文件頭部引入{% load static %}
- 引入文件方式:<link rel="stylesheet" href="{% get_static_prefix %}文件路徑 ">
- 註:路徑和大括弧之間不能有空格, %}文件路徑,要無縫對接,否則無法引入文件
<!-- html代碼 -->
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="{% get_static_prefix %}css/index.css ">
</head>
<body>
<div class="c">hello world!</div>
</body>
</html>
<!-- inde.css代碼 -->
.c{
height: 100px;
width: 100px;
border: 1px solid black;
background-color: aqua;
color: aliceblue;
}
六、ORM(對象關係映射)
ORM全稱:object relational mapping ---- 對象 關係 映射
主要完成的就是資料庫操作。
- MVC或者MVC框架中包括一個重要的部分,就是ORM,它實現了數據模型與資料庫的解耦,即數據模型的設計不需要依賴於特定的資料庫,通過簡單的配置就可以輕鬆更換資料庫,這極大的減輕了開發人員的工作量,不需要面對因資料庫變更而導致的無效勞動
- ORM是“對象-關係-映射”的簡稱。(Object Relational Mapping,簡稱ORM)(將來會學一個sqlalchemy,是和他很像的,但是django的orm沒有獨立出來讓別人去使用,雖然功能比sqlalchemy更強大,但是別人用不了)
- 類對象--->sql--->pymysql--->mysql服務端--->磁碟,orm其實就是將類對象的語法翻譯成sql語句的一個引擎,明白orm是什麼了,剩下的就是怎麼使用orm,怎麼來寫類對象關係語句。
具體的東西後面跟新
七、資料庫的連接
這裡只講解兩種資料庫的連接模式:
-
Django自帶的sqlite3小型資料庫,實際應用不常用,多用於測試代碼時使用
-
mysql資料庫的連接操作
(1)sqlite3
Django預設自帶的資料庫,直接執行初始化創建資料庫即可
(2)mysql
mysql資料庫的連接需要配通過包來實現,在Java中叫連接池,不過python把這個封裝成了包,很多包都可以實現,對於django1.0版本通常使用pymysql模塊來實現連接,但是對於django2.0版本以上可能會出錯,這時也可以使用mysqlclient模塊來連接資料庫,當然還有一些其它連接資料庫的模塊。
這裡主要介紹pymysql的連接方法
-
下載好pymysql模塊後
-
在項目主目錄的__init__.py中指定
import pymysql pymysql.install_as_MySQLdb()
-
settings文件中的
DATABASES
裡面配置資料庫的連接信息DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', # 資料庫類型 'NAME': 'drawer', # 資料庫名 'USER': 'root', # 用戶名 'PASSWORD': '1234', # 密碼 'HOST': 'localhost', # ip 'PORT': '3306', # 埠 'OPTIONS': { "init_command": "SET sql_mode='STRICT_TRANS_TABLES'", } # 這個可以不寫 } }
-
註意:連接mysql資料庫的時候要現在mysql中創建好資料庫,不然連接時會報錯,因為djang無法自動創建資料庫
(3)初始化和執行資料庫
初始化命令:python manage.py makemigrations
執行操作命令:python manage.py migrate
(4)通過pycharm的圖形界面操作來操作資料庫
在pycharm的右邊框位置有個database在裡面可以創建sqlite和MySQL的連接實現對資料庫的操作
具體使用後面補充