陳擎文教學網:python後台網頁Django
python資源
官網 python官網 vscode官網    
python 教學網站 w3c school(中文版) w3c school(英文版)    
線上執行python online

https://repl.it/languages/python3

https://www.onlinegdb.com/online_python_compiler

https://www.tutorialspoint.com/execute_python_online.php

其它資源
  上課程式碼即時貼網站 線上黑板( Online blackboard) 上課即時貼(guestBook) 4月30日範例 有道翻譯
  考試題目 考試題目(Exam) 畢業門檻(Graduation threshold) 2018通識課規定 DWCS3
  Goole 輸入法(Input software) Goole輸入法(Input:exe) Goole 輸入法(Input:zip) online goole input(中文) online goole input(英文)
  Windows+Apache
+MySQL+PHP整合安裝系統
phpstudy2014 phpstudy2018 XAMPP wampserver
  免費的網頁編輯軟體 微軟的vs code(visual studio code)      
 

 
chp1.Django的簡介、安裝、簡單練習

下載

下載本章project成果
2.常用pip指令 3.建立一個django專案 4.建立第一個應用程式App 5.環境設定(settings.py) 6. MTV架構
exp01_01:用MTV架構,在網頁顯示文字 exp01_02:網址傳遞參數 exp01_03:網址傳遞第二個變數 exp01_04:回傳計算變數到模板指定網頁 exp01_05:顯示圖片

python下載點

python官網

vscode下載點

vscode官網

1.簡介:

Django是一個開源的Python基於web開發而設計的應用框架,基於MVC的設計思想,大大簡化了網站開發的難度,
能夠簡單快速的開發網站。其中封裝的大量函式和方法,可以直接呼叫,同時擴充套件性非常好,可以擴充套件第三方外掛。
框架的主要三部分M(模型)V(檢視)T(模板)是基於MVC的思想在Django內的結構,其中V接受瀏覽器的資訊傳遞給M把資料存進資料庫,還可以接受M的返回結果讓T產生一個HTML頁面,Django的特點是大而全,內嵌了ORM框架,通過檔案遷移建立類和表的對應關係,操作資料庫不需要寫sql語句,而是通過類和物件對資料表操作,

Django是目前Python開發網站最常用的後端框架。
2.常用 pip 指令 (1).查詢目前python安裝了那些套件或模組
指令:pip list

(2).卸除已經安裝的模組套件
pip uninstall 套件名稱

(3).安裝一個模組套件(例如:django)
pip install django

(4).更新安裝一個模組套件(例如:django)
pip install --upgrade 套件名稱
pip install --upgrade django
3.建立一個django專案 建立目錄: md py_django
進入目錄: cd py_django

建立一個django專案語法:django-admin startproject 專案名稱
例如:django-admin startproject pj01

結果:發現已經建立一個pj01目錄
(1).manage.py (python命令檔,提供專案管理的功能)
(2).子目錄:pj01(裡面有4個檔案)
__init__.py (一個空檔)
settings.py (設定檔)
urls.py (url配置檔)
wsgi.py (網頁伺服器的界面設定檔)
4.建立第一個應用程式application(App)

(1).一個專案project可以有很多的App
要先到pj01目錄: cd pj01
語法:python manage.py startapp 應用程式名稱
例如:python manage.py startapp app01
結果:
產出一個app01目錄
裡面有6個檔案

(2).建立templates目錄
方法:md templates
功能:是模板,可以顯示*.html

(3).建立static目錄
方法:md static
功能:存放圖片檔,CSS,javascript檔案的地方

(4).目前在pj01目錄下面有4個平行目錄
pj01
app01
templates
static

(5).建立migration資料檔
功能:若使用資料庫,可以建立資料表的架構與版本記錄,好處是未來可以追踪
語法:python manage.py makemigrations (app名稱)
例如:python manage.py makemigrations
若是沒有指定app01,就會對所有的app來記錄,建議不指定名稱

(6).將模型與資料庫同步
語法:python manage.py migrate (app名稱)
例如:python manage.py migrate
若是沒有指定app01,就會對所有的app來記錄,建議不指定名稱
☎注意:不要指定app名稱,否則無法讀取資料表

結果:
會產生一個資料庫:db.sqlite3

(7).啟動server
語法:python manage.py runserver
結果:
手動開啟一個網頁,輸入:http://127.0.0.1:8000/
結果顯示:
The install worked successfully! Congratulations!

(8).關閉server
輸入指令:ctrl+C,即可停止執行模式狀態
5.環境設定(settings.py (1).除錯模式:line 26
DEBUG = true

(2).加入Application應用程式:line 40
'app01',

(3).設定templates的存放目錄:line 58
'DIRS': [os.path.join(BASE_DIR,'templates')],

(4).設定語系及時區:line 107,109
設定為繁體中文
LANGUAGE_CODE = 'zh-hant'

設定為台北時區
TIME_ZONE = 'Asia/Taipei'

(5).設定static靜態檔的路徑:line 122
#static靜態檔 = 此目錄可以存放圖形檔,CSS,或javascript檔案
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'static'),
]
6. MTV架構 (1).Django採用MTV架構,把網頁的執行與顯示,分成3個部分:model, template,view),類似ASP.NET的MVC架構。
M:模型Model
T:模板Template
V:視圖View

運作方法:
(A).在Template目錄,放置顯示的樣板網頁*.html
(B).在views.py定義執行的函式function
在views.py取得資料庫的資料,使用render函式的方式,傳遞給template模板*.html顯示
(C).在模型Model存取函數庫

流程圖:
資料庫 ➔ Model模型存取資料庫 ➔ View函式 ➔ 模板template網頁html

(2).MVC架構(ASP.NET)
M:模型Model
V:視圖View
C:控制Controller
(3).☎範例:exp01_01.py #目的:使用MTV架構,在網頁顯示:你好,歡迎光臨
(A).建立應用程式(App): app02
例如:python manage.py startapp app02

(A).在views.py先寫一個傳回文字的函式
☎重點:如何在網頁輸出一段文字:HttpResponse(文字)
例如:
from django.http import HttpResponse
return HttpResponse('你好,歡迎光臨')

程式碼:
from django.http import HttpResponse
def sayhi(request):
return HttpResponse('你好,歡迎光臨')

(B).在urls.py設定views.py裡面的函式與執行網址的對應關係
在urls.py裡面:
from django.conf.urls import url
from app01.views import sayhi1
urlpatterns = [
path('admin/', admin.site.urls),
url(r'^$',sayhi1)
]

(C).測試瀏覽網頁:127.0.0.1:8000


(D).若是出現錯誤訊息:UnicodeError:'utf-8' codec can't decode
原因:網頁有中文字,若是你是用筆記本note寫程式,存檔的格式要選utf8(不可以選ANSI)
(2).☎範例:exp01_02.py #目的:網址傳遞參數,http://127.0.0.1:8000/birthday,顯示你好,生日快樂
http://127.0.0.1:8000/newyear,顯示你好,新年快樂
(A).在views.py先寫一個傳回文字的函式

from django.http import HttpResponse
def sayhi2(request):
return HttpResponse('你好,生日快樂')
def sayhi3(request):
return HttpResponse('你好,新年快樂')

(B).在urls.py設定views.py裡面的函式與執行網址的對應關係
urls.py裡面:
from django.conf.urls import url
from app01.views import sayhi1,sayhi2,sayhi3
urlpatterns = [
path('admin/', admin.site.urls),
url(r'^$',sayhi1),
url(r'^birthday/$',sayhi2),
url(r'^newyear/$',sayhi3),
]

(C).測試瀏覽網頁:
127.0.0.1:8000/birthday
127.0.0.1:8000/newyear


(3).☎範例:exp01_03.py #目的:網址傳遞第二個變數,http://127.0.0.1:8000/birthday/張三,顯示你好,生日快樂
http://127.0.0.1:8000/newyear/張三,顯示張三你好,新年快樂
(A).在views.py先寫一個傳回文字的函式

from django.http import HttpResponse
def sayhi2(request):
return HttpResponse('你好,生日快樂')
def sayhi3(request):
return HttpResponse('你好,新年快樂')
def sayhi4(request,myname):
return HttpResponse(myname + '你好,生日快樂')
def sayhi5(request,myname):
return HttpResponse(myname + '你好,新年快樂')

(B).在urls.py設定views.py裡面的函式與執行網址的對應關係
urls.py裡面:
from django.conf.urls import url
from app01.views import sayhi1,sayhi2,sayhi3,sayhi4,sayhi5
urlpatterns = [
path('admin/', admin.site.urls),
url(r'^$',sayhi1),
url(r'^birthday/$',sayhi2),
url(r'^newyear/$',sayhi3),
url(r'^birthday/(\w+)/$',sayhi4),
url(r'^newyear/(\w+)/$',sayhi5)
]

(C).測試瀏覽網頁:
127.0.0.1:8000/birthday/李四
127.0.0.1:8000/newyear/王五


(3).☎範例:exp01_04.py #☎目的:回傳計算變數到模板指定網頁sayhi05.html
http://127.0.0.1:8000/newyear/張三,顯示:今天日期是,2019年9月26日,張三你好,新年快樂
#☎將所有views.py的變數都傳到模板templates(sayhi6.html)的方法:
return render(request,'模板網頁',locals())
#☎範例:
from django.shortcuts import render
def sayhi6(request,myname):
return render(request,'sayhi6.html',locals())
#☎locals():代表傳遞所有的區域變數

(A).修改settings.py環境設定
40行:新的app名稱
'app01',

58行:設定templates目錄位置
'DIRS': [os.path.join(BASE_DIR,'templates')],

107行:設定繁體中文,台北語區
LANGUAGE_CODE = 'zh-Hant'
TIME_ZONE = 'Asia/Taipei'

(B).在views.py先寫一個傳回文字的函式
from django.shortcuts import render
from django.http import HttpResponse
from datetime import datetime
def sayhi6(request, myname):
now = datetime.today()
return render(request,'sayhi6.html',locals())

(C).在urls.py設定views.py裡面的函式與執行網址的對應關係
urls.py裡面:
from django.conf.urls import url
from app01.views import sayhi1,sayhi2,sayhi3,sayhi4,sayhi5,sayhi6
urlpatterns = [
path('admin/', admin.site.urls),
url(r'^$',sayhi1),
url(r'^birthday/$',sayhi2),
url(r'^newyear/$',sayhi3),
url(r'^birthday/(\w+)/$',sayhi4),
url(r'^newyear/(\w+)/$',sayhi5),
url(r'^now/(\w+)/$',sayhi6),
]
(D).模板templates:sayhi6.html
#☎在模板template顯示變數的方法:{{變數}}
<HTML>
<HEAD>
<TITLE>sayhi6</TITLE>
<META content="text/html; charset=utf-8" http-equiv=Content-Type>
</HEAD>
<BODY>
<h1>{{myname}}你好,新年快樂</h1>
<h2>現在日期時間:{{now}}</h2>
</BODY>
</HTML>

(E).測試瀏覽網頁:
http://127.0.0.1:8000/now/王五

(4).☎範例:exp01_05.py #☎目的:接上面範例,再顯示圖片icon01.png
#☎觀念:django把圖片,css,javascript放在static目錄
#☎將所有views.py的變數都傳到模板templates(sayhi6.html)的方法:
return render(request,'模板網頁',locals())

(A).建立static目錄,在建立images目錄
複製貼上圖片:

(B).修改settings.py環境設定
122行:設定static的目錄
STATICFILES_DIRS = [
os.path.join(BASE_DIR,'static'),
]

(C).模板templates:sayhi6.html
#☎載入staticfiles的目錄設定:{% load staticfiles %}
#☎顯示圖片檔案:src="{% static 'images/icon01.png' %}"

<HTML>
<HEAD>
<TITLE>sayhi6</TITLE>
{% load staticfiles %}
<META content="text/html; charset=utf-8" http-equiv=Content-Type>
</HEAD>
<BODY>
<h1><img src="{% static 'images/icon01.png' %}">{{myname}}你好,新年快樂</h1>
<h2>現在日期時間:{{now}}</h2>
</BODY>
</HTML>

(D).測試瀏覽網頁:
http://127.0.0.1:8000/now/王五

 
chp2.視圖View與模板templates

下載

下載本章project成果
目錄 MTV架構 在視圖View如何傳遞變數到Templates模板 exp02_01顯示丟骰子的數字 宣告全域變數global
exp02_02.py顯示玩家姓名,年紀 Templates語法:變數 Templates語法:if Templates語法:for exp02_03.py傳遞串列到模板
exp02_04.py:for:forloop exp02_05.py:for:forloop參數revcounter Templates語法:變數的過濾器:| exp02_06.py過濾器 Html標籤處理指令

1. MTV架構

1. MTV架構
(1).Django採用MTV架構,把網頁的執行與顯示,分成3個部分:model, template,view),類似ASP.NET的MVC架構。
M:模型Model
T:模板Template
V:視圖View

運作方法:
(A).在Template目錄,放置顯示的樣板網頁*.html
(B).在views.py定義執行的函式function
在views.py取得資料庫的資料,使用render函式的方式,傳遞給template模板*.html顯示
(C).在模型Model存取函數庫

流程圖:
資料庫 ➔ Model模型存取資料庫 ➔ View函式 ➔ 模板template網頁html

2.在視圖View如何傳遞變數到Templates模板

2.在視圖View如何傳遞變數到Templates模板
(1).使用render語法:
from django.shortcuts import render
render(request, 模板名稱, 字典)

☎字典:
例如1:所有的區域變數 = locals()
例如1:指定單一字典變數 = {'num':9001}
例如1:{'name':'tom','age':25}

☎在模板templates容易顯示字典變數dict1:
(正確){{name}}
(錯誤){{dict1.name}}

☎例如:
from django.shortcuts import render
def sayhi6(request, myname):
return render(request,'sayhi6.html',locals())

範例:exp02_01.py

(2).☎範例:exp02_01.py
☎#目的:顯示丟骰子的數字
☎前置作業
_(A).關閉vscode ,然後再開啟vscode
_(B).建立專案
django-admin startproject pj02
_(C).建立應用程式app
python manage.py startapp app01
_(D).修改settings.py
40行:新的app名稱
'app01',

58行:設定templates目錄位置
'DIRS': [os.path.join(BASE_DIR,'templates')],

107行:設定繁體中文,台北語區
LANGUAGE_CODE = 'zh-Hant'
TIME_ZONE = 'Asia/Taipei'

122行:設定static的目錄
STATICFILES_DIRS = [
os.path.join(BASE_DIR,'static'),
]
_(E).到目前專案目錄
cd pj02
_(F).執行本專案程式
python manage.py startapp app01

_(G).修改函式(視圖views.py
☎傳遞字典: = {'num':num}
from django.shortcuts import render
import random
def dice1(request):
num = random.randint(1,6)
#return render(request, 'dice1.html',locals())
return render(request, 'dice1.html',{'num':num})
_(H).修改(urls.py
from django.conf.urls import url
from app01.views import dice1
urlpatterns = [
path('admin/', admin.site.urls),
url(r'^dice1/$', dice1),
]

_(I).修改模板(templates/dice1.html
<HTML>
<HEAD>
<TITLE>丟骰子</TITLE>
<META content="text/html; charset=utf-8" http-equiv=Content-Type>
</HEAD>
<BODY>
<h1>骰子點數 = {{num}}</h1>
</BODY>
</HTML>

_(J).測試結果:http://127.0.0.1:8000/dice1/
骰子點數 = 1

3.宣告全域變數global

3.如何宣告全域變數(global),如何傳遞全域變數
(1).如何宣告全域變數:
語法:global 變數

(2).如何傳遞全域變數:
local()參數無法傳遞全域變數。
解決方法:區域變數 = 全域變數

(3).注意:網站不要用全域變數global1
原因:因為在個人主機雖然正常,但在專業主機如heroku,全域變數會亂變,跳來跳去,
解決方法:所以還是要用session變數,數據才穩

(4).如何傳遞字典型別的變數
例如:
a1 = {"name":"tom","age":25}

如何在模板*.html要如何顯示姓名,年紀
姓名 = {{a1.name}}
年紀 = {{a1.age}}
☎注意:在模板的字典變數,不是使用傳統的方式:a1['name']

範例:exp02_02.py顯示玩家姓名,年紀..

(5).範例:exp02_02.py
#目的:顯示玩家姓名,年紀,骰子數字,累計次數times
#全域變數 = times

#views.py
times = 0
def dice2(request):
global times
stu = {"name":"張三","age":25}
num = random.randint(1,6)
times = times +1
local_times = times
return render(request, 'dice2.html',locals())

#urls.py
urlpatterns = [
path('admin/', admin.site.urls),
url(r'^dice1/$', dice1),
url(r'^dice2/$', dice2)
]

#dice2.html
<HTML>
<HEAD>
<TITLE>丟骰子</TITLE>
<META content="text/html; charset=utf-8" http-equiv=Content-Type>
</HEAD>
<BODY>
<h1>姓名 = {{stu.name}},年紀 = {{stu.age}}</h1>
<h2>骰子點數 = {{num}}</h2>
<h2>累計次數 = {{local_times}}</h2>
</BODY>
</HTML>

(6).測試結果:http://127.0.0.1:8000/dice2/
姓名 = 張三,年紀 = 25
骰子點數 = 6
累計次數 = 18

4.Templates語法:變數

4.Templates語法:變數語法:
(1).字典dict變數用法:
python語法:dict1[name]
templates語法:{{dict1.name}}

(2).串列list變數用法:
python語法:list1[0]
templates語法:{{list1.0}}

(3).物件變數的屬性用法:
python語法:obj1.name
templates語法:{{obj.name}}

(4).物件變數的方法用法:
python語法:obj1.show()
templates語法:{{obj1.show}}

(5).違反的變數名稱(會出現錯誤):
class,del

5.Templates語法:if

5.Templates語法:if語法:
☎注意:明顯與python的語法不同

(1).單向選擇
{% if a >= b %}
...
...
{% endif %}

(2).雙向選擇
{% if a >= b %}
...
{% else %}
...
{% endif %}

(3).多向選擇
{% if a >= 60 %}
...
{% elif a>=70 %}
...
{% elif a>=80 %}
...
{% endif %}

6.Templates語法:for

6.Templates語法:for語法:
☎注意:明顯與python的語法不同
(1).for迴圈語法:
{% for 變數item in 串列 %)
...讀取串列資料(item)
(% empty %}
...若是沒有串列資料(空串列)的處理方法
{% endfor %}

(2).for-反轉迴圈語法:(reversed )
{% for 變數item in 串列 reversed %)
...讀取串列資料(item)
(% empty %}
...若是沒有串列資料(空串列)的處理方法
{% endfor %}

(3).for迴圈的forloop參數:
forloop屬性
forloop.counter = forloop的計數器,由1開始遞增到迭代總數
forloop.counter0 = forloop的計數器,由0開始遞增到迭代總數減1
forloop.revcounter = forloop的倒數器,由迭代總數遞減到1
forloop.revcounter0 = forloop的倒數器,由迭代總數減1遞減到0
forloop.first = 真假值,若是第一次for迴圈,此值為真,否則為假
forloop.last = 真假值,若是最後一次for迴圈,此值為真,否則為假
forloop.parentloop = 父迴圈(上一層迴圈)的forloop變量

<範例:exp02_03.py傳遞串列到模板

☎(2).範例:exp02_03.py
#目的:練習傳遞串列到模板(顯示本班三位同學的聯絡資料)
#views.py
def stu3(request):
man1 = {"name":"張三","tel":"0945789456","age":20}
man2 = {"name":"李四","tel":"0922786656","age":19}
man3 = {"name":"王五","tel":"0911774156","age":21} man = [man1,man2,man3]
return render(request, 'stu3.html', locals())

#urls.py
from app01.views import dice1,dice2,stu3
urlpatterns = [
path('admin/', admin.site.urls),
url(r'^dice1/$', dice1),
url(r'^dice2/$', dice2),
url(r'^stu3/$',stu3),
]

#stu3.html
<HTML>
<HEAD>
<TITLE>顯示學生資料</TITLE>
<META content="text/html; charset=utf-8" http-equiv=Content-Type>
</HEAD>
<BODY>
{% for item in man %}
<h1>姓名 = {{item.name}}</h1>
<h2>手機 = {{item.tel}},年紀 = {{item.age}}</h2>
{% empty %}
<h2>沒有任何資料</h2>
{% endfor %}
</BODY>
</HTML>

#測試結果:http://127.0.0.1:8000/stu3/
姓名 = 張三
手機 = 0945789456,年紀 = 20
姓名 = 李四
手機 = 0922786656,年紀 = 19
姓名 = 王五
手機 = 0911774156,年紀 = 21

.範例:exp02_04.py:for:forloop

☎(4).範例:exp02_04.py
#目的:練習for:forloop參數(顯示本班第n位同學的聯絡資料)
#重點:第 {{ forloop.counter }} 位學生資料
#views.py
def stu4(request):
man1 = {"name":"張三","tel":"0945789456","age":20}
man2 = {"name":"李四","tel":"0922786656","age":19}
man3 = {"name":"王五","tel":"0911774156","age":21}
man = [man1,man2,man3]
return render(request, 'stu4.html', locals())

#urls.py
from app01.views import dice1,dice2,stu3,stu4
urlpatterns = [
path('admin/', admin.site.urls),
url(r'^dice1/$', dice1),
url(r'^dice2/$', dice2),
url(r'^stu3/$',stu3),
url(r'^stu4/$',stu4),
]

#stu4.html
<HTML>
<HEAD>
<TITLE>顯示學生資料</TITLE>
<META content="text/html; charset=utf-8" http-equiv=Content-Type>
</HEAD>
<BODY>
{% for item in man %}
<h1>第 {{ forloop.counter }} 位學生資料:</h1>
<h2>姓名 = {{item.name}},手機 = {{item.tel}},年紀 = {{item.age}}</h2>
{% empty %}
<h2>沒有任何資料</h2>
{% endfor %}
</BODY>
</HTML>

#測試結果:http://127.0.0.1:8000/stu4/
第 1 位學生資料:
姓名 = 張三,手機 = 0945789456,年紀 = 20
第 2 位學生資料:
姓名 = 李四,手機 = 0922786656,年紀 = 19
第 3 位學生資料:
姓名 = 王五,手機 = 0911774156,年紀 = 21

範例:exp02_05.py:for:forloop參數revcounter

☎(5).範例:exp02_05.py
#目的:練習for:forloop參數revcounter(反轉顯示本班第n位同學的聯絡資料)
#重點:{% for item in man reversed %}
<h1>第 {{ forloop.revcounter }} 位學生資料 </h1>
#views.py
def stu5(request):
man1 = {"name":"張三","tel":"0945789456","age":20}
man2 = {"name":"李四","tel":"0922786656","age":19}
man3 = {"name":"王五","tel":"0911774156","age":21}
man = [man1,man2,man3]
return render(request, 'stu5.html', locals())

#urls.py
from app01.views import dice1,dice2,stu3,stu4,stu5
urlpatterns = [
path('admin/', admin.site.urls),
url(r'^dice1/$', dice1),
url(r'^dice2/$', dice2),
url(r'^stu3/$',stu3),
url(r'^stu4/$',stu4),
url(r'^stu5/$',stu5),
]

#stu5.html
<HTML>
<HEAD>
<TITLE>顯示學生資料</TITLE>
<META content="text/html; charset=utf-8" http-equiv=Content-Type>
</HEAD>
<BODY>
{% for item in man reversed %}
<h1>第 {{ forloop.revcounter }} 位學生資料:</h1>
<h2>姓名 = {{item.name}},手機 = {{item.tel}},年紀 = {{item.age}}</h2>
{% empty %}
<h2>沒有任何資料</h2>
{% endfor %}
</BODY>
</HTML>

#測試結果:http://127.0.0.1:8000/stu5/
第 3 位學生資料:
姓名 = 王五,手機 = 0911774156,年紀 = 21
第 2 位學生資料:
姓名 = 李四,手機 = 0922786656,年紀 = 19
第 1 位學生資料:
姓名 = 張三,手機 = 0945789456,年紀 = 20

7.Templates語法:變數的過濾器:|

7.Templates語法:變數的過濾器:|(pipe)
7-1.各種指令語法:
過濾器:|(pipe)= 篩檢程式
1.可以通過篩檢程式來修改變數的顯示,
篩檢程式的形式是:{{ variable | filter }},
管道符號'|'代表使用篩檢程式
2.篩檢程式能夠採用鏈式的方式使用,
例如:{{ text | escape | linebreaks }}
3.篩檢程式還可以帶參數,
例如: {{ bio|truncatewords:30 }}
4.篩檢程式的參數中如果帶有空格,那麼需要用引號引起來,
例如:{{ list | join : ", "}}
5.django中30個內建的篩檢程式

(1)add
使用形式為:{{ value | add: "2"}}
意義:將value的值增加2
{{ 123|add:"5" }} 給value加上一個數值

(2)addslashes
使用形式為:{{ value | addslashes }}
意義:在value中的引號前增加反斜線
{{ "AB'CD"|addslashes }} 單引號加上轉義號,一般用於輸出到javascript中

(3)capfirst
使用形式為:{{ value | capfirst }}
意義:value的第一個字元轉化成大寫形式
{{ "abcd"|capfirst }} 第一個字母大寫

(4)cut
使用形式為:{{ value | cut:arg}}, 例如,如果value是“String with spaces” arg是" "那麼輸出是"Stringwithspaces"
意義:從給定value中刪除所有arg的值
{{ "123spam456spam789"|cut:"spam" }} 查找刪除指定字串

(5)date
使用形式為::
(a) {{ value | date:"D d M Y" }},例如,如果value是一個datetime物件(datetime.datetime.now())那麼輸出將是字串"Wed 09 Jan 2008"
(b) {{ value | date }},這種形式沒有格式化字串,這時候,格式化字串會自動採用DATE_FORMAT所設置的形式。
意義:將日期格式資料按照給定的格式輸出
例如:格式化:{{ pub_date | date:"F j, Y" }}

(6)default
使用形式:{{ value | default: "nothing" }},例如,如果value是“”,那麼輸出將是nothing
意義:如果value的意義是False,那麼輸出使用缺省值
{{ value|default:"(N/A)" }} 值不存在,使用指定值

(7)default_if_none
使用形式:{{ value | default_if_none:"nothing" }},例如,如果value是None,那麼輸出將是nothing
意義:如果value是None,那麼輸出將使用缺省值
{{ value|default_if_none:"(N/A)" }} 值是None,使用指定值

(8)dictsort
意義:如果value的值是一個字典,那麼返回值是按照關鍵字排序的結果
{{ 清單變數|dictsort:"數字" }} 排序從小到大
使用形式:{{ value | dictsort:"name"}},
例如,
如果value是:
[
{‘name’: ‘zed’, ‘age’: 19},
{‘name’: ‘amy’, ‘age’: 22},
{‘name’: ‘joe’, ‘age’: 31},
]
那麼,輸出是:
[
{‘name’: ‘amy’, ‘age’: 22},
{‘name’: ‘joe’, ‘age’: 31},
{‘name’: ‘zed’, ‘age’: 19},
]

(9)dictsortreversed
意義:如果value的值是一個字典,那麼返回值是按照關鍵字排序的結果的反序
使用形式:與上述(8)完全相同。
{{ 清單變數|dictsortreversed:"數字" }} 排序從大到小

(10)divisibleby
使用形式:{{ value | divisibleby:arg}},如果value是21,arg是3,那麼輸出將是True
意義:如果value能夠被arg整除,那麼返回值將是True
{% if 92|pisibleby:"2" %} 判斷是否整除指定數字

(11)escape
使用形式:{{ value | escape}}
意義:替換value中的某些字元,以適應HTML格式,包括:
< is converted to <
> is converted to >
’ (single quote) is converted to '
” (double quote) is converted to "
& is converted to &
{{ string|escape }} 轉換為html實體

escape僅僅在輸出的時候才起作用,所以escape不能夠用在鏈式篩檢程式的中間,
他應該總是最後一個篩檢程式,如果想在鏈式篩檢程式的中間使用,那麼可以使用force_escape

(12)escapejs
使用形式:{{ value | escapejs }}
意義:替換value中的某些字元,以適應JAVASCRIPT和JSON格式。

(13)filesizeformat
使用形式:{{ value | filesizeformat }}
意義:格式化value,使其成為易讀的檔大小,例如:13KB,4.1MB等。
{{ 21984124|filesizeformat }} 以1024為基數,計算最大值,保留1位小數,增加可讀性

(14)first
使用形式:{{ value | first }}
意義:返回列表中的第一個Item,例如,如果value是列表[‘a’,’b’,’c’],那麼輸出將是’a’。
{{ list|first }} 返回清單第一個元素

(15)floatformat
使用形式:{{ value | floatformat}}或者{{value|floatformat:arg}},
arg可以是正數也可以是負數。沒有參數的floatformat相當於floatformat:-1
(1)如果不帶arg,那麼引擎會四捨五入,同時最多只保留一位小數。
{{ 13.414121241|floatformat }} 保留1位小數,可為負數,幾種形式
{{ 13.414121241|floatformat:"2" }} 保留2位小數

34.23234 {{ value|floatformat }} 34.2
34.00000 {{ value|floatformat }} 34
34.26000 {{ value|floatformat }} 34.3

(2)如果arg是正數,那麼引擎會四捨五入,同時保留arg位的小數。

34.23234 {{ value|floatformat:3 }} 34.232
34.00000 {{ value|floatformat:3 }} 34.000
34.26000 {{ value|floatformat:3 }} 34.260

(3)如果arg是負數,那麼引擎會四捨五入,如果有小數部分,那麼保留arg位元小數;否則,則沒有任何小數部分。

34.23234 {{ value|floatformat:”-3” }} 34.232
34.00000 {{ value|floatformat:”-3” }} 34
34.26000 {{ value|floatformat:”-3” }} 34.26

(16)get_digit
使用形式:{{ value | get_digit:”arg”}},例如,如果value是123456789,arg是2,那麼輸出是8
意義:給定一個數位,返回,請求的數字,記住:1代表最右邊的數字,如果value不是合法輸入,
那麼會返回所有原有值。
{{ 23456 |get_digit:"1" }} 從個位數開始截取指定位置的1個數字

(17)iriencode
使用形式:{{value | iriencode}}
意義:如果value中有非ASCII字元,那麼將其進行抓化成URL中適合的編碼,如果value已經進行過URLENCODE,
改操作就不會再起作用。

(18)join
使用形式:{{ value | join:”arg”}},如果value是[‘a’,’b’,’c’],arg是’//’那麼輸出是a//b//c
意義:使用指定的字元串連接一個list,作用如同python的str.join(list)
{{ list|join:", " }} 用指定分隔符號號連接列表

(19)last
使用形式:{{ value | last }}
意義:返回列表中的最後一個Item

(20)length
使用形式:{{ value | length }}
意義:返回value的長度。
{{ list|length }} 返回列表個數

(21)length_is
使用形式:{{ value | length_is:”arg”}}
意義:返回True,如果value的長度等於arg的時候,例如:如果value是[‘a’,’b’,’c’],arg是3,那麼返回True
{% if 列表|length_is:"3" %} 列表個數是否指定數值

(22)linebreaks
使用形式:{{value|linebreaks}}
意義:value中的”\n”將被
替代,並且整個value使用

包圍起來,從而適和HTML的格式
{{ "ABCD"|linebreaks }} 用新行用

(23)linebreaksbr
使用形式:{{value |linebreaksbr}}
意義:value中的”\n”將被
替代
{{ "ABCD"|linebreaksbr }} 用新行用標記包裹

(24)linenumbers
使用形式:{{value | linenumbers}}
意義:顯示的文本,帶有行數。
{{ 變數|linenumbers }} 為變數中每一行加上行號

(25)ljust
使用形式:{{value | ljust}}
意義:在一個給定寬度的欄位中,左對齊顯示value
{{ "abcd"|ljust:"50" }} 把字串在指定寬度中對左,其它用空格填充

(26)center
使用形式:{{value | center}}
意義:在一個給定寬度的欄位中,中心對齊顯示value
{{ "abcd"|center:"50" }} 輸出指定長度的字串,並把值對中

(27)rjust
使用形式:{{value | rjust}}
意義:在一個給定寬度的欄位中,右對齊顯示value
{{ string|rjust:"50" }} 把字串在指定寬度中對右,其它用空格填充

(28)lower
使用形式:{{value | lower}}
意義:將一個字串轉換成小寫形式
{{ "ABCD"|lower }} 小寫

(29)make_list
使用形式:{{value | make_list}}
意義:將value轉換成一個list,對於字串,轉換成字元list;對於整數,轉換成整數list
例如value是Joel,那麼輸出將是[u’J’,u’o’,u’e’,u’l’];value是123,那麼輸出將是[1,2,3]
{% for i in "1abc1"|make_list %}ABCDE,{% endfor %} 把字串或數位的字元個數作為一個清單

(30)pluralize
使用形式:{{value | pluralize}},或者{{value | pluralize:”es”}},或者{{value | pluralize:”y,ies”}}
意義:如果value不是1,則返回一個複數尾碼,缺省的尾碼是’s’
{{ 清單或數位|pluralize }} 單詞的複數形式,如清單字串個數大於1,返回s,否則返回空串
{{ 清單或數字|pluralize:"es" }} 指定es
{{ 清單或數字|pluralize:"y,ies" }} 指定ies替換為y

(31)random
使用形式:{{value | random}}
意義:從給定的list中返回一個任意的Item
{{ 列表|random }} 返回列表的隨機一項

(32)removetags
使用形式:{{value | removetags:”tag1 tag2 tag3…”}}
意義:刪除value中tag1,tag2….的標籤。例如,如果value是Joel a slug
tags是”b span”,那麼輸出將是:Joel a slug
{{ string|removetags:"br p p" }} 刪除字串中指定html標記

(33)safe
使用形式:{{value | safe}}
意義:當系統設置autoescaping打開的時候,該篩檢程式使得輸出不進行escape轉換

(34)safeseq
與上述safe基本相同,但有一點不同的就是:safe是針對字串,而safeseq是針對多個字串組成的sequence

(35)slice
使用形式:{{some_list | slice:”:2”}}
意義:與python語法中的slice相同,:2表示第一的第二個元素
{{ 列表|slice:":2" }} 切片

(36)slugify
使用形式:{{value | slugify}}
意義:將value轉換成小寫形式,同事刪除所有分單詞字元,並將空格變成橫線
例如:如果value是Joel is a slug,那麼輸出將是joel-is-a-slug
{{ string|slugify }} 字串中留下減號和底線,其它符號刪除,空格用減號替換

(37)stringformat
這個不經常用,先不說
{{ value|stringformat:”E” }}
If value is 10, the output will be 1.000000E+01.
{{ 3|stringformat:"02i" }} 字串格式,使用Python的字串格式語法

(38)striptags
使用形式:{{value | striptags}}
意義:刪除value中的所有HTML標籤
{{ "EABCD"|striptags }} 剝去[X]HTML語法標記

(39)time
使用形式:{{value | time:”H:i”}}或者{{value | time}}
意義:格式化時間輸出,如果time後面沒有格式化參數,那麼輸出按照TIME_FORMAT中設置的進行。

{{ datetime|timesince }} 給定日期到現在過去了多少時間
{{ datetime|timesince:"other_datetime" }} 兩日期間過去了多少時間
{{ datetime|timeuntil }} 給定日期到現在過去了多少時間,與上面的區別在於2日期的前後位置。
{{ datetime|timeuntil:"other_datetime" }} 兩日期間過去了多少時間

(40)title
轉換一個字串成為title格式。
{{ 時間變數|time:"P" }} 日期的時間部分格式
{{ "abdsadf"|title }} 首字母大寫

(41)truncatechars
如果字串長度超過指定的字元數,則截斷該字串。截斷的字串將以可翻譯省略號字元(“…”)結尾。
論點: 要截斷到的字元數
例如::
{{ value|truncatechars:7 }}
如果 value 是 "Joel is a slug" ,輸出為 "Joel i…" .

(42)truncatechars_html
類似 truncatechars ,但它知道HTML標記。在字串中打開但在截斷點之前未關閉的所有標記在截斷後立即關閉。
例如::
{{ value|truncatechars_html:7 }}
如果 value 是 "

Joel is a slug

" ,輸出為 "

Joel i…

" .
將保留HTML內容中的分行符號。

(41)truncatewords
在一定數量的單詞後截斷字串。
論點: 後面要截斷的字數
例如::
{{ value|truncatewords:2 }}
如果 value 是 "Joel is a slug" ,輸出為 "Joel is …" .
將刪除字串中的分行符號。

(42)truncatewords_html
類似 truncatewords ,但它知道HTML標記。在字串中打開但在截斷點之前未關閉的所有標記在截斷之後立即關閉。
這比 truncatewords ,因此只能在傳遞HTML文本時使用。
例如::
{{ value|truncatewords_html:2 }}
如果 value 是 "

Joel is a slug

" ,輸出為 "

Joel is …

" .
將保留HTML內容中的分行符號。

(41)truncatewords
使用形式:{{value | truncatewords:2}}
意義:將value切成truncatewords指定的單詞數目
例如,如果value是Joel is a slug 那麼輸出將是:Joel is …
例如,顯示前30個字:{{ bio | truncatewords:"30" }}
{{ "A B C D E F"|truncatewords:"3" }} 截取指定個數的單詞

(42)truncatewords_html
使用形式同(41)
意義:truncation點之前如果某個標籤打開了,但是沒有關閉,那麼在truncation點會立即關閉。
因為這個操作的效率比truncatewords低,所有只有在value是html格式時,才考慮使用。
{{ "111221"|truncatewords_html:"2" }} 截取指定個數的html標記,並補完整

(43)upper
轉換一個字串為大寫形式
{{ string|upper }} 全部大寫

(44)urlencode
將一個字串進行URLEncode

(45)urlize
意義:將一個字串中的URL轉化成可點擊的形式。
使用形式:{{ value | urlize }}
例如,如果value是Check out www.djangoproject.com,那麼輸出將是:
Check out www.djangoproject.com
{{ string|urlize }} 將URLs由純文字變為可點擊的連結。


(46)urlizetrunc
使用形式:{{ value | urlizetrunc:15}}
意義:與(45)相同,但是有一點不同就是現實的連結字元會被truncate成特定的長度,後面以…現實。
{{ string|urlizetrunc:"30" }} 同上,多個截取字元數。

(47)wordcount
返回字串中單詞的數目
{{ "B C D E F"|wordcount }} 單詞數

(48)wordwrap
使用形式:{{value | wordwrap:5}}
意義:按照指定的長度包裝字串
例如,如果value是Joel is a slug,那麼輸出將會是:
Joel
is a
slug
{{ "a b c d e f g h i j k"|wordwrap:"5" }} 每指定數量的字元就插入回車符

(49)timesince
使用形式:{{value |since:arg}}
意義:返回參數arg到value的天數和小時數
例如,如果 blog_date 是一個日期實例表示 2006-06-01 午夜, 而 comment_date 是一個日期實例表示 2006-06-01 早上8點,
那麼 {{ comment_date|timesince:blog_date }} 將返回 “8 hours”.

(50)timeuntil
使用形式:{{value | timeuntil}}
意義:與(50)基本相同,一個不同點就是,返回的是value距離當前日期的天數和小時數。

(51)yesno
{{ boolean|yesno:"Yes,No,Perhaps" }} 對三種值的返回字串,對應是 非空,空,None。

範例:exp02_06.py過濾器

☎7-2:範例:exp02_06.py
#目的:練習過濾器
#重點:{% for item in man reversed %}
<h1>第 {{ forloop.revcounter }} 位學生資料 </h1>
#views.py
from datetime import datetime
def filter6(request):
str1 = "today is a good day"
str2 = "<p>how are you?</p>"
str3 = "how\nare\nyou?"
str4 = "taiwan?"
list1 = ['tom','jane','mike','john']
dict1 = [{'name':'tom','age':25},{'name':'brown','age':21},{'name':'mike','age':27}]
num1 = 7
date1 = datetime.now()
bool1 = num1>5
return render(request,'filter6.html',locals())

#urls.py
from app01.views import dice1,dice2,stu3,stu4,stu5,filter6
urlpatterns = [
path('admin/', admin.site.urls),
url(r'^dice1/$', dice1),
url(r'^dice2/$', dice2),
url(r'^stu3/$',stu3),
url(r'^stu4/$',stu4),
url(r'^stu5/$',stu5),
url(r'^filter6/$',filter6)

#filter6.html
<HTML>
<HEAD>
<TITLE>templates的過濾器filter</TITLE>
<META content="text/html; charset=utf-8" http-equiv=Content-Type>
</HEAD>
<BODY>
<h2>字串處理指令:</h2>
<p>第一個字開頭大寫capfirst = {{str1|capfirst}}</p>
<p>每個字開頭大寫title = {{str1|title}}</p>
<p>全部小寫lower = {{str1|lower}}</p>
<p>全部大寫upper = {{str1|upper}}</p>
<p>只顯示前面10個字...(truncatechars:10) = {{str1|truncatechars:10}}</p>
<p>計算幾個word字(wordcount) = {{str1|wordcount}}</p>
<p>輸出文字前顯示編號(linenumbers) = {{str1|linenumbers}}</p>
<p>空白處用-顯示(slugify) = {{str1|slugify}}</p>
<p>刪除字串裡面的子字串(cut:'is') = {{str1|cut:'is'}}</p>
<p>把字串轉成串列(make_list) = {{str4|make_list}}</p>

<h2>Html標籤處理指令:</h2>
<p>輸出html tag(escape) = {{str2|escape}}</p>
<p>刪除html tag(striptags) = {{str2|striptags}}</p>
<p>取得innerHtml(safe) = {{str2|safe}}</p>
<p>把\n換成<br/><p>(linebreaks) = {{str3|linebreaks}}</p>
<p>把\n換成<br/>(linebreaksbr) = {{str3|linebreaksbr}}</p>

<h2>串列處理指令:</h2>
<p>輸出串列第一個元素(first) = {{list1|first}}</p>
<p>輸出串列最後一個元素(last) = {{list1|last}}</p>
<p>輸出串列共幾個元素(length) = {{list1|length}}</p>
<p>判別串列元素是否為5個(length_is:5) = {{list1|length_is:5}}</p>
<p>輸出串列元素連接成一個字串(join:',') = {{list1|join:','}}</p>
<p>傳回串列的前幾個元素(slice:n) = {{list1|slice:3}}</p>
<p>以亂數輸出串列元素(random) = {{list1|random}}</p>

<h2>字典處理指令:</h2>
<p>以字典的年紀排序(dictsort:'age') = {{dict1|dictsort:'age'}}</p>
<p>以字典的年紀反向排序(dictsortreversed:'age') = {{dict1|dictsortreversed:'age'}}</p>

<h2>數字處理指令:</h2>
<p>加上數字5(add:5) = {{num1|add:5}}</p>
<p>數字以科學記號顯示(stringformat:'E') = {{num1|stringformat:'E'}}</p>

<h2>顯示日期格式處理指令:</h2>
<p>顯示今日日期:月 日(星期) 年(M d日(D) Y年) = {{date1|date:'M d日(D) Y年'}}</p>

<h2>boolean處理指令:</h2>
<p>7>5 是否為真(yesno:'是,否,取消') = {{bool1|yesno:'是,否,取消'}}</p>

</BODY>
</HTML>

#測試結果:http://127.0.0.1:8000/filter6/
字串處理指令:
第一個字開頭大寫capfirst = Today is a good day
每個字開頭大寫title = Today Is A Good Day
全部小寫lower = today is a good day
全部大寫upper = TODAY IS A GOOD DAY
只顯示前面10個字...(truncatechars:10) = today is …
計算幾個word字(wordcount) = 5
輸出文字前顯示編號(linenumbers) = 1. today is a good day
空白處用-顯示(slugify) = today-is-a-good-day
刪除字串裡面的子字串(cut:'is') = today a good day
把字串轉成串列(make_list) = ['t', 'a', 'i', 'w', 'a', 'n', '?']



Html標籤處理指令

Html標籤處理指令:
輸出html tag(escape) =

how are you?


刪除html tag(striptags) = how are you?
取得innerHtml(safe) =
how are you?
把\n換成<br/><p>(linebreaks) =
how
are
you?
把\n換成<br/>(linebreaksbr) = how
are
you?

串列處理指令:
輸出串列第一個元素(first) = tom
輸出串列最後一個元素(last) = john
輸出串列共幾個元素(length) = 4
判別串列元素是否為5個(length_is:5) = False
輸出串列元素連接成一個字串(join:',') = tom,jane,mike,john
傳回串列的前幾個元素(slice:n) = ['tom', 'jane', 'mike']
以亂數輸出串列元素(random) = john

字典處理指令:
以字典的年紀排序(dictsort:'age') = [{'name': 'brown', 'age': 21}, {'name': 'tom', 'age': 25}, {'name': 'mike', 'age': 27}]
以字典的年紀反向排序(dictsortreversed:'age') = [{'name': 'mike', 'age': 27}, {'name': 'tom', 'age': 25}, {'name': 'brown', 'age': 21}]
數字處理指令:
加上數字5(add:5) = 12
數字以科學記號顯示(stringformat:'E') = 7.000000E+00

顯示日期格式處理指令:
顯示今日日期:月 日(星期) 年(M d日(D) Y年) = 九月 28日(星期六) 2019年

boolean處理指令:
7>5 是否為真(yesno:'是,否,取消') = 是
 

 
chp3.模型model讀取資料庫
目錄 View如何傳遞變數到Templates exp03_01建立資料庫管理者的帳號密碼 exp03_02建立資料表類別student django 模型models 常用欄位
django 模型models 欄位常用參數 表單使用get傳遞變數三種方法 exp03_03在模板templates顯示一筆 exp03_04y在模板templates顯示全部 exp03_05網頁基礎模板base.htm

下載

下載本章project成果

在視圖View如何傳遞變數到Templates模板

1. MTV架構

2.在視圖View如何傳遞變數到Templates模板
(1).使用render語法:
from django.shortcuts import render
render(request, 模板名稱, 字典)

範例:exp03_01.py建立資料庫管理者的帳號密碼

(2).☎範例:exp03_01.py
☎#目的:建立資料庫管理者的帳號密碼
☎前置作業
_(A).關閉vscode ,然後再開啟vscode
_(B).建立專案
django-admin startproject pj03
_(C).建立應用程式app
python manage.py startapp app01
_(D).修改setting.py
40行:新的app名稱
'app01',

58行:設定templates目錄位置
'DIRS': [os.path.join(BASE_DIR,'templates')],

107行:設定繁體中文,台北語區
LANGUAGE_CODE = 'zh-Hant'
TIME_ZONE = 'Asia/Taipei'

122行:設定static的目錄
STATICFILES_DIRS = [
os.path.join(BASE_DIR,'static'),
]
_(E).到目前專案目錄
cd pj02
建立templates:md templates
建立static:md static

_(F).建立migration資料檔
功能:若使用資料庫,可以建立資料表的架構與版本記錄,好處是未來可以追踪
語法:python manage.py makemigrations (app名稱)
例如:python manage.py makemigrations
若是沒有指定app01,就會對所有的app來記錄,建議不指定名稱

_(G).將模型與資料庫同步
語法:python manage.py migrate (app名稱)
例如:python manage.py migrate
若是沒有指定app01,就會對所有的app來記錄,建議不指定名稱
☎注意:不要指定app名稱,否則無法讀取資料表

_(H).建立資料庫管理者的帳號與密碼
指令:python manage.py createsuperuser
使用者名稱 (leave blank to use 'administrator'): admin
電子信箱: admin@gmail.com
Password:admin
Password (again):admin
這個密碼與使用者名稱太相近。
這個密碼過短。請至少使用 8 個字元。

_(I).登入資料庫管理者系統
網頁:http://127.0.0.1:8000/admin

範例:exp03_02.py建立資料表類別student,輸入三筆

(3).☎範例:exp03_02.py
☎#目的:建立資料表類別student,並輸入三筆資料
☎#特別注意:欄位名稱不可以取為『url』,否則會出現csrf_token找不到或錯誤

_(A).修改models.ply
from django.db import models
# Create your models here.
class student(models.Model):
cname = models.CharField(max_length=20, null=False)
csex = models.CharField(max_length=4, default='男',null=False)
cbirthday = models.DateField(null=False)
cemail = models.CharField(max_length=50,blank=True, default='')
ctel = models.CharField(max_length=20, blank=True, default='')
caddress = models.CharField(max_length=255, blank=True, default='')
def __str__(self):
return self.cname

_(B).修改admin.ply(資料庫管理者,讀入model裡面的資料表類別)
from django.contrib import admin
from app01.models import student
# Register your models here.
admin.site.register(student)

☎注意:只要資料表有修改新增,就要重新執行migration
_(C).建立migration資料檔
功能:若使用資料庫,可以建立資料表的架構與版本記錄,好處是未來可以追踪
語法:python manage.py makemigrations (app名稱)
例如:python manage.py makemigrations
若是沒有指定app01,就會對所有的app來記錄,建議不指定名稱

_(D).將模型與資料庫同步
語法:python manage.py migrate (app名稱)
例如:python manage.py migrate
若是沒有指定app01,就會對所有的app來記錄,建議不指定名稱
☎注意:不要指定app名稱,否則無法讀取資料表

_(E).資料庫管理者系統,瀏覽資料表
網頁:http://127.0.0.1:8000/admin
點按:新增->新增3筆記錄
django 模型models 常用欄位元 _(F).django 模型models 常用欄位元
☎注意:不能為空值的寫法(null = False)
☎注意:可以是空白值的寫法(blank = True)
☎#特別注意:欄位名稱不可以取為『url』,否則會出現csrf_token找不到或錯誤

1、models.AutoField  
自增列 = int(11)
如果沒有的話,默認會生成一個名稱為 id 的列
如果要顯式的自定義一個自增列,必須設置primary_key=True。

2、models.CharField  
字串欄位元
必須設置max_length參數

3、models.BooleanField 
布爾類型=tinyint(1)
不能為空,可添加Blank=True

4、models.ComaSeparatedIntegerField
用逗號分割的數字=varchar
繼承CharField,所以必須 max_lenght 參數

5、models.DateField
日期類型 date
DateField.auto_now:保存時自動設置該欄位為現在日期,最後修改日期
DateField.auto_now_add:當該對象第一次被創建是自動設置該欄位為現在日期,創建日期。

6、models.DateTimeField 
日期時間類型 datetime
同DateField的參數

7、models.Decimal 
十進位小數類型 = decimal
DecimalField.max_digits:數字中允許的最大位數
DecimalField.decimal_places:存儲的十進位位數

8、models.EmailField  
一個帶有檢查 Email 合法性的 CharField

9、models.FloatField
浮點類型 = double

10、models.IntegerField 
整形

11、models.BigIntegerField
   長整形
integer_field_ranges = {
  'SmallIntegerField': (-32768, 32767),
  'IntegerField': (-2147483648, 2147483647),
  'BigIntegerField': (-9223372036854775808, 9223372036854775807),
  'PositiveSmallIntegerField': (0, 32767),
  'PositiveIntegerField': (0, 2147483647),
}

12、models.GenericIPAddressField  
一個帶有檢查 IP位址合法性的 CharField

13、models.NullBooleanField 
允許為空的布爾類型

14、models.PositiveIntegerFiel  
正整數

15、models.PositiveSmallIntegerField 
正smallInteger

16、models.SlugField  
減號、下劃線、字母、數字

17、models.SmallIntegerField  
數字
資料庫中的欄位有:tinyint、smallint、int、bigint

18、models.TextField
大文本。默認對應的form標籤是textarea。

19、models.TimeField
時間 HH:MM[:ss[.uuuuuu]]

20、models.URLField 
一個帶有URL合法性校驗的CharField。

21、models.BinaryField 
二進位
存儲二進位數據。不能使用filter函數獲得QuerySet。

22、models.ImageField
圖片
ImageField.height_field、ImageField.width_field:如果提供這兩個參數,則圖片將按提供的高度和寬度規格保存。
該欄位要求 Python Imaging 庫Pillow。
會檢查上傳的對象是否是一個合法圖片。

23、models.FileField(upload_to=None[, max_length=100, ** options])
文件
FileField.upload_to:一個用於保存上傳檔的本地檔系統路徑,該路徑由 MEDIA_ROOT 中設置
這個欄位不能設置primary_key和unique選項.在資料庫中存儲類型是varchar,默認最大長度為100

24、models.FilePathField(path=None[, math=None, recursive=False, max_length=100, **options])
FilePathField.path:文件的絕對路徑,必填
FilePathField.match:用於過濾路徑下檔案名的正則表達式,該表達式將用在檔案名上(不包括路徑)。
FilePathField.recursive:True 或 False,默認為 False,指定是否應包括所有子目錄的路徑。
例如:FilePathField(path="/home/images", match="foo.*", recursive=True)
將匹配「/home/images/foo.gif」但不匹配「/home/images/foo/bar.gif」

django 模型models 欄位常用參數

2. django 模型models 欄位常用參數
1、null
如果是True,Django會在資料庫中將此欄位的值置為NULL,默認值是False

2、blank
如果為True時django的 Admin 中添加數據時可允許空值,可以不填。如果為False則必須填。默認是False。
null純粹是與資料庫有關係的。而blank是與頁面必填項驗證有關的

3、primary_key = False
主鍵,對AutoField設置主鍵後,就會代替原來的自增 id 列

4、auto_now 和 auto_now_add
auto_now 自動創建---無論添加或修改,都是當前操作的時間
auto_now_add 自動創建---永遠是創建時的時間

5、choices
一個二維的元組被用作choices,如果這樣定義,Django會select box代替普通的文本框,
並且限定choices的值是元組中的值
GENDER_CHOICE = (
(u'M', u'Male'),
(u'F', u'Female'),
)
gender = models.CharField(max_length=2,choices = GENDER_CHOICE)

6、max_length
欄位長度

7、default
默認值

8、verbose_name 
Admin中欄位的顯示名稱,如果不設置該參數時,則與屬性名。

9、db_column
資料庫中的欄位名稱

10、unique=True  
不允許重複

11、db_index = True
資料庫索引

12、editable=True 
在Admin里是否可編輯

13、error_messages=None
錯誤提示

14、auto_created=False 
自動創建

15、help_text 
在Admin中提示幫助信息

16、validators=[]
驗證器

17、upload-to
文件上傳時的保存上傳文件的目錄

範例:exp03_03.py在模板templates顯示一筆

(4).☎範例:exp03_03.py
☎#目的:在模板templates顯示一筆資料
☎#方法:資料表類別.objects.get(查詢指令)
_(A).修改視圖view.ply
程式碼:
from django.shortcuts import render
from app01.models import student
# Create your views here.
def show_one(request):
#讀取一筆資料:cname =張三
try:
item = student.objects.get(cname='張三')
except Exception as e:
errormsg = '讀取資料出現錯誤:' + e
return render(request,'show_one.html',locals())

_(B).修改視圖urls.ply
程式碼:
from django.conf.urls import url
from app01.views import show_one
urlpatterns = [
path('admin/', admin.site.urls),
url(r'^show_one/$',show_one),
]

_(C).修改視圖templates/show_one.html
程式碼:
<HTML>
<HEAD>
<TITLE>顯示一筆學生資料</TITLE>
<META content="text/html; charset=utf-8" http-equiv=Content-Type>
</HEAD>
<BODY>
<h2>姓名 = {{item.cname}}</h2>
<p>性別 = {{item.csex}}</p>
<p>生日 = {{item.cbirthday}}</p>
<p>郵件 = {{item.cemail}}</p>
<p>電話 = {{item.ctel}}</p>
<p>住址 = {{item.caddress}}</p>
</BODY>
</HTML>

_(D).測試:http://127.0.0.1:8000/show_one/
自動編號 = 1
姓名 = 張三
性別 = 男
生日 = 2019年9月28日
郵件 = abc@gmail.com
電話 = 0956123456
住址 = 台南市勝利路250號

exp03_04.py在模板templates顯示全部

(5).☎範例:exp03_04.py
☎#目的:在模板templates顯示全部的資料
☎#方法:資料表類別.objects.all()
_(A).修改視圖view.ply
☎注意:搜尋全部資料:student.objects.all()
☎注意:搜尋全部資料,以id欄位排序:student.objects.all().order_by('id')
☎注意:搜尋全部資料,以id欄位,反向排序:student.objects.all().order_by('-id')
程式碼:
from django.shortcuts import render
from app01.models import student
def show_all(request):
items = student.objects.all().order_by('-id')
return render(request,'show_all.html',locals())

_(B).修改視圖urls.ply
程式碼:
from app01.views import show_one,show_all
urlpatterns = [
path('admin/', admin.site.urls),
url(r'^show_one/$',show_one),
url(r'^show_all/$',show_all),
]

_(C).修改視圖templates/show_all.html
☎注意:雖然建立資料表的時候沒有建立『自動編號』欄位,但是系統會建立『自動編號』欄位(id)
程式碼:
<HTML>
<HEAD>
<TITLE>顯示全部學生資料</TITLE>
<META content="text/html; charset=utf-8" http-equiv=Content-Type>
</HEAD>
<BODY>
<h2>顯示全部學生資料</h2>
<table border="1" cellsapcings='0' cellpadding='0'>
<th>編號</th><th>姓名</th><th>性別</th><th>生日</th><th>郵件</th><th>電話</th><th>住址</th>
{% for item in items %}
<tr>
<td>{{item.id}}</td>
<td>{{item.cname}}</td>
<td>{{item.csex}}</td>
<td>{{item.cbirthday}}</td>
<td>{{item.cemail}}</td>
<td>{{item.ctel}}</td>
<td>{{item.caddress}}</td>
</tr>
{% endfor %}
</table>

</BODY>
</HTML>

_(D).測試:http://127.0.0.1:8000/show_all/
顯示全部學生資料
編號 姓名 性別 生日 郵件 電話 住址
3 王五 男 2019年9月25日 wu@yahoo.com 0945123789 高雄市
2 李四 女 2019年9月24日 ok@gmail.com 02-57188883 台北市
1 張三 男 2019年9月28日 abc@gmail.com 0956123456 台南市勝利路250號

範例:exp03_05.py網頁基礎模板base.html

(5).☎範例:exp03_05.py
☎#目的:將模板*.html分割成兩個(網頁基礎模板base.html+呼叫模板網頁)
☎#方法:網頁基礎模板templates/base.html
<HTML>
<HEAD>
{% block title %}
{% endblock %}
</HEAD>
<BODY>
{% block content %}
{% endblock %}
</BODY>
</HTML>

☎#方法:呼叫模板網頁templates/base.html
{% extends 'base.html' %}
{% %}
{% block title %}
............
{% endblock %}
{% block content %}
............
{% endblock %}

_(A).修改視圖view.ply
☎注意:搜尋全部資料:student.objects.all()
程式碼:
from django.shortcuts import render
from app01.models import student
def show_all_base(request):
items = student.objects.all('cbirthday')
return render(request,'show_all_base.html',locals())

_(B).修改視圖urls.ply
程式碼:
from django.conf.urls import url
from app01.views import show_one,show_all
urlpatterns = [
path('admin/', admin.site.urls),
url(r'^show_one/$',show_one),
url(r'^show_all/$',show_all),
url(r'^show_all_base/$',show_all),
]

_(C).修改基礎模板templates/base.html
程式碼:
<HTML>
<HEAD>
{% block title %}
{% endblock %}
</HEAD>
<BODY>
{% block content %}
{% endblock %}
</BODY>
</HTML>

_(D).呼叫基礎模板templates/show_all_base.html
程式碼:
{% extends 'base.html' %}
{% %}
{% block title %}
<TITLE>顯示全部學生資料</TITLE>
<META content="text/html; charset=utf-8" http-equiv=Content-Type>
{% endblock %}
{% block content %}
<h2>顯示全部學生資料</h2>
<table border="1" cellsapcings='0' cellpadding='0'>
<th>編號</th><th>姓名</th><th>性別</th><th>生日</th><th>郵件</th><th>電話</th><th>住址</th>
{% for item in items %}
<tr>
<td>{{item.id}}</td>
<td>{{item.cname}}</td>
<td>{{item.csex}}</td>
<td>{{item.cbirthday}}</td>
<td>{{item.cemail}}</td>
<td>{{item.ctel}}</td>
<td>{{item.caddress}}</td>
</tr>
{% endfor %}
</table>
{% endblock %}

_(E).測試:http://127.0.0.1:8000/show_all_base/
顯示全部學生資料
編號 姓名 性別 生日 郵件 電話 住址
3 王五 男 2019年9月25日 wu@yahoo.com 0945123789 高雄市
2 李四 女 2019年9月24日 ok@gmail.com 02-57188883 台北市
1 張三 男 2019年9月28日 abc@gmail.com 0956123456 台南市勝利路250號
 
 
chp4.新增,修改,刪除資料表
目錄 表單form傳遞資料的兩種方法post,get django後台(view.py)接收前端網頁(*.html)的資料 exp04_01前端表單傳送姓名年紀 exp04_02前端表單新增一筆:不驗證 exp04_03新增驗證欄位
exp04_04刪除指定編號資料 exp04_05修改指定編號資料 表單使用get傳遞變數 exp04_06表單使用get傳遞,方法一 exp04_07表單使用get傳遞,方法二 exp04_08整合性表單使用get傳遞,方法三

下載

下載本章project成果

表單form傳遞資料的兩種方法(post,get)

1.表單form傳遞資料的兩種方法(post,get)
(1).語法:
<form method='post' name='form1' action='/POST/'>
方法1:method='post'
功能:將表單資料放置在HTTP標頭的方式傳送

方法2:method='get'
功能:將表單資料以字串的方式放在網址的後面傳送(放在?後面,不同欄位的值以&連接)

在django後台(view.py),如何接收前端網頁(*.html)傳來的資料

2.在django後台(view.py),如何接收前端網頁(*.html)傳來的資料(post,get)
☎在view.py接受前端傳來的資料
(1).判別前端傳來的方法是post,還是get
if request.method == 'POST'
if request.method == 'GET'
☎注意:request.method == 'POST',POST必須大寫

(2)接受post傳來的資料
a = request.POST['欄位名稱name']

(3)接受get傳來的資料
a = request.GET['欄位名稱name']

範例:exp04_01.py:前端表單傳送姓名年紀給後台view.py

(4).☎範例:exp04_01.py
☎#目的:前端表單傳送姓名,年紀,如何在後台view.py接收並顯示
_(A).前置作業
#建立專案pj04:django-admin startproject pj04
cd pj04
#建立app01:python manage.py startapp app01
#建立目錄
md static
md templates
#修改settings.py
40行:新的app名稱
'app01',

58行:設定templates目錄位置
'DIRS': [os.path.join(BASE_DIR,'templates')],

107行:設定繁體中文,台北語區
LANGUAGE_CODE = 'zh-Hant'
TIME_ZONE = 'Asia/Taipei'

122行:設定static的目錄
STATICFILES_DIRS = [
os.path.join(BASE_DIR,'static'),
]

_(B).在templates/建立form1.html傳送2個參數
程式碼:
<HTML>
<HEAD> <TITLE>表單傳送資料</TITLE>
<META content="text/html; charset=utf-8" http-equiv=Content-Type>
</HEAD>
<BODY>
<form method="POST" name="myform" action="/POST/">
輸入姓名=<input type="text" id='myname' />
<br/>
輸入年紀=<input type="text" id='myage' />
<input type="submit" value="傳送資料" />
</form>
</BODY>
</HTML>

_(C).在views.py接收2個參數
from django.shortcuts import render
# Create your views here.
☎注意:request.method == 'POST',POST必須大寫
def form1(request):
if request.method == 'POST': #POST必須大寫
myname = request.POST['myname']
myage = request.POST['myage']
else:
myname = '資料沒有採用post傳送'
myage = '資料沒有採用post傳送'
return render(request,'form1.html',locals())

_(D).在templates/顯示傳回form1.html的2個參數
☎注意:action="/form1/",表示會執行http://127.0.0.1:8000/form1/
☎注意:method="post"時,表單欄位代號必須用name(不用id)
☎注意:{% csrf_token %}必須放在form 表單裡面
☎注意:若是採用POST方式來傳送資料,就必須啟動CRSF防護,避免伺服器被攻擊。
若是沒有啟動CRSF防護,就會產生錯誤訊息
☎注意:為什麼要啟動CRSF防護?及其原理
原因:伺服器要檢查這個資料的傳送,是否是當初自己給的,若不是,就是外來的攻擊
原理:當我們開啟django一個前端網頁時,同時django主機也順便傳送一個亂數產生的token到前端網頁了。
而前端網頁傳送資料回主機時,django主機會檢查這個token是否是當初主機給的值
程式碼:
<HTML>
<HEAD>
<TITLE>表單傳送資料</TITLE>
<META content="text/html; charset=utf-8" http-equiv=Content-Type>
</HEAD>
<BODY>
<form method="post" name="myform" action="/form1/">
{% csrf_token %}
輸入姓名=<input type="text" name='myname' />
<br/>
輸入年紀=<input type="text" name='myage' />
<input type="submit" value="傳送資料" />
</form>
django主機傳回:<br/>
姓名 = {{ myname }}<br/>
年紀 = {{ myage }}<br/>
</BODY>
</HTML>

_(E).設定urls.py
from django.conf.urls import url
from app01.views import form1
urlpatterns = [
path('admin/', admin.site.urls),
url(r'^$', form1),
url(r'^form1/$', form1),
]

_(F).測試:http://127.0.0.1:8000/
輸入姓名=
輸入年紀=

django主機傳回:
姓名 = john
年紀 = 23

範例:exp04_02.py前端表單新增一筆資料(不驗證欄位資料)

(5).☎範例:exp04_02.py(不驗證欄位資料)
☎#目的:前端表單新增一筆資料(不驗證欄位資料),如何在後台view.py接收並顯示
_(A).前置作業
#models.py建立資料表類別
程式碼:
class stu(models.Model):
cname = models.CharField(max_length=20,null=False)
csex = models.CharField(max_length=2,null=False)
cbirthday = models.DateField(null=False)
cmail = models.EmailField(max_length=30,default='',blank=True)
ctel = models.CharField(max_length=20,default='',blank=True)
caddress = models.CharField(max_length=255,default='',blank=True)

def __str__(self):
return self.cname

#admin.py建立資料表類別
from app01.models import stu
# Register your models here.
admin.site.register(stu)

#執行資料表庫migration
python manage.py makemigrations

#同步資料表庫migration
python manage.py migrate
☎注意:不要指定app名稱,否則無法讀取資料表

#測試資料庫
python manage.py runserver
http://127.0.0.1:8000/admin
(需要帳號密碼)

#建立superuser的帳號密碼
指令:python manage.py createsuperuser
使用者名稱 (leave blank to use 'administrator'): admin
電子信箱: admin@gmail.com
Password:admin
Password (again):admin
這個密碼與使用者名稱太相近。
這個密碼過短。請至少使用 8 個字元。

#新增三筆資料
http://127.0.0.1:8000/admin


_(B).建立一個網頁,顯示全部資料,並有新增按鈕(show_all.html
#在views.py建立show_all函式
from app01.models import stu
def show_all(request):
items = stu.objects.all()
return render(request,'shoow_all.html',locals())

#在show_all.html建立網頁(使用base.html
☎注意:『新增』的超連結的網址,不寫網址,而是寫view.py的函式名稱(例如<a href='/add01/'>)
☎在view.py:def add01(request):
return render(request,'add01.html',locals())
程式碼:
{% extends 'base.html' %}
{% block title %}
<TITLE>顯示所有學生資料</TITLE>
<META content="text/html; charset=utf-8" http-equiv=Content-Type>
{% endblock %}
{% block content %}
<h2>顯示全部學生資料:
<a href='/add01/'>新增一筆(不驗證)</a>
<a href='/add02/'>新增一筆(驗證)</a>
<a href='/del01/'>刪除</a>
<a href='/edit01/'>修改</a>
<a href='/add03/'>新增(get方法)</a>
</h2>
<table border="1" cellsapcings='0' cellpadding='0'>
<th>編號</th><th>姓名</th><th>性別</th><th>生日</th><th>郵件</th><th>電話</th><th>住址</th>
{% for item in items %}
<tr>
<td>{{item.id}}</td>
<td>{{item.cname}}</td>
<td>{{item.csex}}</td>
<td>{{item.cbirthday}}</td>
<td>{{item.cmail}}</td>
<td>{{item.ctel}}</td>
<td>{{item.caddress}}</td>
</tr>
{% endfor %}
</table>
{% endblock %}

#在views.py:建立add01函式
def add01(request):
return render(request,'add01.html',locals())

_(C).建立一個網頁,可以新增一筆記錄(add01.html
☎注意:因為有從主機傳回值,所以要驗證token ,方法:{% csrf_token %}
☎注意:若表單form送出到主機的位置與目前一樣,那麼action = ".",或是action = ""
☎注意:日期欄位的格式是:2019-5-5(不是209/5/5)
例如:生日=<input type="text" placeholder="2019-9-2" name='mybirthday' />
程式碼:
{% extends 'base.html' %}
{% block title %}
<TITLE>新增一筆資料,資料不作驗證</TITLE>
<META content="text/html; charset=utf-8" http-equiv=Content-Type>
{% endblock %}
{% block content %}
<form method="post" name="myform" action=".">
{% csrf_token %}
姓名=<input type="text" name='myname' />
<br/>
性別=<input type="text" placeholder="男" name='mysex' />
<br/>
生日=<input type="text" placeholder="2019-9-2" name='mybirthday' />
<br/>
郵件=<input type="text" placeholder="abc@gmail.com" name='mymail' />
<br/>
電話=<input type="text" name='mytel' />
<br/>
住址=<input type="text" name='myaddress' />
<br/>
<input type="submit" value="送出" />
<input type="reset" value="重設" />
</form>
<p style="color: magenta">{{message01}}</p>

{% endblock %}


_(D).修改views.py:修改add01函式(處理上傳資料給主機新增一筆記錄)
☎django轉網址有三種方法(一):redirect('/xxx/')
☎注意:要先import redirect函式(from django.shortcuts import redirect)
☎新增一筆記錄的語法
recd = stu.objects.create(欄位=變數,欄位=變數,cbirthday=mybirthday)
recd.save()
程式碼:
from django.shortcuts import render,redirect
def add01(request):
if request.method == 'POST':
myname = request.POST['myname']
mysex = request.POST['mysex']
mybirthday = request.POST['mybirthday']
mymail = request.POST['mymail']
mytel = request.POST['mytel']
myaddress = request.POST['myaddress']
#新增一筆記錄
recd = stu.objects.create(cname=myname,csex=mysex,cbirthday=mybirthday,cmail=mymail,ctel=mytel,caddress=myaddress)
recd.save()
return redirect('/show_all/')
else:
message01 = '請輸入資料(資料不作驗證)'
return render(request,'add01.html',locals())

_(E).設定urls.py
from django.contrib import admin
from django.urls import path
from django.conf.urls import url
from app01.views import form1,show_all,add01
urlpatterns = [
path('admin/', admin.site.urls),
url(r'^$', form1),
url(r'^form1/$', form1),
url(r'^show_all/$', show_all),
url(r'^add01/$', add01),
]



範例:exp04_03.py驗證欄位資料

(6).☎範例:exp04_03.py(要驗證欄位資料)
☎#目的:前端表單新增一筆資料(要驗證欄位資料),如何在後台view.py接收並顯示
_(A).前置作業:#form.py建立驗證欄位類別
☎注意:預設都是欄位必須有值,除非註明required=False
☎注意:預設值的設定用initial=''(不是用default='')
☎注意:若是日期欄位,設定為forms.DateField(),則可以輸入2019/8/9,或是209-8-9
☎注意:若是email欄位,設定為forms.EmailField(),則會檢驗是否符合email格式

在app01目錄底下,新增檔案:form.py
程式碼:
from django import forms
class PostForm(forms.Form):
myname = forms.CharField(max_length=20,initial='')
mysex = forms.CharField(max_length=2,initial='男')
mybirthday = forms.DateField()
mymail = forms.EmailField(max_length=20, initial='',required=False)
mytel = forms.CharField(max_length=10, initial='',required=False)
myaddress = forms.CharField(max_length=100, initial='',required=False)

_(B).在views.py建立add02函數
#功能:可以顯示新增一筆資料網頁(add02.html),可以處理新增記錄存入資料庫(recd.save())
☎注意:PostForm()會建立一個空白PostForm物件
☎注意:PostForm(request.POST)會把表單form的輸入參數,建立一個PostForm物件(有表單參數)
☎驗證PostForm物件是否正確:postform.is_valid()
☎接收表單的myname欄位 postform.cleaned_data['myname']
☎切換網頁:return redirect('/show_all/')
程式碼:
from app01.form import PostForm
def add02(request):
if request.method=='POST':
#建立form物件
postform = PostForm(request.POST)
#如果通過forms驗證
if postform.is_valid():
myname = postform.cleaned_data['myname']
mysex = postform.cleaned_data['mysex']
mybirthday = postform.cleaned_data['mybirthday']
mymail = postform.cleaned_data['mymail']
mytel = postform.cleaned_data['mytel']
myaddress = postform.cleaned_data['myaddress']
#新增一筆記錄
recd = stu.objects.create(cname=myname,csex=mysex,cbirthday=mybirthday,cmail=mymail,ctel=mytel,caddress=myaddress)
recd.save()
message01 = '已經成功儲存'
return redirect('/show_all/')
else:
message01 = '輸入欄位驗證錯誤'
else:
message01 = '有幾個欄位是必須輸入的:姓名,生日,性別'
postform = PostForm()
return render(request,'add02.html',locals())

_(C).在urls.py建立網址設定公式
程式碼:
from app01.views import form1,show_all,add01,add02
urlpatterns = [
path('admin/', admin.site.urls),
url(r'^$', form1),
url(r'^form1/$', form1),
url(r'^show_all/$', show_all),
url(r'^add01/$', add01),
url(r'^add02/$', add02),
]

_(D).建立模板顯示網頁add02.html
☎顯示textbox欄位 = {{ postform.myname }}
因為它會引用form.py裡面的驗證欄位來顯示
☎注意:若是日期欄位,設定為forms.DateField(),則可以輸入2019/8/9,或是209-8-9
☎注意:若是email欄位,設定為forms.EmailField(),若是有輸入文字,則會檢驗是否符合email格式
程式碼:
{% extends 'base.html' %}
{% block title %}
<TITLE>新增一筆資料,資料不作驗證</TITLE>
<META content="text/html; charset=utf-8" http-equiv=Content-Type>
{% endblock %}
{% block content %}
<form method="post" name="myform" action=".">
{% csrf_token %}
姓名 = {{ postform.myname }}
<br/>
性別 = {{ postform.mysex }}
<br/>
生日 = {{ postform.mybirthday}}
<br/>
郵件 = {{ postform.mymail }}
<br/>
電話 = {{ postform.mytel }}
<br/>
住址 = {{ postform.myaddress }}
<br/>
<input type="submit" value="送出" />
<input type="reset" value="重設" />
</form>
<p style="color: magenta">{{message01}}</p>
{% endblock %}
結果:


範例:exp04_04.py刪除指定編號資料

(7).☎範例:exp04_04.py(刪除指定編號資料)
☎#目的:刪除指定編號資料

_(A).在views.py建立del01函數
☎注意:刪除一筆資料的語法
recd = stu.objects.get(編號=myid)
recd.delete()
☎注意:如何取得由post傳來的myid數字 = request.POST['myid']

def del01(request):
if request.method=="POST":
myid = request.POST['myid']
try:
recd = stu.objects.get(id=myid)
recd.delete()
return redirect('/show_all/')
except:
message01 = '這個id不存在'
return render(request,'del01.html',locals())

_(B).在urls.py建立網址設定公式
from app01.views import form1,show_all,add01,add02,del01
urlpatterns = [
path('admin/', admin.site.urls),
url(r'^$', form1),
url(r'^form1/$', form1),
url(r'^show_all/$', show_all),
url(r'^add01/$', add01),
url(r'^add02/$', add02),
url(r'^del01/$', del01),
]

_(C).建立模板顯示網頁del01.html
{% extends 'base.html' %}
{% block title %}
<TITLE>刪除一筆資料</TITLE>
<META content="text/html; charset=utf-8" http-equiv=Content-Type>
{% endblock %}
{% block content %}
<form method="post" name="myform" action=".">
{% csrf_token %}
輸入想刪除的編號=<input type="text" name='myid' />
<br/>
<input type="submit" value="刪除" />
</form>
<p style="color: magenta">{{message01}}</p>
{% endblock %}
結果:


範例:exp04_05.py修改指定編號資料

(8).☎範例:exp04_05.py(修改指定編號資料)
☎#目的:修改指定編號資料(首先要指定編號,然後顯示所有資料,修改後,再回存)

_(A).在views.py建立edit01函數(首先要指定編號)
☎注意:不同網頁之間,傳遞變數的方法:request.session['myid']
☎注意:如何判別這個id不存在?(使用try...except,查詢資料表id=myid是否存在
myid = request.POST['myid']
try:
recd = stu.objects.get(id=myid)
return redirect('/edit02/')
except:
message01 = '這個id不存在'
程式碼:
def edit01(request):
if request.method=='POST':
request.session['myid'] = request.POST['myid']
myid = request.POST['myid']
try:
recd = stu.objects.get(id=myid)
return redirect('/edit02/')
except:
message01 = '這個id不存在'
return render(request,'edit01.html',locals())

_(B).在views.py建立edit02函數(顯示所有資料,修改後,再回存)
☎注意:查詢資料表後,顯示某個欄位的方法是:recd.欄位名稱
recd = stu.objects.get(id=myid)
myname = recd.cname

☎注意:修改資料表的語法
#先查詢某筆資料
recd = stu.objects.get(id=myid)
#直接把表單post傳遞來的值覆蓋在recd上
recd.cname = request.POST['myname']
#存檔recd,就是修改了
recd.save()

☎注意:修改顯示日期2019年9月19日,改成2019-9-19格式(修改後才不會出現錯誤)
方法:str(recd.cbirthday).replace('年','-').replace('月','-').replace('日','-')
程式碼:
def edit02(request):
#顯示資料表尚未修改前的數據
myid = request.session['myid']
recd = stu.objects.get(id=myid)
myname = recd.cname
mysex = recd.csex
#修改顯示日期2019年9月19日,改成2019-9-19格式
mybirthday = str(recd.cbirthday).replace('年','-').replace('月','-').replace('日','-')
mymail = recd.cmail
mytel = recd.ctel
myaddress = recd.caddress
if request.method=='POST':
#若是經由POST傳來,表示已經被修改了
#修改資料表寫法(先查到改變,再覆蓋值)
recd = stu.objects.get(id=myid)
recd.cname = request.POST['myname']
recd.csex = request.POST['mysex']
recd.cbirthday = request.POST['mybirthday']
recd.cmail = request.POST['mymail']
recd.ctel = request.POST['mytel']
recd.caddress = request.POST['myaddress']
recd.save()
#修改完畢
return redirect('/show_all/')
return render(request,'edit02.html',locals())

_(C).在urls.py建立網址設定公式、
程式碼:
from app01.views import form1,show_all,add01,add02,del01,edit01,edit02
urlpatterns = [
path('admin/', admin.site.urls),
url(r'^$', form1),
url(r'^form1/$', form1),
url(r'^show_all/$', show_all),
url(r'^add01/$', add01),
url(r'^add02/$', add02),
url(r'^del01/$', del01),
url(r'^edit01/$', edit01),
url(r'^edit02/$', edit02),
]

_(D).建立模板網頁edit01.html(指定編號資料)
程式碼:
{% extends 'base.html' %}
{% block title %}
<TITLE>修改一筆資料</TITLE>
<META content="text/html; charset=utf-8" http-equiv=Content-Type>
{% endblock %}
{% block content %}
<form method="post" name="myform" action=".">
{% csrf_token %}
輸入想修改的編號=<input type="text" name='myid' />
<br/>
<input type="submit" value="確定" />
</form>
<p style="color: magenta">{{message01}}</p>
{% endblock %}

_(E).建立模板網頁edit02.html(顯示所有資料,修改後,再回存)
☎在input顯示主機傳來的資料:value="{{ myname }}"
<input type="text" name='myname' value="{{ myname }}" />
程式碼:
{% extends 'base.html' %}
{% block title %}
<TITLE>修改一筆資料,資料不作驗證</TITLE>
<META content="text/html; charset=utf-8" http-equiv=Content-Type>
{% endblock %}
{% block content %}
<form method="post" name="myform" action=".">
{% csrf_token %}
姓名=<input type="text" name='myname' value="{{ myname }}" />
<br/>
性別=<input type="text" placeholder="男" name='mysex' value="{{ mysex }}" />
<br/>
生日=<input type="text" placeholder="2019-9-2" name='mybirthday' value="{{ mybirthday }}" />
<br/>
郵件=<input type="text" placeholder="abc@gmail.com" name='mymail' value="{{ mymail }}" />
<br/>
電話=<input type="text" name='mytel' value="{{ mytel }}" />
<br/>
住址=<input type="text" name='myaddress' value="{{ myaddress }}" />
<br/>
<input type="submit" value="修改" />
</form>
<p style="color: magenta">{{message01}}</p>
{% endblock %}
結果:


3.網頁表單使用get傳遞變數,有三種方法

3.網頁表單使用get傳遞變數
(1).網頁表單使用get傳遞變數,有三種方法:
☎方法1:需要form表單,在action指定雙層參數
<form method="get" name="myform" action="/add03/save/">

#在view.py
def add03(request,mode=None):
if mode == 'save':
myname = str(request.GET.get('myname'))

☎方法2:需要form表單
<form method="get" name="myform" action="">
<input type="submit" value="送出" name='submitButton' />

#在view.py
def add04(request):
if request.GET.get('submitButton') =='送出':
myname = request.GET.get('myname')

☎方法3:不需要form表單,直接超連結
<a href='/del05/?myid={{item.id}}'>刪除</a>
<a href='/del05/?myid=2'>刪除</a>

範例:exp04_06.py表單使用get傳遞,方法一

(2).☎範例:exp04_06.py(表單使用get傳遞,方法一)
☎#目的:新增一筆記錄,但是表單使用get傳遞

_(A).修改:show_all.html
<h2>顯示全部學生資料:
<a href='/add01/'>新增一筆(不驗證)</a>
<a href='/add02/'>新增一筆(驗證)</a>
<a href='/del01/'>刪除</a>
<a href='/edit01/'>修改</a>
<a href='/add03/'>新增(get方法)</a>
</h2>

_(A).在view.py建立add03函數(表單使用get傳遞,方法一)
☎注意:兩種GET接收變數的方法:
#若是由form傳來get變數:request.GET['pagebtn']
#若是由網址?pagebtn=..傳來的get變數:request.GET.get('pagebtn')

☎注意:接收get變數的方法:request.GET.get('myname')
例如:myname = str(request.GET.get('myname'))

☎注意:get變數的型態不是字串,還要用str(...)轉換

☎注意:無法用if request.method == 'GET'來判別是否是get的表單按鈕submit傳遞來的
原因:因為只要是網頁傳遞來的,預設就是用get模式(可能是網址後?id=b0001傳來的)
所以若是用if request.method == 'GET'來判別,任何網頁的呼叫(除了post外)都會符合
☎解決方法:如何才能判別是真的由get表單按了submit傳遞來的
方法:action使用雙參數:action="/add03/save/"
#模板:
<form method="get" name="myform" action="/add03/save/">

#視圖view
def add03(request,mode=None):
if mode == 'save':

views.py程式碼:
#使用get方法傳遞,新增一筆
def add03(request,mode=None):
#因為網頁預設就是GET方法,所以雖然沒有按submit,也是用get方法,所以不能用request.method == 'GET'來判別是否按了submit
#改良方法:用第二個參數mode
#if request.method == 'GET':
if mode == 'save':
myname = str(request.GET.get('myname'))
mysex = str(request.GET.get('mysex'))
mybirthday = str(request.GET.get('mybirthday'))
mymail = str(request.GET.get('mymail'))
mytel = str(request.GET.get('mytel'))
myaddress = str(request.GET.get('myaddress'))
#新增一筆記錄
recd = stu.objects.create(cname=myname,csex=mysex,cbirthday=mybirthday,cmail=mymail,ctel=mytel,caddress=myaddress)
recd.save()
return redirect('/show_all/')
else:
message01 = '請輸入資料(資料不作驗證)'
return render(request,'add03.html',locals())

_(C).在urls.py建立網址設定公式、
程式碼:
from app01.views import form1,show_all,add01,add02,del01,edit01,edit02,add03
urlpatterns = [
path('admin/', admin.site.urls),
url(r'^$', form1),
url(r'^form1/$', form1),
url(r'^show_all/$', show_all),
url(r'^add01/$', add01),
url(r'^add02/$', add02),
url(r'^del01/$', del01),
url(r'^edit01/$', edit01),
url(r'^edit02/$', edit02),
url(r'^add03/$', add03),
url(r'^add03/(\w+)/$', add03),
]

_(D).建立模板網頁add03.html
程式碼:
{% extends 'base.html' %}
{% block title %}
<TITLE>新增一筆資料,資料不作驗證</TITLE>
<META content="text/html; charset=utf-8" http-equiv=Content-Type>
{% endblock %}
{% block content %}
<form method="get" name="myform" action="/add03/save/">
{% csrf_token %}
姓名=<input type="text" name='myname' />
<br/>
性別=<input type="text" placeholder="男" name='mysex' />
<br/>
生日=<input type="text" placeholder="2019-9-2" name='mybirthday' />
<br/>
郵件=<input type="text" placeholder="abc@gmail.com" name='mymail' />
<br/>
電話=<input type="text" name='mytel' />
<br/>
住址=<input type="text" name='myaddress' />
<br/>
<input type="submit" value="送出" />
<input type="reset" value="重設" />
</form>
<p style="color: magenta">{{message01}}</p>
{% endblock %}


範例:exp04_07.py表單使用get傳遞,方法二

(3).☎範例:exp04_07.py(表單使用get傳遞,方法二)
☎#目的:新增一筆記錄,但是表單使用get傳遞

_(A).修改:show_all.html
<h2>顯示全部學生資料:
<a href='/add01/'>新增一筆(不驗證)</a>
<a href='/add02/'>新增一筆(驗證)</a>
<a href='/del01/'>刪除</a>
<a href='/edit01/'>修改</a>
<a href='/add03/'>新增(get方法一)</a>
<a href='/add04/'>新增(get方法二)</a>
</h2>

_(A).在views.py建立add04函數(表單使用get傳遞,方法二)
☎如何才能判別是真的由get表單按了submit傳遞來的
方法:type="submit" 設定雙參數: value="送出" name='submitButton'
#模板:
<input type="submit" value="送出" name='submitButton' />

#視圖view
if request.GET.get('submitButton') =='送出'

程式碼:
#使用get方法傳遞,新增一筆
def add04(request):
if request.GET.get('submitButton') =='送出':
myname = request.GET.get('myname')
myname = str(request.GET.get('myname'))
mysex = str(request.GET.get('mysex'))
mybirthday = str(request.GET.get('mybirthday'))
mymail = str(request.GET.get('mymail'))
mytel = str(request.GET.get('mytel'))
myaddress = str(request.GET.get('myaddress'))
#新增一筆記錄
recd = stu.objects.create(cname=myname,csex=mysex,cbirthday=mybirthday,cmail=mymail,ctel=mytel,caddress=myaddress)
recd.save()
return redirect('/show_all/')
else:
message01 = '請輸入資料(資料不作驗證)'
return render(request,'add04.html',locals())

_(C).在urls.py建立網址設定公式、
程式碼:
from app01.views import form1,show_all,add01,add02,del01,edit01,edit02,add03
urlpatterns = [
path('admin/', admin.site.urls),
url(r'^$', form1),
url(r'^form1/$', form1),
url(r'^show_all/$', show_all),
url(r'^add01/$', add01),
url(r'^add02/$', add02),
url(r'^del01/$', del01),
url(r'^edit01/$', edit01),
url(r'^edit02/$', edit02),
url(r'^add03/$', add03),
url(r'^add03/(\w+)/$', add03),
url(r'^add04/$', add04),
]

_(D).建立模板網頁add04.html
程式碼:
{% extends 'base.html' %}
{% block title %}
<TITLE>新增一筆資料,資料不作驗證</TITLE>
<META content="text/html; charset=utf-8" http-equiv=Content-Type>
{% endblock %}
{% block content %}
<form method="get" name="myform" action="">
{% csrf_token %}
姓名=<input type="text" id='myname' name='myname' />
<br/>
性別=<input type="text" placeholder="男" name='mysex' />
<br/>
生日=<input type="text" placeholder="2019-9-2" name='mybirthday' />
<br/>
郵件=<input type="text" placeholder="abc@gmail.com" name='mymail' />
<br/>
電話=<input type="text" name='mytel' />
<br/>
住址=<input type="text" name='myaddress' />
<br/>
<input type="submit" value="送出" name='submitButton' />
</form>
<p style="color: magenta">{{message01}}</p>
{% endblock %}


範例:exp04_08.py整合性表單,使用get傳遞,方法三

(4).☎範例:exp04_08.py(整合性表單,使用get傳遞,方法三)
☎#目的:新增一筆記錄,但是表單使用get傳遞

_(A).建立:show_all_05.html
☎重點:如何才能使用get(?myid=2)傳遞這一行的myid:href='/del05/?myid={{item.id}}'
<a href='/del05/?myid={{item.id}}'>刪除</a>
☎重點:而且這種?myid=...的方法,不需要放在form表單裡面

程式碼:
{% extends 'base.html' %}
{% block title %}
<TITLE>顯示所有學生資料</TITLE>
<META content="text/html; charset=utf-8" http-equiv=Content-Type>
{% endblock %}
{% block content %}
<h2>顯示全部學生資料:
<a href='/add01/'>新增一筆(不驗證)</a>
<a href='/add02/'>新增一筆(驗證)</a>
</h2>
<table border="1" cellsapcings='0' cellpadding='0'>
<th>編號</th><th>姓名</th><th>性別</th><th>生日</th><th>郵件</th><th>電話</th><th>住址</th><th>刪除</th><th>編輯</th>
{% for item in items %}
<tr>
<td>{{item.id}}</td>
<td>{{item.cname}}</td>
<td>{{item.csex}}</td>
<td>{{item.cbirthday}}</td>
<td>{{item.cmail}}</td>
<td>{{item.ctel}}</td>
<td>{{item.caddress}}</td>
<td><a href='/del05/?myid={{item.id}}'>刪除</a></td>
<td><a href='/edit05/?myid={{item.id}}'>編輯</a></td>
</tr>
{% endfor %}
</table>
{% endblock %}

_(B).在views.py建立add04函數(整合性表單,使用get傳遞,方法三)
☎接收get變數的兩種方法:
☎注意:兩種GET接收變數的方法:
#若是由form傳來get變數:request.GET['pagebtn']
#若是由網址?pagebtn=..傳來的get變數:request.GET.get('pagebtn')
方法1: myid = request.GET.get('myid')
方法2: myid = request.GET['myid']

☎接收post變數的方法:
myid = request.POST['myid']

程式碼:
def del05(request):
if request.method=="GET":
#兩種get取值方法都可以
myid = request.GET.get('myid')
#myid = request.GET['myid']
message01 = myid
recd = stu.objects.get(id=myid)
recd.delete()
return redirect('/show_all05/')

def edit05(request):
if request.method=="GET":
#顯示資料表尚未修改前的數據
myid = request.GET['myid']
recd = stu.objects.get(id=myid)
myname = recd.cname
mysex = recd.csex
#修改顯示日期2019年9月19日,改成2019-9-19格式
mybirthday = str(recd.cbirthday).replace('年','-').replace('月','-').replace('日','-')
mymail = recd.cmail
mytel = recd.ctel
myaddress = recd.caddress
return render(request,'edit05.html',locals())
elif request.method=='POST':
#若是經由POST傳來,表示已經被修改了
#修改資料表寫法(先查到改變,再覆蓋值)
myid = request.POST['myid']
recd = stu.objects.get(id=myid)
recd.cname = request.POST['myname']
recd.csex = request.POST['mysex']
recd.cbirthday = request.POST['mybirthday']
recd.cmail = request.POST['mymail']
recd.ctel = request.POST['mytel']
recd.caddress = request.POST['myaddress']
recd.save()
#修改完畢
return redirect('/show_all05/')

_(C).在urls.py建立網址設定公式、
程式碼:
from app01.views import form1,show_all,add01,add02,del01,edit01,edit02,add03,add04,show_all05,del05,edit05
urlpatterns = [
path('admin/', admin.site.urls),
..........
url(r'^show_all05/$', show_all05),
url(r'^del05/$', del05),
url(r'^edit05/$', edit05),
]

_(D).建立:edit05.html
☎重點:要建立編號欄位(因為要接收post變數myid)
編號=<input type="text" name='myid' readonly value="{{ myid }}" />

程式碼:
{% extends 'base.html' %}
{% block title %}
<TITLE>修改一筆資料,資料不作驗證</TITLE>
<META content="text/html; charset=utf-8" http-equiv=Content-Type>
{% endblock %}
{% block content %}
<form method="post" name="myform" action=".">
{% csrf_token %}
編號=<input type="text" name='myid' readonly value="{{ myid }}" />
<br/>
姓名=<input type="text" name='myname' value="{{ myname }}" />
<br/>
性別=<input type="text" placeholder="男" name='mysex' value="{{ mysex }}" />
<br/>
生日=<input type="text" placeholder="2019-9-2" name='mybirthday' value="{{ mybirthday }}" />
<br/>
郵件=<input type="text" placeholder="abc@gmail.com" name='mymail' value="{{ mymail }}" />
<br/>
電話=<input type="text" name='mytel' value="{{ mytel }}" />
<br/>
住址=<input type="text" name='myaddress' value="{{ myaddress }}" />
<br/>
<input type="submit" value="修改" />
</form>
<p style="color: magenta">{{message01}}</p>
{% endblock %}


 
 
chp5. Session 與 Cookie

下載

下載本章project成果
目錄 為什麼要有Session 與 Cookie Session exp05-01設定session變數,取出變數 exp05-02判斷會員是否已經登入
設定session的期限三種方法 exp05-03設定session,刪除session exp05-04登入帳號密碼後記錄session,登出後刪除 Cookie exp05-05用cookie顯示瀏覽本頁人數

1.為什麼要有Session 與 Cookie

1.為什麼要有Session 與 Cookie
(1)壯態管理:
當使用者在發送一個請求關得到返回資訊之後,用戶端與伺服器端之間的網路連接就已經斷開了,在下一個請求發送時,伺服器無法確定這次請求和上次的請求是否來自同一個客戶端。也就是說,伺服器不能記住"記住"使用者,
如何讓伺服器知道不同的請求是否來自同一個用戶端,就是狀態管理問題出現了session和cookie。

(2).保存上次暫存記錄:
例如:要保存會員剛剛登入的會員資料,可以用兩種方法
A.會員資料記錄在用戶端電腦的小檔案(cookie)
B.會員資料記錄在伺服器記憶體的小空間,暫時記憶資料(session)

2.Session

2.Session
(1).特色與限制:
A.資料記錄在伺服器記憶體裡面,所以資料不易被竊取,比較安全,因此比較多人使用Session,而少用cookie
B.Session變數的有效期限是有限制,一段時間就會消失,這是伺服器的設定

(2).Django必須安裝 session App 才能夠使用 session變數
方法:在settings.py
#第37行
'django.contrib.sessions',

#第45行
'django.contrib.sessions.middleware.SessionMiddleware',

(3).存取session變數方法:(用字典方式存取)
A.設定session變數
request.session[變數] = 值
例如:
request.session['username'] = 'tom'

B.讀進session變數
變數 = request.session[變數]
例如:
myname = request.session['username']

exp05-01.py設定session變數,取出變數

(4).範例:exp05-01.py(設定session變數,取出session變數)
_(B).建立專案
django-admin startproject pj03
_(C).建立應用程式app
python manage.py startapp app01
_(D).修改settings.py
40行:新的app名稱
'app01',

58行:設定templates目錄位置
'DIRS': [os.path.join(BASE_DIR,'templates')],

107行:設定繁體中文,台北語區
LANGUAGE_CODE = 'zh-Hant'
TIME_ZONE = 'Asia/Taipei'

122行:設定static的目錄
STATICFILES_DIRS = [
os.path.join(BASE_DIR,'static'),
]

_(E).到目前專案目錄
cd pj02

_(F).建立migration資料檔
例如:python manage.py makemigrations

_(G).將模型與資料庫同步
例如:python manage.py migrate
☎注意:若是沒有執行(python manage.py migrate),則無法使用session變數

_(I).登入資料庫管理者系統
網頁:http://127.0.0.1:8000/admin


☎重點:如何在網頁輸出一段文字:HttpResponse(文字)
例如:return HttpResponse('你好,歡迎光臨')

(A).在views.py設定函數
☎重點:如何在網頁輸出一段文字:HttpResponse(文字)
from django.http import HttpResponse
return HttpResponse('你好,歡迎光臨')
程式碼:
from django.http import HttpResponse
def setS(request):
request.session['myname'] = "張三"
return HttpResponse('已經設定session變數')

def getS(request):
n1 = request.session['myname']
return HttpResponse('取得session變數 = ' + n1)

(B).在urls.py設定
from app01.views import setS,getS
urlpatterns = [
path('admin/', admin.site.urls),
url(r'^setS/$',setS),
url(r'^getS/$',getS),
]

(C).測試:
網頁:http://127.0.0.1:8000/setS/
網頁:http://127.0.0.1:8000/getS/

(D).在Chrome開發者工具,觀看session變數
F12
Appplication
Storage -> Cookies -> http://127.0.0.1:8000


exp05-02判斷會員是否已經登入

(5).範例:exp05-02.py(判斷會員是否已經登入了)
(A).在views.py設定函數
☎重點:如何判別在session裡面有沒有這個變數login
if not "login" in request.session:

程式碼:
def isMember(request):
if not "login" in request.session:
request.session['login'] = True
return HttpResponse('會員現在登入')
else:
return HttpResponse('會員已經在線上')

(B).在urls.py設定
from app01.views import setS,getS,isMember
urlpatterns = [
path('admin/', admin.site.urls),
.....
url(r'^isMember/$',isMember),
]

(C).測試:http://127.0.0.1:8000/isMember/

設定session的期限,刪除session的方法

(6).設定session的期限,刪除session的方法
(A).設定session的時限:方法一(在views.py函式內)
指令:request.session.set_expiry(n*60)
n分鐘

(B).設定session的時限:方法二(在settings.py函式內)
SESSION_COOKIE_AGE = 1440
(24分鐘 = 24 × 60 = 1440 秒)

(C).設定關閉瀏覽器後,session自動消失(在settings.py函式內)
SESSION_EXPIRE_AT_BROWSER_CLOSE = True
(預設是False,關閉後還是會存在)

(D).關閉指定名稱session(在views.py函式內)
del request.session[名稱]

(E).關閉所有的session(在views.py函式內)
request.session.clear()

exp05-03.py設定session的時間,刪除session

(7).範例:exp05-03.py(設定session的時間,刪除session)
(A).在views.py設定函數
def setStime(request):
if 'myname' in request.session:
request.session.set_expiry(60*60) #60分鐘
return HttpResponse('已經設定session變數:myname有效時間為:60分鐘' )
else:
return HttpResponse('沒有這個session變數:myname ')

def delS(request):
#刪除myname
#del request.session['myname']
#刪除全部的session
request.session.clear()
return HttpResponse('已經清除全部的session變數')

(B).在urls.py設定
from app01.views import setS,getS,isMember,setStime,delS
urlpatterns = [
path('admin/', admin.site.urls),
.....
url(r'^setStime/$',setStime),
url(r'^delS/$',delS),
]

(C).測試:http://127.0.0.1:8000/setStime/
測試:http://127.0.0.1:8000/delS/

(D).在Chrome開發者工具,觀看session變數(發現都不見了)
F12
Appplication
Storage -> Cookies -> http://127.0.0.1:8000


exp05-04.py登入帳號密碼後記錄session,登出後刪除

(3).範例:exp05-04.py(登入帳號密碼後記錄session,登出後刪除session)
(A).在views.py設定函數
程式碼:
def login(request):
if request.method == "POST":
if not 'username' in request.session:
if request.POST['myname'] == 'john' and request.POST['mypw'] == 'john':
request.session['username'] = request.POST['myname']
request.session['password'] = request.POST['mypw']
login = True
message = '歡迎光臨,' + request.session['username'] + '你登入了'
else:
message = '帳號密碼錯誤!'
else:
login = True
message = request.session['username'] + ',你已經在線上了'
return render(request,'login.html',locals())

def logout(request):
if 'username' in request.session:
login = False
message = '再見,' + request.session['username'] + ',你登出了'
del request.session['username']
del request.session['password']
return render(request,'login.html',locals())

(B).在urls.py設定
from app01.views import setS,getS,isMember,setStime,delS,login,logout
urlpatterns = [
path('admin/', admin.site.urls),
.....
url(r'^login/$',login),
url(r'^logout/$',logout),
]

(C).在模板建立login.html
☎注意:用if else 來顯示登入,與登出畫面
{% extends 'base.html' %}
{% block title %}
<TITLE>會員登入</TITLE>
<META content="text/html; charset=utf-8" http-equiv=Content-Type>
{% endblock %}
{% block content %}
<form method="post" name="myform" action=".">
{% csrf_token %}
{% if login == True %}
<a href='/logout/'>登出系統</a>
{% else %}
會員帳號:<input type="text" name='myname' />
<br/>
會員密碼:<input type="text" name='mypw' />
<br/>
<input type="submit" value="登入" />
{% endif %}
</form>
<p style="color: magenta">{{message}}</p>
{% endblock %}

(D).測試:http://127.0.0.1:8000/login/



3. Cookie

3. Cookie
(1).特色與限制:
A.若關閉瀏覽器,cookie還是繼續保存資料
B.可以設定cookie的保存期限
C.每個瀏覽器只能使用300個 cookie
D.每個瀏覽器只能對同一個伺服器存取20個 cookie
E.每個cookie的大小,只有4k Bytes
F.cookie資料被儲存在電腦內,所以容易被分析而竊取。

(2).存取cookie變數方法:(用字典方式存取)
A.設定cookie變數
response.set_cookie(變數,值,max_age = None,expires=None)
例如:
from django.http import HttpResponse
response = HttpResponse('newcookie01')
response.set_cookie('username','john')
response.set_cookie('username','john',max_age=3600) #一個小時=3600秒
max_age = 秒數
expires = 某日的日期時間

B.讀進cookie變數
變數 = request.COOKIES[變數]
例如:
myname = request.COOKIES['username']

(3).設定cookie的期限,刪除cookie的方法
(A).設定cookie的時限:(在views.py函式內)
response.set_cookie(變數,值,max_age = None,expires=None)
max_age = 秒數
expires = 某日的日期時間
例如:response.set_cookie('username','john',max_age=3600) #一個小時=3600秒

(D).刪除指定名稱cookie(在views.py函式內)
delete_cookie(名稱)
例如:
from django.http import HttpResponse
response = HttpResponse('newcookie01')
response.delete_cookie(名稱)

exp05-05.py使用cookie顯示目前瀏覽本頁人數

(4).範例:exp05-05.py(使用cookie來顯示目前瀏覽本頁人數)
(A).在views.py設定函數
☎注意:判別num變數是否在COOIES裡面:if 'num' in request.COOKIES:
☎注意:讀取目前的COOIES變數num:int(request.COOKIES['num'])
☎注意:設定目前最新的COOIES變數num:
rsp = HttpResponse('網頁瀏覽人數 = '+ str(num))
rsp.set_cookie('num',num)

程式碼:
def shownum(request):
if 'num' in request.COOKIES:
num = int(request.COOKIES['num'])
num += 1
else:
num = 1
rsp = HttpResponse('網頁瀏覽人數 = '+ str(num))
rsp.set_cookie('num',num)
return rsp

(B).在urls.py設定
from app01.views import setS,getS,isMember,setStime,delS,login,logout,shownum
urlpatterns = [
path('admin/', admin.site.urls),
......
url(r'^shownum/$',shownum),
]

 
 
chp6. 會員管理套件(auth套件)

下載

下載本章project成果
目錄 設定會員資料管理套件auth 建立會員資料auth exp06-01顯示所有會員的名稱 exp06-02查詢john會員是否存在
寫程式新增一筆使用者User exp06-03新增一筆使用者User 使用者資料表user來進行登入登出 exp06-04使用者資料表user來進行登入登出

設定會員資料管理套件auth

1.設定會員資料管理套件(auth)
(1).安裝 Django auth app
在setting裡面必須設定這兩行
第35行:'django.contrib.auth',
第48行:'django.contrib.auth.middleware.AuthenticationMiddleware',
測試:http://127.0.0.1:8000/admin/
發現:已經有兩個資料表:使用者,群組(這兩個都是auth的內定資料表)
其中的使用者資料表(User),更是重要,裡面可以記錄會員的個人資訊(帳號,密碼)

(2).前置作業
_(A).建立目錄
md chp6
cd chp6
_(B).建立專案
django-admin startproject pj06
cd pj06
_(C).建立應用程式app
python manage.py startapp app01
_(D).修改settings.py
40行:新的app名稱
'app01',

58行:設定templates目錄位置
'DIRS': [os.path.join(BASE_DIR,'templates')],

107行:設定繁體中文,台北語區
LANGUAGE_CODE = 'zh-Hant'
TIME_ZONE = 'Asia/Taipei'

122行:設定static的目錄
STATICFILES_DIRS = [
os.path.join(BASE_DIR,'static'),
]
_(E).到目前專案目錄
cd pj02
建立templates:md templates
建立static:md static

_(F).建立migration資料檔
python manage.py makemigrations

_(G).將模型與資料庫同步
例如:python manage.py migrate

_(H).建立資料庫管理者的帳號與密碼
指令:python manage.py createsuperuser
使用者名稱 (leave blank to use 'administrator'): admin
電子信箱: admin@gmail.com
Password:admin
Password (again):admin
這個密碼與使用者名稱太相近。
這個密碼過短。請至少使用 8 個字元。

_(I).登入資料庫管理者系統
網頁:http://127.0.0.1:8000/admin

建立會員資料auth

2.建立會員資料(auth)
(1).手動建立一個user資料
http://127.0.0.1:8000/admin
登入後,在『使用者』-> 按『新增』
帳號:john
密碼:john963852
☎注意:密碼若是設定太過簡單的(abcd1234,都不會通過)

(2).寫程式讀取目前所有的使用者User
A.語法:
☎讀取所有的會員
from django.contrib.auth.models import User
User.objects.all()

☎讀取所有的會員的名稱(兩種方法)
for i in User.objects.all():
方法一:myname += str(i) + '<br>'
方法二:mynames += i.username + '<br>'

exp06-01顯示所有會員的名稱

(3).範例:exp06-01.py(顯示所有會員的名稱)
(A).在views.py設定函數
from django.contrib.auth.models import User
from django.http import HttpResponse
# Create your views here.
def showall(request):
mynames = ''
for i in User.objects.all():
#myname += str(i) + '<br>'
mynames += i.username + '<br>'
return HttpResponse(mynames)

(B).在urls.py設定
from django.conf.urls import url
from app01.views import showall
urlpatterns = [
path('admin/', admin.site.urls),
url(r'^showall/$',showall),
]

測試:http://127.0.0.1:8000/showall/

exp06-02查詢john會員是否存在

(4).範例:exp06-02.py(查詢john會員是否存在)
(A).在views.py設定函數
from django.contrib.auth.models import User
from django.http import HttpResponse
def find(request):
try:
a1 = User.objects.get(username='john')
return HttpResponse('找到john')
except:
a1 = None
return HttpResponse('查無此人')

(B).在urls.py設定
from django.conf.urls import url
from app01.views import showall
urlpatterns = [
path('admin/', admin.site.urls),
url(r'^find/$',find),
]

測試:http://127.0.0.1:8000/find/

寫程式新增一筆使用者User

(5).寫程式新增一筆使用者User
A.語法:
☎新增一筆的會員宗利
from django.contrib.auth.models import User
a2 = User.objects.create_user('姓名','郵件','密碼')
a2.first_name = '名字'
a2.last_name = '姓'
a2.is_staff = True
a2.save()

☎切換網頁
from django.shortcuts import redirect
return redirect('/函式/')

exp06-03.py新增一筆使用者User

(6).範例:exp06-03.py(新增一筆使用者User)
(A).在views.py設定函數
程式碼:
from django.contrib.auth.models import User
from django.http import HttpResponse
from django.shortcuts import redirect
def add(request):
#要新增一筆:tom
#先判別是否已經存在資料表內
try:
a1 = User.objects.get(username='mike')
except:
a1 = None
#若無,則新增一筆
if a1==None:
a2 = User.objects.create_user('mike','mike@gmail.com','mike963852')
a2.first_name = '麥克'
a2.last_name = '李'
a2.is_staff = True
a2.save()
return redirect('/showall/')
else:
return HttpResponse('mike 已經存在')

(B).在urls.py設定
from django.conf.urls import url
from app01.views import showall,find,add
urlpatterns = [
path('admin/', admin.site.urls),
url(r'^showall/$',showall),
url(r'^find/$',find),
url(r'^add/$',add),
]

測試:http://127.0.0.1:8000/add/

使用者資料表user來進行登入,登出

3.使用者資料表(user)來進行登入,登出
(1).進行登入登出,要做的動作
A.登入時,要先進行會員驗證
from django.contrib.auth import authenticate
from django.contrib import auth
方法:user = auth.authenticate(username=帳號, password=密碼)

B.判別是否通過驗證
方法:if request.user.is_authenticated == True #通過驗證

C.判別是否為通過驗證,且為有效成員(帳號已經啟用)
方法:if user.is_active == True #通過驗證,且帳號已經啟用

☎範例:驗證是否是user資料表成員
a1 = auth.authenticate(username=myname,password=mypw)
#判別是否為有效成員,且通過驗證
if a1 is not None:
if a1.is_active:
☎重點:若是沒有該成員,則a1 = None
☎重點:若是有該成員(通過驗證),且帳號已經啟用,則a1 = True
☎重點:若是有該成員(通過驗證),但帳號還沒開始啟用,則a1 = False

D.成員登入系統
from django.contrib.auth import authenticate
from django.contrib import auth
方法:auth.login(request,user)

E.成員登出系統
方法:auth.logout(request)

exp06-04使用者資料表user來進行登入,登出

(2).範例:exp06-04.py(使用者資料表(user)來進行登入,登出)
(A).在views.py設定函數
☎重點:驗證是否是user資料表成員
a1 = auth.authenticate(username=myname,password=mypw)
#判別是否為有效成員,且通過驗證
if a1 is not None:
if a1.is_active:
☎重點:若是沒有該成員,則a1 = None
☎重點:若是有該成員,且通過驗證,則a1 = True
☎重點:若是有該成員,但沒有通過驗證,則a1 = False

☎注意:切換網頁,有兩種方法(都可以把變數傳遞過去)
方法一:return redirect('/index/')
方法二:return render(request,'index.html',locals())
☎注意:但是return redirect('網頁A'),網頁A不可以說目前自己網頁

程式碼:views.py
from django.contrib.auth.models import User
from django.http import HttpResponse
from django.shortcuts import redirect
def login(request):
mylogin = False
if request.method =='POST':
myname = request.POST['myname']
mypw = request.POST['mypw']
#驗證是否是user資料表成員
a1 = auth.authenticate(username=myname,password=mypw)
#判別是否為有效成員,且通過驗證
if a1 is not None:
if a1.is_active:
auth.login(request,a1)
message = '已經成功登入' return redirect('/index/')
#return render(request,'index.html',locals())
else:
message = '帳號還沒有開始啟用'
else:
message = '沒有這個帳號'
return render(request,'login.html',locals())
#return redirect('/login/')

def logout(request):
auth.logout(request)
#return render(request,'index.html',locals())
return redirect('/index/')

(B).在urls.py設定
from django.conf.urls import url
from app01.views import showall,find,add,index,login,logout
urlpatterns = [
path('admin/', admin.site.urls),
.....
url(r'^login/$',login),
url(r'^logout/$',logout),

(C).首頁index.html
☎重點:在模板要判別是否通過驗證
{% if request.user.is_authenticated == False %}

程式碼:
<!DOCTYPE html>
<htm>
<head>
<meta http-equiv="Content-Type" content="text/html" charset="utf-8">
<title>首頁</title>
</head>
<bod>
{% csrf_token %}
<h1>淘寶網首頁</h1>
{% if request.user.is_authenticated == False %}
<p>你尚未登入</p>
<p></p><a href="/login/">登入</a></p>
{% else %}
<p></p><a href="/logout/">登出</a></p>
{% endif %}
<p></p>
<p style="color: palevioletred">{{ message }}</p>
</body>
</htm>

(D).登入頁login.html
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html" charset="utf-8">
<title>登入頁</title>
</head>
<body>
<form action="" method="post" name='myform'>
{% csrf_token %}
<p>輸入帳號:<input type="text" name="myname" ></p>
<p>輸入密碼:<input type="text" name="mypw" ></p>
<p><input type="submit" name="mysubmit" value="登入" ></p>
</form>
<p style="color: palevioletred">{{ message }}</p>
</body>
</html>


 
 
Chp7.新聞公告系統

下載

下載本章project成果
目錄 前置作業 下載已經建立好的網頁模板:templates,static 瀏覽或修改既有舊的sqlite資料庫 exp07-01顯示NEWSAPP_NEWSUNIT資料表所有資料
資料表共13中查詢(ORM查詢) 資料表的三種常用查詢 三種常用查詢:filter、exclude、get 資料表查詢 vs 排除查詢:比較filter(),exclude()
資料表的排序:order_by() 顯示某個欄位的全部筆數(消除重複資料) 限制查詢結果的筆數數目與起始筆(適用分頁) 資料表的精確查詢 vs 關鍵字查詢
查詢第一筆,最後一筆記錄 連表查詢 複雜查詢:Q查询 exp07-02讀取新聞資料庫,一頁顯示8筆,上下頁瀏覽
exp07-03完整新聞發布系統:可會員登入,可編輯,新增,刪除新聞

1.前置作業

1.前置作業
_(A).建立目錄
_(B).建立專案
django-admin startproject pj07
cd pj07
_(C).建立應用程式app
python manage.py startapp app01
_(D).修改settings.py
40行:新的app名稱
'app01',

58行:設定templates目錄位置
'DIRS': [os.path.join(BASE_DIR,'templates')],

107行:設定繁體中文,台北語區
LANGUAGE_CODE = 'zh-Hant'
TIME_ZONE = 'Asia/Taipei'

122行:設定static的目錄
STATICFILES_DIRS = [
os.path.join(BASE_DIR,'static'),
]
_(E).到目前專案目錄
建立templates:md templates
建立static:md static

_(F).建立migration資料檔
python manage.py makemigrations

_(G).將模型與資料庫同步
例如:python manage.py migrate

_(H).建立資料庫管理者的帳號與密碼
指令:python manage.py createsuperuser
使用者名稱 (leave blank to use 'administrator'): admin
電子信箱: admin@gmail.com
Password:aa123456
Password (again):aa123456
這個密碼與使用者名稱太相近。
這個密碼過短。請至少使用 8 個字元。

_(I).登入資料庫管理者系統
網頁:http://127.0.0.1:8000/admin

下載已經建立好的網頁模板:templates,static

2.下載已經建立好的網頁模板:templatesstatic
複製,覆蓋templates,static

3.下載已經建立好的SQLite資料庫:db.sqlite3
(帳號:admin,密碼:aa123456)
到pj07目錄
複製覆蓋原有的db.sqlite3

瀏覽或修改既有舊的sqlite資料庫

4.如何瀏覽,或修改既有舊的sqlite資料庫
(1).到sqlite官網,下載sqlite資料庫瀏覽器
https://sqlitebrowser.org/dl/

(2).安裝後,開啟資料庫
在browse data按鈕,選擇資料表:newsapp_newsunit
可以看到21筆資料

選擇一筆資料,然後修改內容

5.使用inspectdb將舊的sqlite資料庫,建立相對應的models.py
☎注意:這個models.py的目錄位置不對,還要移動

☎指令:
python manage.py inspectdb > models.py

☎複製chp7\pj07的models.py
覆蓋到,chp7\pj07\app01的models.py
覆蓋models.py

6.編輯models.py,加上二行指令(def __str__(self))
class NewsappNewsunit(models.Model):
nickname = models.CharField(max_length=20)
title = models.CharField(max_length=50)
message = models.TextField()
pubtime = models.DateTimeField()
enabled = models.BooleanField()
press = models.IntegerField()
catego = models.CharField(max_length=10)

class Meta:
managed = False
db_table = 'newsapp_newsunit'
def __str__(self):
return self.title

7.編輯admin.py
from django.contrib import admin
from app01 import models
# Register your models here.
admin.site.register(models.NewsappNewsunit)

_(F).建立migration資料檔
python manage.py makemigrations

_(G).將模型與資料庫同步
例如:python manage.py migrate

_(J).登入資料庫管理者系統
網頁:http://127.0.0.1:8000/admin

結果:發現一個舊的資料表:NEWSAPP NEWSUNIT
裡面有18筆記錄

exp07-01顯示NEWSAPP_NEWSUNIT資料表所有資料

8.自行撰寫程式,讀取外來資料庫
(1).範例:exp07-01.py(顯示NEWSAPP_NEWSUNIT資料表所有資料,並可以編輯修改)
(A).在views.py設定函數
☎注意:欄位名稱在admin裡面顯示都會是以大寫開頭(Title),但是實際欄位卻是title

views.py程式碼:
from django.shortcuts import redirect
from app01.models import NewsappNewsunit as news
def showall(request):
items = news.objects.all()
return render(request,'showall.html',locals())
def edit(request):
if request.method=='POST':
id = request.POST['id']
recd = news.objects.get(id=id)
recd.title = request.POST['title']
recd.catego = request.POST['catego']
recd.message = request.POST['message']
recd.nickname = request.POST['nickname']
recd.press = request.POST['press']
try:
recd.save()
return redirect('/showall/')
except:
message01 = '修改資料發生錯誤'
return render(request,'edit.html',locals())
#return redirect('/showall/')
elif request.method=='GET':
myid = request.GET['id']
items = news.objects.get(id=myid)
id = items.id
title = items.title
catego = items.catego
message = items.message
nickname = items.nickname
press = items.press
return render(request,'edit.html',locals())

(B).在urls.py設定
from app01.views import index,showall,edit
urlpatterns = [
path('admin/', admin.site.urls),
url(r'^$',index),
url(r'^showall/$',showall),
url(r'^edit/$',edit),
]

(C).顯示全部資料網頁showall.html
{% extends 'base.html' %}
{% block title %}
<title>顯示所有新聞</title>
{% endblock %}

{% block content %}
<h1>新聞列表</h1>
{% csrf_token %}
<table border='1' cellsapcing='0' cellpadding='0' >
<th>標題</th><th>分類</th><th>訊息</th><th>發表者</th><th>點閱</th><th>修改</th><th>刪除</th>
{% for item in items %}
<tr>
<td>{{item.title}}</td>
<td>{{item.catego}}</td>
<td>{{item.message}}</td>
<td>{{item.nickname}}</td>
<td>{{item.press}}</td>
<td><a href='/edit/?id={{item.id}}'>編輯</a></td>
<td><a href='/del/?id={{item.id}}'>刪除</a></td>
</tr>
{% endfor %}

</table>
<p style="color: magenta">{{message01}}</p>
{% endblock %}

(D).編輯一筆資料網頁edit.html
{% extends 'base.html' %}
{% block title %}
<title>修改資料</title>
{% endblock %}

{% block content %}
<h1>修改新聞資料</h1>
<form name='myform' action="" method="POST">
{% csrf_token %}
<table border='1' cellsapcing='0' cellpadding='0' >
<tr>
<td>編號</td><td><input type="text" name='id' readonly value="{{id}}"></td>
</tr>
<tr>
<td>標題</td><td><input type="text" name='title' value="{{title}}"></td>
</tr>
<tr>
<td>分類</td><td><input type="text" name='catego' value="{{catego}}"></td>
</tr>
<tr>
<td>訊息</td><td><input type="text" name='message' value="{{message}}"></td>
</tr>
<tr>
<td>發表者</td><td><input type="text" name='nickname' value="{{nickname}}"></td>
</tr>
<tr>
<td>點閱</td><td><input type="text" name='press' value="{{press}}"></td>
</tr>
</table>
<p></p>
<input type="submit" name='bnt1' value="確認修改">
<p></p>
<p style="color: magenta">{{message01}}</p>
</form>
{% endblock %}


資料表共13中查詢(ORM查詢)

9.資料表共13中查詢(ORM查詢)
一,傳統的資料庫查詢語法:SQL查詢語法
二,Django的查詢稱為:ORM查詢,有13種查詢
(1).all(): 查詢所有結果
(2).filter(**kwargs): 它包含了與所給篩選條件相匹配的物件
(3).get(**kwargs): 返回與所給篩選條件相匹配的物件,返回結果有且只有一個,如果符合篩選條件的物件超過一個或者沒有都會丟擲錯誤。
(4).exclude(**kwargs): 它包含了與所給篩選條件不匹配的物件
(5).values(*field): 返回一個ValueQuerySet——一個特殊的QuerySet,執行後得到的並不是一系列model的例項化物件,而是一個可反覆運算的字典序列
(6).values_list(*field): 它與values()非常相似,它返回的是一個元組序列,values返回的是一個字典序列
(7).order_by(*field): 對查詢結果排序
(8).reverse(): 對查詢結果反向排序,請注意reverse()通常只能在具有已定義順序的QuerySet上呼叫(在model類的Meta中指定ordering或呼叫order_by()方法)。
(9).distinct(): 從返回結果中剔除重複紀錄(如果你查詢跨越多個表,可能在計算QuerySet時得到重複的結果。此時可以使用distinct(),注意只有在PostgreSQL中支援按欄位去重。)
(10).count(): 返回資料庫中匹配查詢(QuerySet)的物件數量。
(11).first(): 返回第一條記錄
(12).last(): 返回最後一條記錄
(13).exists(): 如果QuerySet包含資料,就返回True,否則返回False

三,何謂ORM,Object Relational Mapping = 物件關聯對映
ORM,英文錯誤 Object Relational Mapping,
中文稱為:物件關聯對映。
ORM 在網站開發結構中,是在『資料庫』和『 Model 資料容器』兩者之間,將關聯式資料庫映射至物件導向的資料抽象化技術
簡單來說,它是一個幫助使用者更簡便、安全的去從資料庫讀取資料,
其理念是將資料庫的內容映射為物件,讓程式開發人員可以用操作物件的方式對資料庫進行操作,而不直接使用SQL語法對資料庫進行操作
因為 ORM 的一個特性為: 透過程式語言(Ruby, Java),去操作資料庫語言( SQL )。
而這也是實作了物件導向的概念,產生的一種工具模式

四,ORM的優缺點
(1).優點
_(A).安全性:有一種常見的網路攻擊叫做 SQL 注入( SQL injection ),就是駭客在傳輸到網站伺服器裡的資料直接寫 SQL ,
_(B).簡化性:程式碼簡單
_(C).通用性:網站未來有資料庫轉移的問題,也比較不會遇到需要改寫程式的狀況。因為不同的資料庫間,SQL 語句的語法也會稍有差異,
例如:比較下麵 MySQL 和 MsSQL 做兩件同樣事
// MySQL
SELECT * FROM TestTable WHERE id=12 LIMIT 10
// MsSQL
SELECT TOP 10 * FROM TestTable WHERE id=12
這兩個程式碼都要做同一件事,可是寫法會有所不同,
但是使用 ORM 就比較不會有這個狀況,

(2).缺點
_(A).效能差:當ORM達成了方便性,通常都會犧牲到效能的問題,
_(B).學習曲線高
_(C).複雜查詢維護性低:目前若是簡單的查詢,ORM還能完成,但是對於複雜的查詢,ORM 的使用上就較為力不從心。

資料表的三種常用查詢

10.資料表的三種常用查詢:(比較get(),filter()的差別)
(1).三種方法:
方法1:items = news.objects.all(),顯示所有資料列表list
方法2:items = news.objects.filter(name='john'),查詢結果也是list(結果可是多個:ltems[0], itmes[1],...)
方法3:items = news.objects.get(name='john'),(結果只能唯一的一個:ltems),但若是查不到會報錯,所以要用try..except

(2).方法1:items = news.objects.all(),顯示所有資料列表list
查詢結果有多個::ltems[0], itmes[1],...
若是沒有資料,不會報錯
所以使用news.objects.all(),不用配合try...except...

例如:
def show_all(request):
items = student.objects.all().order_by('-id')
return render(request,'show_all.html',locals())

(3).方法2:items = news.objects.filter(name='john')
查詢結果也是list
所以結果可是多個:ltems[0], itmes[1],...
若是沒有資料,不會報錯
所以使用news.objects.filter(...),不用配合try...except...

例如:
objs = MyModel.objects.filter(id=1)
if len(objs) == 1:
obj = objs[0]
else:
message = '沒有找到資料'

(4).方法3:items = news.objects.get(name='john'),
☎結果只能唯一的一個:ltems,
☎但若是查不到會報錯,所以.get(..)一定要配合用try..except
☎應用:因為刪除(delete)資料表,修改(update)資料表,都要配合objects.get(id=..)先查詢,然後在delete(),或是save()修改,
所以刪除(delete)資料表,修改(update)資料表,在使用.get()時,也要配合配合try...except...

例如:查詢
def show_one(request):
#讀取一筆資料:cname =張三
try:
item = student.objects.get(cname='張三')
except Exception as e:
errormsg = '讀取資料出現錯誤:' + e
return render(request,'show_one.html',locals())

例如:刪除
recd = stu.objects.get(編號=myid)
recd.delete()

例如:修改
recd = stu.objects.get(id=myid)
recd.cname = request.POST['myname']
recd.save()

三種常用查詢:filter、exclude、get

12.三種常用查詢:filter、exclude、get (1).在Django中,查詢一般就是使用filter、exclude、get三個方法來實現
(2).在mysql中,想要查詢數據,就需要使用where關鍵字加上字段條件去查詢,
(3).在Django的orm之中,查詢經常使用filter、exclude、get關鍵詞加上field+__+condition作為關鍵詞去查詢

資料表查詢 vs 排除查詢:比較filter(),exclude()

13.資料表查詢 vs 排除查詢:(比較filter(),exclude())
(1).filter表示=,exclude表示 !=

(2).查詢:filter(**kwargs)
可以根據代入的參數來決定輸出的物件。
例如:
objs = MyModel.objects.filter(id=1)
if len(objs) == 1:
obj = objs[0]
else:
message = '沒有找到資料'

(3).排除查詢:exclude(**kwargs)
輸出排除輸入的參數以外的物件。

例如:sut.objects.filter(name='john')
=> 列出名稱為john的 物件

例如:stu.objects.exclude(name='john')
=> 列出名稱為非john的物件

資料表的排序:order_by()

14.資料表的排序:order_by()
(1).語法:order_by('a','b','c'...)
將搜尋出來的QuerySet利用order_by的順序再次排序。
例如:
stu.objects.filter(sex='M').order_by('-height', 'name')
將stu的Object利用filter搜尋出來之後,再將此QuerySet按照height降冪,name升冪的方式排序


15.查詢少用的指令
(1).查詢資料是否存在:
語法:exist()
回傳True, 如果QuerySet存在

(2).消除重複資料
語法:distinct()

當搜尋多個Table時,有可能會出現重複的資料,利用 distinct() 即可以消除重複的項目。

顯示某個欄位的全部筆數(消除重複資料)

16.如何顯示某個欄位的全部筆數(消除重複資料)
(1).傳統SQL語法只顯示name欄位:
select distinct name from Author
select distinct name,email from Author

(2).django的ORM寫法:
a = Author.objects.values_list(name).distinct()
b = Author.objects.values_list(name,email).distinct()

(3).兩種語法與後續的取值:
#若要讀取某個欄位catego的所有欄位值select catego form news = 有兩種方法:
(兩種方法的功能相同,只是寫法不同)
☎方法1:a1 = news.objects.values('catego').distinct()
☎方法2:a1 = news.objects.values_list('catego').distinct()

_(A).方法一:
☎方法1:a1 = news.objects.values('catego').distinct()
django讀值方法 = a1['catego']

在模板網頁讀值 = item.catego
{% for item in a1 %}
<option>{{item.catego}}</option>
{% endfor %}

_(B).方法二:
☎方法2:a1 = news.objects.values_list('catego').distinct()
讀值方法 = a1[0]

在模板網頁讀值 = item
{% for item in a1 %}
<option>{{item}}</option>
{% endfor %}

限制查詢結果的筆數數目與起始筆(適用分頁)

17.限制查詢結果的筆數數目與起始筆(適用分頁)
(1).取得前8筆記錄:[:8]
語法:資料表物件.objects.all()[:n]
例如:stu.objects.all()[:8]

(2).取得第8筆~第16記錄:[8:16]
語法:資料表物件.objects.all()[m:n]
例如:stu.objects.all()[8:16]

(3).取得最後8筆記錄:[8:]
語法:資料表物件.objects.all()[n:]
例如:stu.objects.all()[8:]

資料表的精確查詢 vs 關鍵字查詢

18.資料表的:『精確查詢』 vs 『關鍵字查詢』
(1).精確查詢:__exact
例如
a1 = stu.objects.filter(name='王五')
或是
a1 = stu.objects.filter(name__exact='王五')
顯示:王五的記錄

(2).關鍵字查詢:__contains
_(A).contains:在mysql中相當於‘like‘模糊查詢,
但是在這裏值的前後都會加上%,意思是要查詢的字段中是否包含某個字符串,
這個條件過濾時是大小寫敏感的,也就是轉化成原生SQL的時候會在值的前面加上BINARY關鍵字:
例如
a1 = stu.objects.filter(name__contains='王')
顯示有關鍵字:王的所有記錄

例如:
a1 = 論文.objects.filter(title__contains='鋼鐵')
對應的的SQL語法:
SELECT `article`.`id`, `article`.`title`, `article`.`content` FROM `論文` WHERE `論文`.`title` LIKE BINARY %鋼鐵%


19.欄位查詢常用指令:
(1).語法:查詢格式:field__lookuptype=value

(2).數字,日期範圍的查詢,可以使用的指令:
GT (Greater than): 大於
LT (Less than): 小於
GTE (Greater Than or Equal): 大於或等於
LTE (Less Than or Equal): 小於或等於

(3).名稱的查詢可以使用:
startswith: 大小寫,開頭的字串相符
istartswith: 大小寫不須一樣,開頭的字串相符
endswith: 大小寫,結尾的字串相符
iendswith: 大小寫不須一樣,結尾的字串相符
exact: 精確的比對
iexact: 不精確的比對(大小寫不須相同)
contains: 包含此文字

(4).其它查詢:
__in 存在於一個list範圍內
__range 在…範圍內
__year 日期欄位的年份
__month 日期欄位的月份
__day 日期欄位的日
__isnull=True/False

(5).範例: # 查詢id大於1 且 小於10的值
models.Tb1.objects.filter(id__lt=10, id__gt=1)

# 查詢id等於11、22、33的資料
models.Tb1.objects.filter(id__in=[11, 22, 33])
# not in
models.Tb1.objects.exclude(id__in=[11, 22, 33])

# 關鍵字查詢name欄位包含"ven"的
models.Tb1.objects.filter(name__contains="ven")
# 關鍵字查詢name欄位包含"ven"的(但是icontains大小寫不敏感)
models.Tb1.objects.filter(name__icontains="ven")

# 查詢id範圍是1到3的,等價於SQL的bettwen and
models.Tb1.objects.filter(id__range=[1, 3])

類似的還有:startswith,istartswith, endswith, iendswith 

#查詢date欄位(2019年)
models.Class.objects.filter(first_day__year=2019)

查詢第一筆,最後一筆記錄

20.查詢第一筆,最後一筆記錄
(1).語法:
stu.objects.first()
stu.objects.last()

例如:
# 第一本書物件
book_obj = models.Book.objects.first()

連表查詢

21.連表查詢
(1).有兩個資料表類別,彼此關聯,可以進行關聯查詢
範例一:
class A(models.Model):
name = models.CharField()
class B(models.Model):
aa = models.ForeignKey(A)

關聯查詢:通过B的外键找到A中name字段包含test内容的数据
B.objects.filter(aa__name__contains='test')

(2).範例二
class A(models.Model):
name = models.CharField()
class B(models.Model):
aa = models.ForeignKey(A,related_name="FAN")
bb = models.CharField()
關聯查詢:反向查询,查询出所有(B.aa=A且B.bb=XXXX)的A实例
A.objects.filter(FAN__bb='XXXX')

複雜查詢:Q查询

22.複雜查詢:Q查詢
(1).功能:
當filter方法中有多個欄位篩選時,是使用AND將其連接在一起的,
但如果想要更複雜的過濾條件(OR),這時候就必須用Django為提供的Q查詢

(2).語法範例:
from django.db.models import Q
Q(name__contains='ang')

邏輯運算:在filter中的多個欄位過濾是使用AND連接的,而OR或其他邏輯運算無法在filter中使用,
而Q物件之間可以使用如|、&、~等邏輯運算,

(2).『或,or』查詢的範例:|
例如:
from django.db.models import Q
Q(name__contains='Z') | Q(name_contains='Q')

#等同於下麵的WHERE子句
WHERE name LIKE '%Z%' OR name LIKE '%Q%'

(3).『且,and』查詢的範例:&&
#查找不以z開頭並且名稱中包含有a或b的書籍
for book in Book.objects.filter(
~ Q(name__startswith='z') && (Q(name__contains='a') | Q(name__contains='b'))
):
print(book)

(4).使用查詢對象:
所有接受關鍵字參數的查找方法,例如get/exclude/filter等都可以使用Q物件,多個Q物件之間如果沒有使用邏輯運算,則會被以AND連接,如果Q物件和普通關鍵字參數混在一起,Q對象要放在普通關鍵字前面,
例如:
Book.objects.filter(Q(pubdate__year=2019) | Q(pubdate__day=31) , name__contains='z')

exp07-02讀取新聞資料庫,一頁顯示8筆,上下頁瀏覽

23.寫程式,讀取新聞資料庫,一頁顯示8頁,上頁,下頁瀏覽,並且可以觀看新聞內容
(1).範例:exp07-02.py
(A).在views.py設定函數(page1,detail)
☎注意:兩種GET接收變數的方法:
#若是由form傳來get變數:request.GET['pagebtn']
#若是由網址?pagebtn=..傳來的get變數:request.GET.get('pagebtn')

☎注意:網址傳來筆數,一律都是文字(就算是數字,也是文字)== '1'
例如:
(正確)if request.GET.get('pagebtn') == '1':
(錯誤)if request.GET.get('pagebtn') == 1:

☎注意:指定查詢結果的筆數數目與起始筆(適用分頁)
startnum = (pagenum-1)*pagesize
endnum = pagenum*pagesize
items = news.objects.filter(enabled=True).order_by('id')[startnum:endnum]

☎注意:由目前pagenum來計算相關顯示數據
startnum = (pagenum-1)*pagesize
endnum = pagenum*pagesize
items = news.objects.filter(enabled=True).order_by('id')[startnum:endnum]

☎注意:全域變數的使用方法
☎注意:網站不要用全域變數global1
原因:因為在個人主機雖然正常,但在專業主機如heroku,全域變數會亂變,跳來跳去,
解決方法:所以還是要用session變數,數據才穩

pagenum = 1
def page1(request):
global pagenum

程式碼:
pagenum = 1
def page1(request): global pagenum
pagesize = 8
#可以顯示的必須enabled=True
items = news.objects.filter(enabled=True)
#計算筆數兩種方法:(1).items.count()。(2)len(items)
#totalnum = len(items)
totalnum = items.count()
#totalpagenum = totalnum//pagesize
totalpagenum = math.ceil(totalnum/pagesize)

#下一頁
#若是由form傳來get變數:request.GET['pagebtn']
#若是由網址?pagebtn=..傳來的get變數:request.GET.get('pagebtn')
#網址傳來筆數,一律都是文字(就算是數字,也是文字)== '1'
#由目前pagenum來計算相關顯示數據
startnum = (pagenum-1)*pagesize
endnum = pagenum*pagesize
items = news.objects.filter(enabled=True).order_by('id')[startnum:endnum]
#若是下一頁,上一頁,再修改所要顯示的數據
if request.GET.get('pagebtn') == '1':
if pagenum <= totalpagenum-1:
pagenum += 1
startnum = (pagenum-1)*pagesize
endnum = pagenum*pagesize
items = news.objects.filter(enabled=True).order_by('id')[startnum:endnum]
#上一頁
elif request.GET.get('pagebtn') == '-1':
if pagenum >= 2:
pagenum -= 1
startnum = (pagenum-1)*pagesize
endnum = pagenum*pagesize
items = news.objects.filter(enabled=True).order_by('id')[startnum:endnum]
#把全域變數設定到local筆數
currentpagenum = pagenum
return render(request,'page1.html',locals())

----------------
☎注意:使用filter查詢的寫法:
item = news.objects.filter(id=...)
if len(item)>0:
☎注意:計算筆數的兩種寫法:
方法一:len(item)
方法二:item.count()

☎注意:若用filter查詢,結果是個list陣列,第一筆資料為item[0](get查詢不是list陣列)
例如:
item = news.objects.filter(id=id)
title = item[0].title

def detail(request):
id = request.GET.get('id')
item = news.objects.filter(id=id)
if len(item)>0:
#注意:若用filter查詢,結果是個list陣列,第一筆資料為item[0](get查詢不是list陣列)
title = item[0].title
catego = item[0].catego
message = item[0].message
nickname = item[0].nickname
pubtime = item[0].pubtime
pubtime = item[0].pubtime
else:
message01 = '找不到資料'
return render(request,'detail.html',locals())

(B).在urls.py設定
from app01.views import index,showall,edit,page1,detail
urlpatterns = [
path('admin/', admin.site.urls),
url(r'^$',index),
....
url(r'^page1/$',page1),
url(r'^detail/$',detail),
]

(C).顯示全部資料網頁page1.html
☎注意:for 資料表筆若是沒有資料的處理:empty
{% for item in items %}
。。。。。。
{% empty %}
。。。。。。
{% endfor %}

☎注意:顯示圖片時會用到static參數來指定圖片目錄
注意格式語法:
{% load staticfiles %}
<img src='{% static "images/prevpage.png" %}'>
<br> 程式碼:
{% extends 'base.html' %}
{% load staticfiles %}
{% block title %}
<title>顯示所有新聞</title>
{% endblock %}

{% block content %}
<div class="contentbox">
<h1>新聞列表</h1>
{% csrf_token %}
<table>
<th>分類</th><th>標題</th><th>發表時間</th><th>點閱</th><th>修改</th><th>刪除</th>
{% for item in items %}
<tr>
<td><div class="typeblock">{{item.catego}}</div></td>
<td><a href='/detail/?id={{item.id}}'>{{item.title}}</a></td>
<td>{{item.pubtime}}</td>
<td>{{item.press}}</td>
<td><a href='/edit/?id={{item.id}}'>編輯</a></td>
<td><a href='/del/?id={{item.id}}'>刪除</a></td>
</tr>
{% empty %}
<div class="status warning">
<img src='{% static "images/icon_warning.png" %}'>
<span>目前新聞資料庫中沒有任何資料!</span>

</div>
{% endfor %}
</table>
<div class="topfunction">
{% if currentpagenum >= 2 %}
<a href='/page1/?pagebtn=-1'><img src='{% static "images/prevpage.png" %}' alt='上一頁'></a>
{% endif %}
{% if currentpagenum < totalpagenum %}
<a href='/page1/?pagebtn=1'><img src='{% static "images/nextpage.png"%}' alt='下一頁'></a>
{% endif %}
</div>
<p style="color: magenta">{{message01}}</p>
</div>
{% endblock %}

(D).瀏覽一筆詳細資料網頁detail.html
程式碼:
{% extends "base.html" %}
{% load staticfiles %}
{% block content %}
<div class="contentbox">
<table width="100%">
<tr>
<th align="left"><span class="typeblock">{{catego}}  </span>  {{title}}</th>
</tr>
<tr>
<td>
<span class="newsinfo">
<img src="{% static "images/date.png" %}" alt="" width="16" height="16" /> {{pubtime}} 
<img src="{% static "images/user.png" %}" alt="" width="16" height="16" /> {{nickname}}
<p>  {{message}}</p>
</span>
</td>
</tr>
</table>
<div class="topfunction">
<a href="/page1/" title="返回首頁">
<img src="{% static "images/home.png" %}" alt="返回首頁" width="86" height="32" /></a>
</div>
<p style="color: magenta">{{message01}}</p>
</div>
{% endblock %}


exp07-03完整新聞發布系統:可會員登入,可編輯,新增,刪除新聞

24.寫程式,完整新聞發布系統(若是會員登入,可以編輯,新增,刪除新聞)
(1).範例:exp07-03.py
☎結構:page2,detail2就跟前面一樣,只是加上一個login的登入會員帳號按鈕
☎結構:若是login2登入後,就會顯示page_admin2,del2,edit2,add2

(A).在urls.py設定
from app01.views import index,showall,edit,page1,detail,page2,detail2,login2,page_admin2,logout2,edit2,del2,add2
urlpatterns = [
path('admin/', admin.site.urls),
url(r'^$',index),
.....
url(r'^page2/$',page2),
url(r'^detail2/$',detail2),
url(r'^login2/$',login2),
url(r'^page_admin2/$',page_admin2),
url(r'^logout2/$',logout2),
url(r'^edit2/$',edit2),
url(r'^edit2/(\w+)/$',edit2),
url(r'^del2/(\w+)/$',del2),
url(r'^del2/$',del2),
url(r'^add2/$',add2),
]

(B).在views.py設定函數(base2,page2,detail2,login2,page_admin2,del2,edit2,add2)
程式碼:
#page2是一般瀏覽者都可以看到的網頁資料(只是在右上加個登入管理者按鈕)
pagenum2 = 1
def page2(request):
global pagenum2
pagesize = 8
#可以顯示的必須enabled=True
items = news.objects.filter(enabled=True).order_by('-id')
totalnum = items.count()
totalpagenum = math.ceil(totalnum/pagesize)

#下一頁
#若是由form傳來get變數:request.GET['pagebtn']
#若是由網址?pagebtn=..傳來的get變數:request.GET.get('pagebtn')
#網址傳來筆數,一律都是文字(就算是數字,也是文字)== '1'
#由目前pagenum2來計算相關顯示數據
startnum = (pagenum2-1)*pagesize
endnum = pagenum2*pagesize
items = news.objects.filter(enabled=True).order_by('-id')[startnum:endnum]
#若是下一頁,上一頁,再修改所要顯示的數據
if request.GET.get('pagebtn') == '1':
if pagenum2 <= totalpagenum-1:
pagenum2 += 1
startnum = (pagenum2-1)*pagesize
endnum = pagenum2*pagesize
items = news.objects.filter(enabled=True).order_by('-id')[startnum:endnum]
#上一頁
elif request.GET.get('pagebtn') == '-1':
if pagenum2 >= 2:
pagenum2 -= 1
startnum = (pagenum2-1)*pagesize
endnum = pagenum2*pagesize
items = news.objects.filter(enabled=True).order_by('-id')[startnum:endnum]
#把全域變數設定到local筆數
currentpagenum = pagenum2
return render(request,'page2.html',locals())

☎注意:這邊測試用filter查詢,結果要用item[0]
def detail2(request):
id = request.GET.get('id')
item = news.objects.filter(id=id)
if len(item)>0:
#注意:若用filter查詢,結果是個list陣列,第一筆資料為item[0](get查詢不是list陣列)
title = item[0].title
catego = item[0].catego
message = item[0].message
nickname = item[0].nickname
pubtime = item[0].pubtime
pubtime = item[0].pubtime
else:
message01 = '找不到資料'
return render(request,'detail2.html',locals())

☎注意:驗證會員身份是否通過的公式:
user = auth.authenticate(username=username,password=password)
if user is not None:
if user.is_active:
auth.login(request,user)
def login2(request):
if request.method == 'POST':
username = request.POST['username']
password = request.POST['password']
message01 = username
#驗證是否為會員
user = auth.authenticate(username=username,password=password)
if user is not None:
if user.is_active:
auth.login(request,user)
message01 = '已經成功登入'
return redirect('/page_admin2/')
else:
message01 = '帳號尚未被啟用'
else:
message01 = '沒有這個帳號,登入錯誤'
return render(request,'login2.html',locals())

☎注意:管理者登入後,顯示新增,修改,刪除按鈕,而且顯示筆數不完全是enabled=true,而是全部消失
pagenum3=1
def page_admin2(request):
global pagenum3
pagesize = 8
items = news.objects.all().order_by('-pubtime')
totalnum = items.count()
totalpagenum = math.ceil(totalnum/pagesize)

#由目前pagenum3來計算相關顯示數據
startnum = (pagenum3-1)*pagesize
endnum = pagenum3*pagesize
items = news.objects.all().order_by('-pubtime')[startnum:endnum]
#若是下一頁,上一頁,再修改所要顯示的數據
if request.GET.get('pagebtn') == '1':
if pagenum3 <= totalpagenum-1:
pagenum3 += 1
startnum = (pagenum3-1)*pagesize
endnum = pagenum3*pagesize
items = news.objects.all().order_by('-pubtime')[startnum:endnum]
#上一頁
elif request.GET.get('pagebtn') == '-1':
if pagenum3 >= 2:
pagenum3 -= 1
startnum = (pagenum3-1)*pagesize
endnum = pagenum3*pagesize
items = news.objects.all().order_by('-pubtime')[startnum:endnum]
#把全域變數設定到local筆數
currentpagenum = pagenum3
return render(request,'page_admin2.html',locals())

def logout2(request):
auth.logout(request)
return redirect('/page2/')

☎注意:傳遞變數用雙參數,不是用?id=...
要鑑別兩種情形(有值,無值)
if id is not None:
elif id is None:
☎注意:讀取模板網頁幾種特殊的元件(select,texarea,radio)
☎讀取select的option值,直接POST[name]
recd.catego = request.POST['catego']

☎讀取textarea的值,直接POST[name]
recd.nickname = request.POST['nickname']

☎讀取radiobutton,乃是讀取radio-name值(不是id),因為有兩個radio,所以只能靠radio-value來鑑別了
#若radio-value = 'yes',則設定recd.enabled = True
yesno = request.POST['enabled']
if yesno=='yes':
recd.enabled = True
else:
recd.enabled = False
☎讀取目前某個欄位(catego),並且消除重複值
#若要讀取某個欄位catego的所有欄位值select catego form news = 有兩種方法:
#方法1:a1 = news.objects.values('catego').distinct(),讀值方法 = a1['catego']。(在模板網頁 = a1.catego)
#方法2:a1 = news.objects.values_list('catego').distinct(),讀值方法 = a1。(在模板網頁 = a1)
categos = news.objects.values('catego').distinct()
categos = news.objects.values_list('catego').distinct()

def edit2(request,id=None):
if id is not None:
if request.method=='POST':
recd = news.objects.get(id=id)
recd.title = request.POST['title']
#讀取select的option值,直接POST[name]
recd.catego = request.POST['catego']
recd.message = request.POST['message']
#讀取textarea的值,直接POST[name]
recd.nickname = request.POST['nickname']
recd.press = request.POST['press']
#讀取radiobutton,乃是讀取radio-name值(不是id),因為有兩個radio,所以只能靠radio-value來鑑別了
#若radio-value = 'yes',則設定recd.enabled = True
yesno = request.POST['enabled']
if yesno=='yes':
recd.enabled = True
else:
recd.enabled = False
try:
recd.save()
return redirect('/page_admin2/')
except:
message01 = '修改資料發生錯誤'
return render(request,'edit2.html',locals())
else:
#取得所有的catego
#消除重複資料語法:distinct()
#若要讀取某個欄位catego的所有欄位值select catego form news = 有兩種方法:
#方法1:a1 = news.objects.values('catego').distinct(),讀值方法 = a1['catego']。(在模板網頁 = a1.catego)
#方法2:a1 = news.objects.values_list('catego').distinct(),讀值方法 = a1。(在模板網頁 = a1)
categos = news.objects.values('catego').distinct()
#categos = news.objects.values_list('catego').distinct()
items = news.objects.get(id=id)
id = items.id
title = items.title
catego = items.catego
message = items.message
nickname = items.nickname
press = items.press
enabled = items.enabled
return render(request,'edit2.html',locals())
elif id is None:
message01 = '沒有給定要顯示的id'
#return redirect('/page_admin2/')
return render(request,'edit2.html',locals())

☎注意:傳遞變數用雙參數,不是用?id=...
要鑑別兩種情形(有值,無值)
if id is not None:
elif id is None:
def del2(request,id=None):
if id is not None:
recd = news.objects.get(id=id)
try:
recd.delete()
return redirect('/page_admin2/')
except:
message01 = '刪除發生錯誤'
return render(request,'page_admin2.html',locals())
elif id is None:
message01 = '沒有給定要刪除的id'
return redirect('/page_admin2/')
#return render(request,'page_admin2.html',locals())

☎注意:新增一般記錄說,某個非null欄位,一定要給值
☎注意:時間欄位給定目前時間:pubtime = datetime.now()
def add2(request):
if request.method=='POST':
title = request.POST['title']
catego = request.POST['catego']
message = request.POST['message']
nickname = request.POST['nickname']
press = 0
yesno = request.POST['enabled']
#讀取radiobutton,乃是讀取radio-name值(不是id),因為有兩個radio,所以只能靠radio-value來鑑別了
#若radio-value = 'yes',則設定recd.enabled = True
if yesno=='yes':
enabled = True
else:
enabled = False
#pubtime欄位不可以為null,一定要給值
pubtime = datetime.now()
recd = news.objects.create(title=title,catego=catego,message=message,nickname=nickname,press=press,enabled=enabled,pubtime=pubtime)
try:
recd.save()
return redirect('/page_admin2/')
except:
message01 = '新增一筆資料發生錯誤'
return render(request,'add2.html',locals())
else:
#message01 = '無法新增資料'
categos = ['公告','更新','活動','其它']

return render(request,'add2.html',locals())

(C).顯示全部資料網頁page2.html
☎注意:在block login加入登入的按鈕
{% extends 'base2.html' %}
{% load staticfiles %}

{% block login %}
<div align='right'>
<a href="/login2/" title="登入管理介面">
<img src='{% static "images/Lock.png" %}' alt="登入管理介面"/></a>
</div>
{% endblock %}

{% block content %}
<div class="contentbox">
<h1>新聞列表</h1>
{% csrf_token %}
<table width='100%'>
<th>分類</th><th>標題</th><th>發表時間</th><th>點閱</th>
{% for item in items %}
<tr>
<td><div class="typeblock">{{item.catego}}</div></td>
<td><a href='/detail2/?id={{item.id}}'>{{item.title}}</a></td>
<td>{{item.pubtime}}</td>
<td>{{item.press}}</td>
</tr>
{% empty %}
<div class="status warning">
<img src='{% static "images/icon_warning.png" %}'>
<span>目前新聞資料庫中沒有任何資料!</span>
</div>
{% endfor %}
</table>
<div class="topfunction">
{% if currentpagenum >= 2 %}
<a href='/page2/?pagebtn=-1'><img src='{% static "images/prevpage.png" %}' alt='上一頁'></a>
{% endif %}
{% if currentpagenum < totalpagenum %}
<a href='/page2/?pagebtn=1'><img src='{% static "images/nextpage.png"%}' alt='下一頁'></a>
{% endif %}
</div>
<p style="color: magenta">{{message01}}</p>
</div>
{% endblock %}

(D).登入網頁login2.html
☎注意:要加上<link href='{% static "css/style.css" %}' rel="stylesheet" type="text/css" />
把style.css加入,才能夠顯示登入左邊的背景圖,與邊框
☎注意:若是返回首頁按鈕的程式寫法:onclick="window.location='/page2/'
<input type="button" name='btn2' value="返回首頁" onclick="window.location='/page2/'" />

程式碼:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>管理者登入</title>
{% load staticfiles %}
<link href='{% static "css/style.css" %}' rel="stylesheet" type="text/css" />
</head>
<body>
<div class="boxLogin">
<form name='myform' action="" method="POST">
{% csrf_token %}
<div class='fields'>
<div class='sep'>
<label for="username">管理者帳號</label>
<input type="text" name='username' required />
</div>
<div class='sep'>
<label for="password">管理者密碼</label>
<input type="text" name='password' required />
</div>
<div class='sep'>
<input type="submit" name='btn1' value="登入系統"/>
<input type="button" name='btn2' value="返回首頁" onclick="window.location='/page2/'" />
</div>
</div>
<p style="color: magenta">{{message01}}</p>
</form>
</div>
</body>
</html>

(E).修改網頁edit2.html
☎注意:下拉式選單,清單有目前所有欄位的值(消除重複),且顯示資料表的欄位值
<select name="catego">
{% for item in categos %}
{% if item.catego == catego %}
<option selected='selected'>{{item.catego}}</option>
{% else %}
<option>{{item.catego}}</option>
{% endif %}
{% endfor %}
</select>
☎注意:radio按鈕給定同一個name,但是value不同,在views裡面感覺value來判別
{% if enabled == True %}
已通過<input type='radio' name=enabled checked='checked' value='yes' id='enable_yes'>
審核中<input type='radio' name=enabled id='enable_no' value="no">
{% else %}
已通過<input type='radio' name=enabled id='enable_yes' value="yes">
審核中<input type='radio' name=enabled checked='checked' id='enable_no' value="no">
{% endif %}
程式碼:
{% extends 'base.html' %}
{% block title %}
<title>修改資料</title>
{% endblock %}
{% block content %}
<h1>修改新聞資料</h1>
<form name='myform' action="" method="POST">
{% csrf_token %}
<table width='100%' border='1' cellsapcing='0' cellpadding='0' >
<tr>
<td>編號</td><td><input type="text" name='id' readonly value="{{id}}"></td>
</tr>
<tr>
<td>標題</td><td><input type="text" name='title' value="{{title}}" size='60'></td>
</tr>
<tr>
<td>分類</td><td>
<select name="catego">
{% for item in categos %}
{% if item.catego == catego %}
<option selected='selected'>{{item.catego}}</option>
{% else %}
<option>{{item.catego}}</option>
{% endif %}
{% endfor %}
</select>
</td>
</tr>
<tr>
<td>訊息</td><td><textarea type="text" name='message' cols="60" rows="10">{{message}}</textarea></td>
</tr>
<tr>
<td>發表者</td><td><input type="text" name='nickname' value="{{nickname}}"></td>
</tr>
<tr>
<td>點閱</td><td><input type="text" name='press' value="{{press}}"></td>
</tr>
<tr>
<td>審核</td><td>
{% if enabled == True %}
已通過<input type='radio' name=enabled checked='checked' value='yes' id='enable_yes'>
審核中<input type='radio' name=enabled id='enable_no' value="no">
{% else %}
已通過<input type='radio' name=enabled id='enable_yes' value="yes">
審核中<input type='radio' name=enabled checked='checked' id='enable_no' value="no">
{% endif %}
</td>
</tr>
</table>
<p></p>
<input type="submit" name='bnt1' value="確認修改">
<input type="button" name='bnt2' value="返回首頁" onclick="window.location='/page_admin2/'">
<p></p>
<p style="color: magenta">{{message01}}</p>

</form>
{% endblock %}

(F).新增網頁add2.html
程式碼:
{% extends 'base2.html' %}
{% load staticfiles %}

{% block login %}
<div align='right'>
<a href="/add2/" title="新增新聞">
<img src='{% static "images/append.png" %}' alt="新增新聞"/></a>
<a href="/logout2/" title="登出管理介面">
<img src='{% static "images/LockOff.png" %}' alt="登入管理介面"/></a>
</div>
{% endblock %}

{% block content %}
<div class="contentbox">
<h1>新增一般新聞資料</h1>
<form name='myform' action="" method="POST">
{% csrf_token %}
<table width='100%' border='1' cellsapcing='0' cellpadding='0' >
<tr>
<td>分類</td><td>
<select name="catego">
{% for catego in categos %}
<option>{{catego}}</option>
{% endfor %}
</select>
</td>
</tr>
<tr>
<td>標題</td><td><input type="text" name='title' value="{{title}}" size="60"></td>
</tr>
<tr>
<td>訊息</td><td><textarea type="text" name='message' value="{{message}}" cols="60" rows="10" ></textarea></td>
</tr>
<tr>
<td>發表者</td><td><input type="text" name='nickname' value="{{nickname}}"></td>
</tr>
<tr>
<td>審核</td><td>
已通過<input type='radio' name=enabled checked='checked' value="yes" id='enable_yes'>
審核中<input type='radio' name=enabled id='enable_no' value="no">
</td>
</tr>

</table>
<p></p>
<input type="submit" name='bnt1' value="確認新增">
<input type="button" name='bnt2' value="返回首頁" onclick="window.location='/page_admin2/'">
<p></p>
<p style="color: magenta">{{message01}}</p>

</form>
</div>
{% endblock %}









 
 
Chp8.圖形驗證碼(Captcha)

下載

下載本章project成果
目錄 圖形驗證碼功能 Django的圖形驗證碼Captcha套件 建立一個djiango的虛擬環境 把一個已經寫好的專案拿來測試
撰寫程式的前置作業 圖形驗證的關鍵三步驟 exp08-02驗證是否為管理者 exp08-03修改驗證圖形碼的樣式

圖形驗證碼功能

1.功能:
圖形驗證碼(Captcha,Completely Automated Public Turing test to tell Computers and Humans Apart,簡稱CAPTCHA)
伺服器的電腦會自動生成一個問題由用戶來解答。這個問題可以由電腦生成並評判,但是必須只有人類才能解答。由於電腦無法解答CAPTCHA的問題,所以回答出問題的用戶就可以被認為是人類。
有些是純數字的圖形驗證碼,有些是字母和數字,有些是圖案
能夠:避免有機器人系統線上灌票,垃圾廣告,垃圾留言....
應用:用在留言板,線上投票系統,購票系統,....
參考:https://ivanjo39191.pixnet.net/blog/post/156335748-python-django-%E5%AD%B8%E7%BF%92%E7%B4%80%E9%8C%84%28%E4%B9%9D%29-%E5%B0%88%E9%A1%8C%E7%B7%B4%E7%BF%92%EF%BC%9A%E7%B6%B2%E7%AB%99%E7%95%99%E8%A8%80

Django的圖形驗證碼(Captcha)=django-simple-captcha套件

2.Django的圖形驗證碼(Captcha)=django-simple-captcha套件
(1).功能:
可產生有背景圖案的英文字母圖片。
可指定圖片中英文字母的數。
可製作數學計算式的圖形驗證碼。

(2).安裝圖像驗證碼套件:指令
pip install django-simple-captcha

(3).在 中「INSTALLED_APPS」項目加入
'captcha',

(4).重整資料庫
django-simple-captcha 會在資料庫中建立圖形驗證碼需使用的資料表,
因此要在專案中以下列指令重整資料庫:
python manage.py migrate

(5).在 加入 captcha 就可以在網頁中使用圖形驗證碼
from django.conf.urls import url,include
urlpatterns = [
url(r'^captcha/',include('captcha.urls')),
]

如何建立一個djiango的虛擬環境

4.如何建立一個djiango的虛擬環境
(1).優點:
A.可以搭建虛擬且獨立的python運行環境, 使得單個項目的運行環境與其它項目獨立起來。同時也可以用於在一臺機器上創建多個獨立的python運行環境
B.在没有权限的情况下安装新套件
C.不同应用程式,可以使用不同的套件版本
D.套件升级不影响其他应用

(2).版本
A.舊版python的虛擬環境是:virtualenv
B.Python3.3以上的版本通过venv模块原生支持虚拟环境,可以代替Python之前的virtualenv。
C.Python3.4以後版本使用虛擬環境,不需要再安裝了(venv)

(3).步驟:
方法一:
A.建立一個目錄:env08_01
B.到此目錄:cd env08_01
C.把此目錄造成虛擬目錄:python -m venv .

方法二:
A.直接建立虛擬目錄:python -m venv env08_01

D.複製專案(chalogin)到此目錄(env08_01):
下載chalogin.zip專案,並解壓縮
E.啟動虛擬環境:scripts\activate
F.安裝django
pip install django

安裝圖像驗證碼套件:指令
pip install django-simple-captcha

G.執行資料庫同步更新
python manage.py makemigrations
python manage.py migrate

H.執行chalogin
python manage.py runserver

I.測試登入帳號密碼,與圖形驗證碼
admin
aa123456

Z.退出虛擬環境:deactivate

如何把一個已經寫好的專案拿來測試

4.如何把一個已經寫好的專案拿來測試(不一定要在虛擬環境內執行)
(1).之前已經安裝django了
(1).下載chalogin.zip專案,並解壓縮
複製貼上到目前目錄下
(2).安裝圖像驗證碼套件:指令
pip install django-simple-captcha

(3).執行資料庫同步更新
python manage.py makemigrations
python manage.py migrate

(4).執行chalogin
python manage.py runserver

(5).測試登入帳號密碼,與圖形驗證碼
admin
aa123456

自行撰寫程式的前置作業

5.自行撰寫程式的前置作業
_(A).建立目錄
_(B).建立專案
django-admin startproject pj07
cd pj07
_(C).建立應用程式app
python manage.py startapp app01
_(D).修改setting.py
40行:新的app名稱
'app01',
'captcha',

58行:設定templates目錄位置
'DIRS': [os.path.join(BASE_DIR,'templates')],

107行:設定繁體中文,台北語區
LANGUAGE_CODE = 'zh-Hant'
TIME_ZONE = 'Asia/Taipei'

122行:設定static的目錄
STATICFILES_DIRS = [
os.path.join(BASE_DIR,'static'),
]
_(E).到目前專案目錄
建立templates:md templates
建立static:md static

_(F).建立migration資料檔
python manage.py makemigrations

_(G).將模型與資料庫同步
例如:python manage.py migrate

_(H).建立資料庫管理者的帳號與密碼
指令:python manage.py createsuperuser
使用者名稱 (leave blank to use 'administrator'): admin
電子信箱: admin@gmail.com
Password:aa123456
Password (again):aa123456
這個密碼與使用者名稱太相近。
這個密碼過短。請至少使用 8 個字元。

_(I).登入資料庫管理者系統
網頁:http://127.0.0.1:8000/admin

_(J).在 <urls.py> 加入 captcha 就可以在網頁中使用圖形驗證碼
from django.conf.urls import url,include
urlpatterns = [
url(r'^captcha/',include('captcha.urls')),
]

圖形驗證的關鍵三步驟

6.觀念:圖形驗證的關鍵三步驟
(1).圖形驗證,在django裡面乃是配合表單驗證的方式來執行的(forms.Form),所以要建立form.py
forms.py,設定表單驗證物件captcha = CaptchaField()
例如:
class PostForm(forms.Form):
username = forms.CharField(max_length=20,initial='')
pd = forms.CharField(max_length=20,initial='')
captcha = CaptchaField()

(2).在views.py裡面,判別是否通過表單驗證
postform = forms.PostForm(request.POST)
if postform.is_valid(): #forms驗證通過
username = postform.cleaned_data['username']
.......
else:
message = '驗證碼錯誤!'

(3).在模板index.html,或是login1.html裡面放置圖形驗證物件:{{postform.captcha}}
<th align="right" valign="baseline">驗證碼</th>
<td valign="baseline">{{postform.captcha}}</td>

exp08-02驗證是否為管理者

7.範例:exp08-02.py(自行寫程式,驗證是否為管理者(帳號密碼),驗證圖形碼)
☎結構:login1.html是登入首頁,若是成功登入,就會開啟member1.html

(A).在form1.html設定表單驗證(包括圖形驗證)
☎注意:這裡所要宣告表單類別class物件,不是def
程式碼:
from django import forms
from captcha.fields import CaptchaField
class PostForm(forms.Form):
username = forms.CharField(max_length=20,initial='')
password = forms.CharField(max_length=20,initial='')
captcha = CaptchaField()

(B).在urls.py設定
☎注意:設定首頁,必須用'^$',而不是'^/$':url(r'^$',views.login1)
☎注意:兩種想法都可以,from app01 import views,或是from app01.views import login1,member1
但是這個寫法比較簡單:from app01 import views
☎注意:圖形驗證,必須額外再加上:url(r'^captcha/', include('captcha.urls'))
程式碼:
from django.conf.urls import url,include
from app01 import views
urlpatterns = [
path('admin/', admin.site.urls),
url(r'^captcha/', include('captcha.urls')),
url(r'^$',views.login1),
url(r'^login1/$',views.login1),
url(r'^member1/$',views.member1),
]

(C).在views.py設定函數(login1,member1)
☎注意:若是要驗證是否為會員的公式:
from django.contrib.auth import authenticate
from django.contrib import auth
if request.method == 'POST':
postform = PostForm(request.POST)
username = postform.cleaned_data['username']
password = postform.cleaned_data['password']
user = auth.authenticate(username=username,password=password)
#通過驗證,並且帳號已經開始啟用
if user is not None :
message01 = '成功登入'
else:
message01 = '帳號密碼有誤,無法登入'
else:
#這裡不是按post來的,表示式一開始顯示畫面時,要把所有表單驗證物件,傳到模板去
postform = PostForm()
message01 = '帳號,密碼,圖形驗證碼,都要輸入'
☎注意:若是要圖形驗證驗證的公式:
postform = PostForm(request.POST)
if postform.is_valid():
user = auth.authenticate(username=username,password=password)
.........
else:
message01 = '圖形驗證錯誤'

程式碼:
from django.shortcuts import render,redirect
from django.contrib.auth import authenticate
from django.contrib import auth
from app01.forms import PostForm
# Create your views here.
def login1(request):
if request.method == 'POST':
postform = PostForm(request.POST)
if postform.is_valid():
username = postform.cleaned_data['username']
password = postform.cleaned_data['password']
#驗證該會員
user = auth.authenticate(username=username,password=password)
#通過驗證,並且帳號已經開始啟用
if user is not None :
message01 = '成功登入'
return render(request,'member1.html',locals())
else:
message01 = '帳號密碼有誤,無法登入'
else:
message01 = '圖形驗證錯誤'
else:
#這裡不是按post來的,表示式一開始顯示畫面時,要把所有表單驗證物件,傳到模板去
postform = PostForm()
message01 = '帳號,密碼,圖形驗證碼,都要輸入'
return render(request,'login1.html',locals())

def member1(request):
return render(request,'member1.html',locals())

(D).登入網頁login1.html
☎注意:因為是採用表單驗證,用表單物件postform = PostForm()類別class物件,所以,欄位直接學生表單類別物件。
例如:{{postform.username}}
程式碼:
<!DOCTYPE html>
<htm>
<head>
<meta charset="utf-8">
<title>圖形驗證碼,登入驗證</title>
</head>
<body>
<form name='myform' action="" method="POST">
{% csrf_token %}
<table width='80%' border="1">
<tr>
<td>輸入帳號</td>
<td>{{postform.username}}</td>
</tr>
<tr>
<td>輸入密碼</td>
<td>{{postform.password}}</td>
</tr>
<tr>
<td>圖形驗證</td>
<td>{{postform.captcha}}</td>
</tr>
</table>
<input type="submit" value="登入">
<div style="color:chocolate">{{message01}}</div>
</form>
</body>
</htm>

(E).測試:http://127.0.0.1:8000/
(會員帳號:admin,aa123456

exp08-03修改驗證圖形碼的樣式

8.範例:exp08-03.py(修改驗證圖形碼的樣式)
(1).發現目前的圖形驗證太複雜,經常會輸入錯誤,要修改樣式
(2).修改:settings.py
在第44行設定干擾噪音noise,都沒有任何noise
CAPTCHA_NOISE_FUNCTIONS = (
'captcha.helpers.noise_null', #没有樣式
#'captcha.helpers.noise_arcs', #線
#'captcha.helpers.noise_dots', #點
)

四種設定:
A.預設:有背景圖形,有線條,有點圖
B.無圖案:'captcha.helpers.noise_null',
C.線圖案:'captcha.helpers.noise_arcs',
D.點圖案:'captcha.helpers.noise_dots',

(3).設定圖片顏色
CAPTCHA_BACKGROUND_COLOR = '#00ff00' #背景頻色

(4).設定顯示的英文字母數目:
CAPTCHA_LENGTH = 6 #英文字母個數

(5).設定驗證碼圖片的尺寸:
CAPTCHA_IMAGE_SIZE = (150, 70) #圖片大小

(6).設定驗證碼圖片的輸入時間:
CAPTCHA_TIMEOUT = 5 #時間限制(分)

(7).設定驗證方式:
目前有兩種驗證方式:
A.英文字母驗證
CAPTCHA_CHALLENGE_FUNCT = 'captcha.helpers.random_char_challenge' #圖片為英文字母

B.數學計算驗證:
CAPTCHA_CHALLENGE_FUNCT = 'captcha.helpers.math_challenge' #圖片中為數學計算式

 
 
chp9:上課加分系統

觀看

本範例的成果圖片1圖片2圖片3圖片4圖片5圖片6圖片7圖片8

下載

下載本章project成果檔案

下載

下載班級學生csv資料庫

下載

下載班級學生sqlite資料庫
 
 
chp10. 經文查詢系統

觀看

本範例的成果圖片1圖片2

下載

下載本章project成果檔案

下載

下載經文csv資料庫

下載

下載經文sqlite資料庫
 
 
chp11.django如何讀取js檔案
如何讀取jquery-1.9.1.js 用onclick直接呼叫views.py的function 用onclick直接呼叫views.py的function,且傳遞get變數

如何讀取jquery-1.9.1.js

1.例如,在django裡面,模板是jquery mobile網頁,如何讀取jquery.mobile-1.4.2/jquery-1.9.1.min.js
(1).錯誤方法:若是把jquery.mobile-1.4.2目錄放在templates目錄下
結果:網頁的格式無法正確顯示,無法直接讀取jquery.mobile-1.4.2/jquery-1.9.1.min.js

(2).正確方法一:若是完整網站url,就會是正確的
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.5/jquery.min.js">

(3).正確方法二:
_(A).必須把jquery.mobile-1.4.2目錄放到static目錄下,
_(B).settings.py內必須有這個設定:
STATICFILES_DIRS = (
os.path.join(BASE_DIR, 'static'),
)
_(C).在網頁模板*.html內,第一行必須有這個設定:
{% load staticfiles %}

_(D).在網頁模板*.html內的css,js路徑,都必須有這個設定:
<script src="{% static 'jquery.mobile-1.4.2/jquery-1.9.1.min.js' %}"></script>

(3).結論:若是Django要讀取外部的Javascript和JQuery檔案,兩種方法
JQuery程式庫可用二種方式載入:
一種為檔案方式(配合{% static '*.js' %})
一種為URL方式。

用onclick直接呼叫views.py裡面的function

2.如何不用form,不用submit,直接讓checkbox用onclick直接呼叫views.py裡面的function
關鍵方法:onclick='javascript:location.href = "/senable/"'

(1)範例:
_(A)模板templates.py
關鍵:onclick='javascript:location.href = "/senable/"'
{% csrf_token %}
<input type="checkbox" name='scoreenable' value='yes' onclick='javascript:location.href = "/senable/"' >
<p style="color: magenta">{{message01}}</p>

_(B)views.py
def senable(request):
message01 = '已經成功修改enable='
return render(request,'score_admin.html',locals())

用onclick直接呼叫views.py的function,且傳遞get變數

3.checkbox如何用onclick直接呼叫views.py裡面的function,並且傳遞get變數
關鍵方法:checked='{{varcheck}}' value='yes' onclick='javascript:location.href = "/senable/?scoreenable="+this.value'

(1)範例:
_(A)模板templates.py
關鍵:onclick='javascript:location.href = "/senable/"'
{% csrf_token %}
<input type="checkbox" name='scoreenable' checked='{{varcheck}}' value='yes' onclick='javascript:location.href = "/senable/?scoreenable="+this.value' >
<p style="color: magenta">{{message01}}</p>

_(B)views.py
def senable(request):
if request.method=="GET":
e1 = request.GET.get('scoreenable',0)
message01 = e1
return render(request,'score_admin.html',locals())

exp11_3


exp11_4

 
 
chp12. django如何與ajax互動
exp12_1:多頁面的處理 exp12_2:多頁面之間傳遞變數 exp12_3:多頁面應用:台北動物園導覽

exp12_1


exp12_2


exp12_3

 
 
chp13.各種views.py函數小技巧
如何修改資料表欄位=其它欄位(方法:使用F('其它欄位')) 如何在views.py讀取templates的全部欄位變數 取得資料庫資料表某欄位的最大值(2種方法) 修改資料update的兩種寫法

如何修改資料表欄位=其它欄位(方法:使用F('其它欄位'))

1.如何修改資料表欄位=其它欄位(方法:使用F('其它欄位'))
Using existing field values in django update query

範例1:
from django.db.models import F
tasks = Task.objects.filter(task_definition__cascades=False)
.update(shared_task_id=F('id'))

範例2:
from django.db.models import F
def avg_app3a(maxscore):
#對重新計算平均分數
recd = App3A.objects.all().update(分數 = 70 + 25/maxscore * F('加分'))

注意1:F要大寫
注意2:要先import F(from django.db.models import F)

如何在views.py讀取templates的全部欄位變數

2.如何在views.py讀取templates的全部欄位變數
方法:(變數list) stuid = request.POST.getlist('欄位名稱')
然後:for item in stuid:
recd = App3A.objects.get(學號=item)

範例1:
Django request.POST get multiple values
方法:request.POST.getlist('pass_id')

<form method="post" action="">
<input type="checkbox" value="1" name="artists">
<input type="checkbox" value="2" name="artists">
<input type="checkbox" value="3" name="artists">
</form>

In views.py :
def handle(request):
if request.method == 'POST':
artists = request.POST.getlist('artists')
# now artists is a list of [1,2,3]


範例2:
模板.html
{% for item in items %}
<span class="slider round"></span>

viws.py
if request.method=='POST':
stuid = request.POST.getlist('stu')
#對學生加分
maxscore = 0
for item in stuid:
recd = App3A.objects.get(學號=item)
recd.加分 = recd.加分 + 1
if recd.加分 > maxscore:
maxscore = recd.加分
recd.save()

取得資料庫資料表某欄位的最大值(2種方法)

3.■如何取得資料庫資料表某欄位的最大值
方法1:
from django.db.models import Max
dict字典 = App4A.objects.all().aggregate(Max('加分'))
結果:# {'加分__max':16 }
注意1:查詢最大值的結果是個dict
注意2:如何取得最大值max = dict字典['加分__max']

範例1:
from django.db.models import Max
dictmax = App4A.objects.all().aggregate(Max('加分'))
maxpoint = dictmax['加分__max']
App3A.objects.all().update(分數 = 70 + 25/maxpoint * F('加分'))

範例2:
要獲得所有產品的最高價格:
from django.db.models import Avg, Max, Min, Sum
>>> Product.objects.all().aggregate(Max('price'))
# {'price__max':599 }


方法2:使用order_by('-加分').first()
recd = App4A.objects.all().order_by('-加分').first()
maxpoint = recd.加分

修改資料update的兩種寫法

4.■修改資料update的兩種寫法
(1)方法1:使用.update(欄位=值)
範例:
recd = Enabled.objects.all().update(yesno = yesno)
(注意:不需要寫recd.save)


(1)方法2:先查詢.get(欄位=值(),再.save()
範例:
recd = stu.objects.get(id=myid)
recd.cname = request.POST['myname']
recd.save()



 
 
chp14.各種模板templates小技巧
在網頁顯示的數字(顯示1位小數)

在網頁顯示的數字(顯示1位小數)

1.■如何在網頁顯示的數字(顯示1位小數)
方法:在模板templates.html裡面{{score|floatformat}}
說明:
{{ 13.414121241|floatformat }} 保留1位小數,可為負數,幾種形式
{{ 13.414121241|floatformat:"2" }} 保留2位小數


exp12_3

 
 
chp20. 上傳到horuku網站
先安裝git 申請horuku網站帳號 在虛擬環境建立建立django專案 登入heroku並上傳 若修改原始檔案後再上傳到heroku的方法
若 Push出現錯誤訊息rejected的方法

先安裝git

1.安裝horuku前,要先安裝git
原因:horoku乃是使用git的某些工具來上傳到伺服器的
(1).安裝git
https://git-scm.com/download/win

申請horuku網站帳號

2.申請horuku網站帳號
(1).帳號密碼
abc@gmail.com
passwork

(2).建立一個app= test1(專案名稱)

(3).安裝heroku CLI
功能:利用git可以把網站與heroku同步
官方教學:Install the Heroku CLI
Download and install the Heroku CLI.
If you haven't already, log in to your Heroku account and follow the prompts to create a new SSH public key.

$ heroku login

Create a new Git repository
Initialize a git repository in a new or existing directory

$ cd my-project/(我應該是test1)
$ git init
$ heroku git:remote -a test1
$ heroku config:set DJANGO_SETTINGS_MODULE=test1.prod_settings

Deploy your application
Commit your code to the repository and deploy it to Heroku using Git.

$ git add .
$ git commit -am "make it better"
$ git push heroku master

Existing Git repository
For existing repositories, simply add the heroku remote

$ heroku git:remote -a test1

在虛擬環境建立建立django專案

在虛擬環境建立建立django專案

3.建立虛擬環境
python -m venv testvenv
cd testvenv
scripts\activate

4.安裝django
pip install django
複製test01目錄到testvenv目錄

5.不顯示錯誤
修改settings.py DEBUG = False

6.安裝heroku伺服器的套件
pip install dj-database-url dj-static gunicorn psycopg2

7.建立requirements.txt
功能:heroku乃是根據test01目錄下面requirements.txt的設定來安裝伺服器套件
位置:在test01目錄下
建立requirements.txt檔案
cd test01
pip freeze >requirements.txt

8.建立Procfile檔案
功能:告訴heroku啟動網站的方式
位置:在test01目錄下(與requirements.txt同一個目錄)
輸入:
web: gunicorn --pythonpath test01 test01.wsgi
說明:會根據《test01》目錄下方的urls.py來開啟指定網頁

9.查詢你的python版本
python --version
Python 3.6.8

10.建立runtime.txt
功能:告訴heroku你的python版本
位置:在test01目錄下(與requirements.txt同一個目錄)
輸入:
python-3.6.8

11.建立prod_settings.py
功能:heroku伺服器的設定檔案會與本機的settings.py不同,一般要另外設定
位置:在test01/test01目錄下(與settings.py同一個目錄)
輸入:
from .settings import *
STATIC_ROOT = 'staticfiles'
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
ALLOWED_HOSTS = ['*']
DEBUG = False

12.建立.gitignore檔案
功能:列出不會上傳到heroku伺服器的目錄與檔案(大部分都是暫存檔)
(建立時,使用.gitignore.就可以建立了)
位置:在test01目錄下(與requirements.txt同一個目錄)
輸入:
*.pyc
__pycache__
staticfiles

13.修改wsgi.py的設定
功能:heroku伺服器處理靜態檔案static的方式與本機端的方法不同,所以要修改
位置:在test01/test01目錄下(與settings.py同一個目錄)
輸入:
import os

from django.core.wsgi import get_wsgi_application
from dj_static import Cling
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'test01.settings')
application = Cling(get_wsgi_application())

新增一行:from dj_static import Cling
取代一行:application = Cling(get_wsgi_application())
(取代舊的application = get_wsgi_application())

登入heroku並上傳

登入heroku並上傳

14.登入,並將網站部署到heroku伺服器
(1).用dos環境登入:cmd
(以下全部在dos的cmd底下運作)
到test01目錄
cd D:\testvenv\test01\test01

(2).登入heroku
heroku login
然後會自動開啟一個網頁,輸入email,password就可以登入
(教學:https://devcenter.heroku.com/articles/heroku-cli)

☎注意:務必到project專案底下:(應該是test01),否則後面的都會出錯
☎cd test01
(3).在本機端建立一個倉庫repository
git init
結果:git 不是內部或外部命令

(4).如何在cmd底下執行git指令
方法:修改path
32位元:
C:\Program Files\Git\mingw32\bin
C:\Program Files\Git\mingw32\libexec\git-core
猜測64位元:
C:\Program Files\Git\bin
C:\Program Files\Git\libexec\git-core;

控制台->“右键“電腦->“進階”->“環境變數”->在下方的“系统變數”中找到“path”
->选中“path”->“编辑”
C:\Program Files\Git\mingw32\bin;C:\Program Files\Git\mingw32\libexec\git-core

(5).把git倉庫與遠端heroku的ehappyboard連接
格式:heroku git:remote -a 在heroku的APP名稱
輸入:heroku git:remote -a test
heroku git:remote -a test
結果:set git remote heroku to https://git.heroku.com/test.git

有時候出現警告:heroku git:remote -a test
» Warning: heroku update available from 7.33.3 to 7.35.1.
set git remote heroku to https://git.heroku.com/test.git
原因:要更正heroku的版本,成7.35.1版本
方法:heroku update

(6).請heruoku把網站的test目錄下面的prod_settings,設定為伺服器的設定值
輸入:heroku config:set DJANGO_SETTINGS_MODULE=test.prod_settings
結果:Setting DJANGO_SETTINGS_MODULE and restarting ⬢ test... done, v3

(7).把網站的所有檔案加入git追踪
git add .

(8).把所有追踪的檔案加入git倉庫
輸入:git commit -am "init commit"

(9).上傳到heroku伺服器
輸入:git push heroku master

(10).讓heroku運行網站
輸入:heroku ps:scale web=1
結果:Scaling dynos... done, now running web at 1:Free

(11).測試網站:
輸入:heroku open

(10).結果:測試
https://test01.herokuapp.com/

(11).如何刪除test01的apps
輸入:heroku apps:destroy test

若修改原始檔案後再上傳到heroku的方法

若修改原始檔案後再上傳到heroku的方法

15.修改原始檔案後,要如何上傳修正heroku的內容
(0).建立虛擬環境
(若是testvenv目錄已經存在,就不需要建立:python -m venv testvenv)
cd testvenv
scripts\activate

(1).登入heroku(若是還沒有登入)
heroku login

(2).把網站的所有檔案加入git追踪
git add .

(3).把所有追踪的檔案加入git倉庫
輸入:git commit -am "init commit101"

(4).上傳到heroku伺服器
輸入:git push heroku master

若是已經電腦版本與主機版本不對,要強迫覆蓋主機倉庫的版本(-f = force)
輸入:git push heroku master -f

(5).讓heroku運行網站
輸入:heroku ps:scale web=1

(6).測試
https://test.herokuapp.com/test1/

若 Push出現錯誤訊息rejected的方法

若 Push出現錯誤訊息rejected的方法

16.幾個月後,若修改原始檔案後,要如何上傳修正heroku的內容
在執行 Push 指令的時候會出現這個錯誤訊息:
$ git push
To https://github.com/eddiekao/dummy-git.git
! [rejected] master -> master (fetch first)
原因:
這段訊息的意思是線上版本的內容比你電腦裡這份還要新,所以 Git 不讓你推上去。

解決方法:覆蓋法
git push -f
強迫覆蓋之前舊的檔案

範例步驟:
(0).建立虛擬環境
cd testvenv
scripts\activate

(1).登入heroku
heroku login

(2).把網站的所有檔案加入git追踪
git add .

(3).把所有追踪的檔案加入git倉庫
輸入:git commit -am "init commit101"

(4).上傳到heroku伺服器
輸入:git push heroku master

若是已經版本不對了,要強迫覆蓋主機倉庫的版本(-f = force)
輸入:git push heroku master -f

(5).讓heroku運行網站
輸入:heroku ps:scale web=1

(6).測試
https://test.herokuapp.com/test1/


 
 
chp21. 將Django架設在IIS上

1.

1.先確認你的windows是否已經安裝IIS,且安裝CGI
(1)開啟控制台→程式集→開啟或關閉Windows功能→Internet Information Services (IIS)

(2)點選裡面的CGI→World wide web服務→應用程式開發功能→勾選『CGI』→安裝


(3)檢查是否FastCgi已經安裝
開啟IIS=>Internet Information Services (IIS)


如果剛剛已經安裝CGI,就會幫你安裝FastCgi
檢查在IIS首頁上是否有FastCgi

2.確認python是否已經安裝?

3.安裝wfastcgi並啟動?
(1)若已經安裝Python環境,通常會安裝wfastcgi
在Cmd:pip install wfastcgi

安裝後就可以在python程式目錄裡面找到wfastcgi


(2)開啟wfastcgi
在Cmd:wfastcgi enable

4.確認Django是否已經安裝?

5.在IIS新增網站
(1)IIS→站台→右鍵→新增網站

A.站台名稱:django(隨便設定,不重要,用不到)
B.實體路徑:D:\20170530\D\Website\lecture\python\py_django\pratice\test74(Django專案的根目錄)
C.繫結→設定IP:120.114.35.300(設定你電腦的IP)


6.設定『處理常式對應』
點選你剛剛設定的網站(django)→[處理常式對應]

設定
A.要求路徑:*
B.模組:FastCgiModule
C.執行檔:(Python.exe的路徑)|(wfastcgi.py的路徑)

例如1:"C:\Program Files\Python36-32\python.exe"|D:\20170530\D\Website\lecture\python\py_django\pratice\test74\wfastcgi.py
注意:先從C:\Program Files\Python36-32\Lib\site-packages複製wfastcgi.py檔案,複製到Django專案根目錄(D:\20170530\D\Website\lecture\python\py_django\pratice\test74\)
注意:目錄名稱若有空白格,該如何處理
方法:用""包住檔案全路徑:"C:\Program Files\Python36-32\python.exe"

例如2::"C:\Program Files\Python36-32\python.exe"|"D:\20170530\D\Website\lecture\python\py_django\pratice\test74\wfastcgi.py"

D.名稱:django(隨便設定,不重要,用不到)
通常會複製檔案複製到你放Django檔案的地方

7.設定FastCGI環境變數
(1)到IIS的本機名稱(第一個)→[FastCGI設定]→點選你剛剛設定的項目


→設定環境變數

→新增以下三項
Name: WSGI_HANDLER
Value:django.core.wsgi.get_wsgi_application()

Name: PYTHONPATH
Value: D:\20170530\D\Website\lecture\python\py_django\pratice\test74(專案路徑)

Name: DJANGO_SETTINGS_MODULE
Value: test74.settings(專案名.settings)


8.啟動測試:http://120.114.35.300/score/
結果:出現錯誤
Invalid HTTP_HOST header: '120.114.35.300'. You may need to add u'120.114.35.300' to ALLOWED_HOSTS. Request Method

原因:要修改你建立django project專案的settings.py,允許ALLOWED_HOSTS

9.修改setting.py 文件:
第28行
ALLOWED_HOSTS = ['*']


10.啟動測試:http://120.114.35.300/score/