tcp/ip五層模型css
應用層html
傳輸層前端
網絡層python
數據鏈路層mysql
物理層jquery
socket : 套接字,位於應用層和傳輸層之間的虛擬層,是一組接口git
c/s架構 ------> b/s架構web
#百度瀏覽器 socket服務器
- 1.建立socket服務端
- 2.綁定ip和接口
- 3.監聽
- 4.等待鏈接
- 7.接受數據
- 8.返回數據
#瀏覽器 socket客戶端
- 5.鏈接服務端
- 6.發送數據
- 9.接受數據
- 10.斷開鏈接
咱們能夠這樣理解:全部的Web應用本質上就是一個socket服務端,而用戶的瀏覽器就是一個socket客戶端。ajax
socket服務端正則表達式
import socket
#建立一個socket對象
sk = socket.socket()
#綁定一個ip和端口
sk.bind(('127.0.0.1',8000))
#監聽
sk.listen()
#等待鏈接
while True:
conn,addr = sk.accept()
#接受數據
conn.recv(1024)
#返回數據
conn.send(b'ok')
#斷開鏈接
conn.close()
在瀏覽器中鏈接上述服務端時出現問題:
咱們能夠一下能夠發現瀏覽器向服務端發送請求時,沒法響應,那麼是什麼致使這個緣由呢?咱們想到必須有一個統一的規則,讓你們發送消息、接收消息的時候都有個格式依據,不能隨便寫。這個規則就是HTTP協議.HTTP協議主要規定了客戶端和服務器之間的通訊格式
讓咱們首先打印下咱們在服務端接收到的消息是什麼
import socket
sk = socket.socket()
sk.bind(("127.0.0.1", 80))
sk.listen()
while True:
conn, addr = sk.accept()
data = conn.recv(8096)
print(data) # 將瀏覽器發來的消息打印出來
conn.send(b"OK")
conn.close()
輸出
b'GET / HTTP/1.1\r\nHost: 127.0.0.1:8080\r\nConnection: keep-alive\r\nCache-Control: max-age=0\r\nUpgrade-Insecure-Requests: 1\r\nUser-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3355.4 Safari/537.36\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8\r\nAccept-Encoding: gzip, deflate, br\r\nAccept-Language: zh-CN,zh;q=0.9\r\nCookie: csrftoken=CtHePYARJOKNx5oNVwxIteOJXpNyJ29L4bW4506YoVqFaIFFaHm0EWDZqKmw6Jm8\r\n\r\n'
咱們將\r\n替換成換行看得更清晰點:
GET / HTTP/1.1
Host: 127.0.0.1:8080
Connection: keep-alive
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3355.4 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Cookie: csrftoken=CtHePYARJOKNx5oNVwxIteOJXpNyJ29L4bW4506YoVqFaIFFaHm0EWDZqKmw6Jm8
點擊view source以後顯示以下圖:
HTTP協議,又稱超文本傳輸協議(英文:Hyper Text Transfer Protocol,HTTP)是一種用於分佈式、協做式和超媒體信息系統的應用層協議,
每一個HTTP請求和響應都遵循相同的格式,一個HTTP包含Header和Body兩部分,其中Body是可選的。HTTP響應的Header中有一個 Content-Type
代表響應的內容格式。它的值如text/html; charset=utf-8。text/html則表示是網頁,charset=utf-8則表示編碼爲utf-8。
HTTP協議採用了請求/響應模型。客戶端向服務器發送一個請求報文,請求報文包含請求的方法、URL、協議版本、請求頭部和請求數據。服務器以一個狀態行做爲響應,響應的內容包括協議的版本、成功或者錯誤代碼、服務器信息、響應頭部和響應數據。
HTTP 請求/響應的步驟:
1.客戶端鏈接到Web服務器
2.發送HTTP請求
3.服務器接受請求並返回HTTP響應
4.釋放鏈接TCP鏈接
5.客戶端瀏覽器解析HTML內容
在瀏覽器地址欄鍵入URL,按下回車以後會經歷如下流程:
1.瀏覽器向 DNS 服務器請求解析該 URL 中的域名所對應的 IP 地址;
2.解析出 IP 地址後,根據該 IP 地址和默認端口 80,和服務器創建TCP鏈接;
3.瀏覽器發出讀取文件(URL 中域名後面部分對應的文件)的HTTP 請求,該請求報文做爲 TCP 三次握手的第三個報文的數據發送給服務器;
4.服務器對瀏覽器請求做出響應,並把對應的 html 文本發送給瀏覽器;
5.釋放 TCP鏈接;
6.瀏覽器解析將該 html 文本並顯示內容;
1.GET
向指定的資源發出「顯示」請求。使用GET方法應該只用在讀取數據,而不該當被用於產生「反作用」的操做中,例如在Web Application中。其中一個緣由是GET可能會被網絡蜘蛛等隨意訪問。
2.POST
向指定資源提交數據,請求服務器進行處理(例如提交表單或者上傳文件)。數據被包含在請求報文中。這個請求可能會建立新的資源或修改現有資源,或兩者皆有。
3.HEAD
與GET方法同樣,都是向服務器發出指定資源的請求。只不過服務器將不傳回資源的本文部分。它的好處在於,使用這個方法能夠在沒必要傳輸所有內容的狀況下,就能夠獲取其中「關於該資源的信息」(元信息或稱元數據)。
4.PUT
向指定資源位置上傳其最新內容。
5.DELETE
請求服務器刪除Request-URI所標識的資源。
6.TRACE
回顯服務器收到的請求,主要用於測試或診斷。
7.OPTIONS
這個方法可以使服務器傳回該資源所支持的全部HTTP請求方法。用'*'來代替資源名稱,向Web服務器發送OPTIONS請求,能夠測試服務器功能是否正常運做。
8.CONNECT
HTTP/1.1協議中預留給可以將鏈接改成管道方式的代理服務器。一般用於SSL加密服務器的連接(經由非加密的HTTP代理服務器)。
注意:
1.方法名稱是區分大小寫,當某個請求所對應的資源部支持對應方法時,服務器應當返回狀態碼405(Method Not Allowed),當服務器不認識或者不支持對應的請求方法的時候,應當返回狀態碼501(Not Implemented)。
2.HTTP服務器至少應該實現GET和HEAD方法,其餘方法都是可選的。固然,全部的方法支持的實現都應當匹配下述的方法各自的語義定義。此外,除了上述方法,特定的HTTP服務器還可以擴展自定義的方法。例如PATCH(由 RFC 5789 指定的方法)用於將局部修改應用到資源
全部HTTP響應的第一行都是狀態行,依次是當前HTTP版本號,3位數字組成的狀態代碼,以及描述狀態的短語,彼此由空格分隔。
狀態代碼的第一個數字表明當前響應的類型:
1xx消息——請求已被服務器接收,繼續處理
2xx成功——請求已成功被服務器接收、理解、並接受
3xx重定向——須要後續操做才能完成這一請求
4xx請求錯誤——請求含有詞法錯誤或者沒法被執行
5xx服務器錯誤——服務器在處理某個正確請求時發生錯誤
超文本傳輸協議(HTTP)的統一資源定位符將從因特網獲取信息的五個基本元素包括在一個簡單的地址中:
傳送協議。
層級URL標記符號(爲[//],固定不變)
訪問資源須要的憑證信息(可省略)
服務器(一般爲域名,有時爲IP地址)
端口號(以數字方式表示,若爲HTTP的默認值「:80」可省略)
路徑(以「/」字符區別路徑中的每個目錄名稱)
查詢(GET模式的窗體參數,以「?」字符爲起點,每一個參數以「&」隔開,再以「=」分開參數名稱與數據,一般以UTF8的URL編碼,避開字符衝突的問題)
片斷。以「#」字符爲起點
以http://www.luffycity.com:80/news/index.html?id=250&page=1 爲例:
http默認端口80,https默認端口443
#請求(request)
#瀏覽器 —— 》 服務器
############ GET請求 沒有請求數據
「請求方式 url路徑 協議版本\r\n
k1:v1\r\n
k2:v2\r\n
\r\n
數據」
#響應(response)
#服務器 —— 》 瀏覽器
「協議版本 狀態碼 狀態碼描述\r\n
k1:v1\r\n
k2:v2\r\n
\r\n
響應數據(響應體)」
1.socket收發消息 - wsgiref wsgiref (本地測試) uwsgi(線上)
2.根據不一樣的路徑返回不一樣的內容
3.返回動態頁面(字符串的替換------->模板的渲染) —— jinja2
django | flask | tornado |
---|---|---|
2 3 | 2 | 1 2 3 |
socket服務端
import socket
sk = socket.socket()
sk.bind(("127.0.0.1",8000))
sk.listen(5)
while True:
conn, addr = sk.accept()
data = conn.recv(8096)
print(data) # 將瀏覽器發來的消息打印出來
conn.send(b"HTTP/1.1 200 0k\r\n\r\n<h1>OK</h1>")
根據不一樣的路徑返回不一樣的內容
import socket sk = socket.socket() sk.bind(("127.0.0.1", 8080)) # 綁定IP和端口 sk.listen() # 監聽 while True: # 等待鏈接 conn, add = sk.accept() data = conn.recv(8096) # 接收客戶端發來的消息 # 從data中取到路徑 data = str(data,encoding="utf-8") # 把收到的字節類型的數據轉換成字符串 # 按\r\n分割 data1 = data.split("\r\n")[0] url = data1.split()[1] # url是咱們從瀏覽器發過來的消息中分離出的訪問路徑 conn.send(b'HTTP/1.1 200 OK\r\n\r\n') # 由於要遵循HTTP協議,因此回覆的消息也要加狀態行 # 根據不一樣的路徑返回不一樣內容 if url == "/index/": response = b"index" elif url == "/home/": response = b"home" else: response = b"404 not found!" conn.send(response) conn.close()
根據不一樣的路徑返回不一樣的內容--函數版
import socket # 建立一個socket對象 sk = socket.socket() # 綁定IP和端口 sk.bind(('127.0.0.1', 8000)) # 監聽 sk.listen(5) # 等待鏈接 def index(url): ret = '<h1>index!</h1>({})'.format(url) return ret.encode('utf-8') def home(url): ret = '<h1>home!</h1>({})'.format(url) return ret.encode('utf-8') list1 = [ ('/index', index), ('/home', home), ] while True: conn, addr = sk.accept() # 接收數據 data = conn.recv(1024) data = data.decode('utf-8') url = data.split()[1] #先發送報頭 conn.send(b'HTTP/1.1 200 OK\r\n\r\n') func = None for i in list1: if url == i[0]: func = i[1] break if func: ret = func(url) else: ret = b'<h1>404 not found!</h1>' conn.send(ret) # 斷開鏈接 conn.close()
返回具體的HTML文件
import socket sk = socket.socket() sk.bind(("127.0.0.1", 8080)) # 綁定IP和端口 sk.listen() # 監聽 # 將返回不一樣的內容部分封裝成不一樣的函數 def index(url): #建立一個html文件,內容隨意 # 讀取index.html頁面的內容 with open("index.html", "r", encoding="utf8") as f: s = f.read() # 返回字節數據 return bytes(s, encoding="utf8") def home(url): #建立一個html文件,內容隨意 with open("home.html", "r", encoding="utf8") as f: s = f.read() return bytes(s, encoding="utf8") # 定義一個url和實際要執行的函數的對應關係 list1 = [ ("/index/", index), ("/home/", home), ] while True: # 等待鏈接 conn, add = sk.accept() data = conn.recv(8096) # 接收客戶端發來的消息 # 從data中取到路徑 data = str(data, encoding="utf8") # 把收到的字節類型的數據轉換成字符串 # 按\r\n分割 data1 = data.split("\r\n")[0] url = data1.split()[1] # url是咱們從瀏覽器發過來的消息中分離出的訪問路徑 conn.send(b'HTTP/1.1 200 OK\r\n\r\n') # 由於要遵循HTTP協議,因此回覆的消息也要加狀態行 # 根據不一樣的路徑返回不一樣內容 func = None # 定義一個保存將要執行的函數名的變量 for item in list1: if item[0] == url: func = item[1] break if func: response = func(url) else: response = b"404 not found!" # 返回具體的響應消息 conn.send(response) conn.close()
讓網頁動起來
import socket
sk = socket.socket()
sk.bind(("127.0.0.1", 8080)) # 綁定IP和端口
sk.listen() # 監聽
# 將返回不一樣的內容部分封裝成不一樣的函數
def index(url):
# 讀取index.html頁面的內容
with open("index.html", "r", encoding="utf8") as f:
s = f.read()
# 返回字節數據
return bytes(s, encoding="utf8")
def home(url):
with open("home.html", "r", encoding="utf8") as f:
s = f.read()
return bytes(s, encoding="utf8")
def timer(url):
import time
with open("time.html", "r", encoding="utf8") as f:
s = f.read()
s = s.replace('@@time@@', time.strftime("%Y-%m-%d %H:%M:%S"))
return bytes(s, encoding="utf8")
# 定義一個url和實際要執行的函數的對應關係
list1 = [
("/index/", index),
("/home/", home),
("/time/", timer),
]
while True:
# 等待鏈接
conn, add = sk.accept()
data = conn.recv(8096) # 接收客戶端發來的消息
# 從data中取到路徑
data = str(data, encoding="utf8") # 把收到的字節類型的數據轉換成字符串
# 按\r\n分割
data1 = data.split("\r\n")[0]
url = data1.split()[1] # url是咱們從瀏覽器發過來的消息中分離出的訪問路徑
conn.send(b'HTTP/1.1 200 OK\r\n\r\n') # 由於要遵循HTTP協議,因此回覆的消息也要加狀態行
# 根據不一樣的路徑返回不一樣內容
func = None # 定義一個保存將要執行的函數名的變量
for item in list1:
if item[0] == url:
func = item[1]
break
if func:
response = func(url)
else:
response = b"404 not found!"
# 返回具體的響應消息
conn.send(response)
conn.close()
python web程序通常會分爲兩部分:服務器程序和應用程序。
服務器程序負責對socket服務端進行封裝,並在請求到來時,對請求的各類數據進行整理。
應用程序則負責具體的邏輯處理。爲了方便應用程序的開發,就出現了衆多的Web框架,例如:Django、Flask、web.py 等。不一樣的框架有不一樣的開發方式,可是不管如何,開發出的應用程序都要和服務器程序配合,才能爲用戶提供服務。
WSGI(Web Server Gateway Interface)就是一種規範,它定義了使用Python編寫的web應用程序與web服務器程序之間的接口格式,實現web應用程序與web服務器程序間的解耦。經常使用的WSGI服務器有uWSGI、Gunicorn。而Python標準庫提供的獨立WSGI服務器叫wsgiref,Django開發環境用的就是這個模塊來作服務器。
利用wsgiref模塊來替換咱們本身寫的web框架的socket server部分:
""" 根據URL中不一樣的路徑返回不一樣的內容--函數進階版 返回HTML頁面 讓網頁動態起來 wsgiref模塊版 """ from wsgiref.simple_server import make_server # 將返回不一樣的內容部分封裝成函數 def index(url): # 讀取index.html頁面的內容 with open("index.html", "r", encoding="utf8") as f: s = f.read() # 返回字節數據 return bytes(s, encoding="utf8") def home(url): with open("home.html", "r", encoding="utf8") as f: s = f.read() return bytes(s, encoding="utf8") def timer(url): import time with open("time.html", "r", encoding="utf8") as f: s = f.read() s = s.replace('@@time@@', time.strftime("%Y-%m-%d %H:%M:%S")) return bytes(s, encoding="utf8") # 定義一個url和實際要執行的函數的對應關係 list1 = [ ("/index", index), ("/home", home), ("/time", timer), ] def run_server(environ, start_response): start_response('200 OK', [('Content-Type', 'text/html;charset=utf8'), ]) # 設置HTTP響應的狀態碼和頭信息 url = environ['PATH_INFO'] # 取到用戶輸入的url func = None for i in list1: if i[0] == url: func = i[1] break if func: response = func(url) else: response = b"404 not found!" return [response, ] if __name__ == '__main__': httpd = make_server('127.0.0.1', 8090, run_server) print("我在8090等你哦...") httpd.serve_forever()
index2.html文件
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta http-equiv="x-ua-compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Title</title> </head> <body> <h1>姓名:{{name}}</h1> <h1>愛好:</h1> <ul> {% for hobby in hobby_list %} <li>{{hobby}}</li> {% endfor %} </ul> </body> </html>
使用jinja2渲染index2.html文件:
from wsgiref.simple_server import make_server from jinja2 import Template def index(url): # 讀取HTML文件內容 with open("index2.html", "r", encoding="utf8") as f: data = f.read() template = Template(data) # 生成模板文件 ret = template.render({'name': 'alex', 'hobby_list': ['抽菸', '喝酒', '燙頭']}) # 把數據填充到模板中 return bytes(ret, encoding="utf8") def home(url): with open("home.html", "r", encoding="utf8") as f: s = f.read() return bytes(s, encoding="utf8") # 定義一個url和實際要執行的函數的對應關係 list1 = [ ("/index", index), ("/home", home), ] def run_server(environ, start_response): start_response('200 OK', [('Content-Type', 'text/html;charset=utf8'), ]) # 設置HTTP響應的狀態碼和頭信息 url = environ['PATH_INFO'] # 取到用戶輸入的url func = None for i in list1: if i[0] == url: func = i[1] break if func: response = func(url) else: response = b"404 not found!" return [response, ] if __name__ == '__main__': httpd = make_server('127.0.0.1', 8090, run_server) print("我在8090等你哦...") httpd.serve_forever()
使用pymysql鏈接數據庫:
conn = pymysql.connect(host="127.0.0.1", port=3306, user="root", passwd="xxx", db="xxx", charset="utf8") cursor = conn.cursor(cursor=pymysql.cursors.DictCursor) cursor.execute("select name, age, department_id from userinfo") user_list = cursor.fetchall() cursor.close() conn.close()
模板的原理就是字符串替換,咱們只要在HTML頁面中遵循jinja2的語法規則寫上,其內部就會按照指定的語法進行相應的替換,從而達到動態的返回內容。
MVC,全名是Model View Controller,是軟件工程中的一種軟件架構模式,把軟件系統分爲三個基本部分:模型(Model)、視圖(View)和控制器(Controller),具備耦合性低、重用性高、生命週期成本低等優勢。
深刻了解:http://www.ruanyifeng.com/blog/2007/11/mvc.html
Django框架的不一樣之處在於它拆分的三部分爲:Model(模型)、Template(模板)和View(視圖),也就是MTV框架。
Model(模型):負責業務對象與數據庫的對象(ORM)
ORM:對象關係映射
Template(模版):負責如何把頁面展現給用戶
View(視圖):負責業務邏輯,並在適當的時候調用Model和Template
此外,Django還有一個urls分發器,它的做用是將一個個URL的頁面請求分發給不一樣的view處理,view再調用相應的Model和Template
cmd命令行
pip install django==1.11.21
pip install django==1.11.21 -i 國內源
pycharm
file--->setting--->
命令行
建立一個文件夾用於存放項目文件,
shift + 鼠標右鍵 ----->點擊"在此處打開命令窗口(w)"
django-admin startproject 項目名稱
項目目錄
pycharm
命令行
cd 項目根目錄 ---------> manage.py
python36 manage.py runserver (默認是80端口)
python36 manage.py runserver 90 在80端口啓動
python36 manage.py runserver 0.0.0.0:80` 0.0.0.0:80
若是運行不成功,嘗試進行下面操做,而後重啓
pycharm
更改端口和ip
命令行
python36 manage.py startapp app01
pacharm工具建立
tools ——》 run manage.py task ——》 startapp app名稱
第三種建立方式
註冊app
INSTALLED_APPS = [ ... 'app01', 'app01.apps.App01Config' #推薦寫法 ]
將urls裏的兩個函數封裝到views.py中
而後再urls導入views.py
python manage.py makemigrations python manage.py migrate
python manage.py createsuperuser
輸入以上命令後,根據提示輸入用戶名、郵箱、密碼、確認密碼。密碼的要求至少是不八位,不能和郵箱太接近,兩次密碼須要一致。
簡單使用
模板 ——》HTML 指定文件夾
urls.py
# 導入 from django.shortcuts import HttpResponse,render # 函數 def index(request): # return HttpResponse('index') return render(request,'index.html') # url和函數對應關係 urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^index/', index), ]
from django.shortcuts import HttpResponse, render, redirect
HttpResponse
內部傳入一個字符串參數,返回給瀏覽器。
def index(request): # 業務邏輯代碼 return HttpResponse("OK")
render
除request參數外還接受一個待渲染的模板文件和一個保存具體數據的字典參數。將數據填充進模板文件,最後把結果返回給瀏覽器。
def index(request): # 業務邏輯代碼 return render(request, "index.html", {"name": "alex", "hobby": ["燙頭", "泡吧"]})
redirect
接受一個URL參數,表示跳轉到指定的URL。
def index(request): # 業務邏輯代碼 return redirect("https://www.baidu.com")
重定向
啓動Django報錯
Django 啓動時報錯 UnicodeEncodeError ...
報這個錯誤一般是由於計算機名爲中文,改爲英文的計算機名重啓下電腦就能夠了。
1.建立一個MySQL數據庫。
2.在settings中配置,Django鏈接MySQL數據庫:
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', # 引擎 'NAME': 'day53', # 數據庫名稱 'HOST': '127.0.0.1', # ip地址 'PORT':3306, # 端口 'USER':'root', # 用戶 'PASSWORD':'123' # 密碼,沒有時寫成'' } }
3.在與settings同級目錄下的 init文件中寫:
import pymysql pymysql.install_as_MySQLdb()
4.建立表結構(在app下的models.py中寫類)
from django.db import models class User(models.Model): username = models.CharField(max_lengh=32) #username varchar password = models.CharField(max_lengh=32) # password varchar
5.執行數據庫遷移的命令
python manage.py makemigrations # 檢測每一個註冊app下的model.py 記錄model的變動記錄 python manage.py migrate # 同步變動記錄到數據庫中
建立數據
提交數據
1.orm操做
# 獲取表中全部的數據 ret = models.User.objects.all() # QuerySet 對象列表 【對象】 # 獲取一個對象(有且惟一) obj = models.User.objects.get(username='alex') # 獲取不到或者獲取到多個對象會報錯 # 獲取知足條件的對象 ret = models.User.objects.filter(username='wusir',password='dasb') # QuerySet 對象列表
2.GET和 POST區別
從標準上來看
GET 用於獲取信息,是無反作用的,是冪等的,且可緩存
POST 用於修改服務器上的數據,有反作用,非冪等,不可緩存
從請求報文看
GET 和 POST 只是 HTTP 協議中兩種請求方式(殊途同歸),而 HTTP 協議是基於 TCP/IP 的應用層協議,不管 GET 仍是 POST,用的都是同一個傳輸層協議,因此在傳輸上,沒有區別。
報文格式上
不帶參數時,最大區別就是第一行方法名不一樣, 僅僅是報文的幾個字符不一樣而已,POST 方法請求報文第一行是這樣的 POST /url HTTP/1.1 GET 方法請求報文第一行是這樣的 GET /url HTTP/1.1
帶參數時,在約定中,GET 方法的參數應該放在 url 中,POST 方法參數應該放在 body 中
GET產生一個TCP數據包;POST產生兩個TCP數據包。
官方文檔連接:https://docs.djangoproject.com/en/1.11/ref/templates/language/
Django模板中只須要記兩種特殊符號:{{ }}表示變量,在模板渲染的時候替換成值,{% %}表示標籤,tag,表示邏輯相關的操做。
{{ 變量名 }}
變量名由字母數字和下劃線組成。
點(.)在模板語言中有特殊的含義,用來獲取對象的相應屬性值。
例:view中代碼
from django.shortcuts import render def template_text(request): string = 'dasb' age = 73 hobby = ['抽菸','喝酒','燙頭'] dic = {'name':'dalao','age':age,'hobby':hobby} return render(request,"template_test.html",{'string':string,'age':age,'hobby':hobby,'dic':dic})
模板中支持的寫法:
{# 取l中的第一個參數 #} {{ l.0 }} {# 取字典中key的值 #} {{ d.name }} {# 取對象的name屬性 #} {{ person_list.0.name }} {# .操做只能調用不帶參數的方法 #} {{ person_list.0.dream }}
注:當模板系統遇到一個(.)時,會按照以下的順序去查詢:
1.在字典中查詢
2.屬性或者方法
3.數字索引
過濾器,用來修改變量的顯示結果。
語法 : {{ value|filter_name:參數}}
':'左右沒有空格
default
{{ value|default:"nothing"}}
若是變量value不存在或者變量爲空的話就顯示nothing
注:TEMPLATES的OPTIONS能夠增長一個選項:string_if_invalid:"變量不存在",能夠替代default的的做用。
1.filesizeformat
文件大小格式化
{{ value|filesizeformat }}
範圍 : byte ~ PB
2.add
{{ value|add:"2" }}
例
{{2|add:4}} # 6 {{"2"|add:4}} # 6 {{"2"|add:"4"}} # 6 {{"2"|add:"asdf"}} #2asdf {{ first|add:second }} #若是first是 [1,.2,3] ,second是 [4,5,6] ,那輸出結果是 [1,2,3,4,5,6] #若是first是 ["抽菸",'喝酒',"燙頭"] ,second是 ["唱","跳","rap",'籃球'] ,那輸出結果是 ["抽菸",'喝酒',"燙頭","唱","跳","rap",'籃球'] #Django模版加法: {{ value|add:10}} value=5,則返回15 #Django模版減法: {{value|add:-10}} value=5,則返回-5,這個比較好理解,減法就是加一個負數 #Django模版乘法和除法: {% widthratio 5 1 100 %} 上面的代碼表示:5/1 *100,返回500,widthratio須要三個參數,它會使用 參數1/參數2*參數3,因此要進行乘法的話,就將參數2=1便可 #數據保留兩位小數 <td>{{ foo.product_amount|floatformat:5 }}</td> register = template.Library() #一些複雜一些的運算 利用 add 這個filter ,能夠作更瘋狂的事: 計算 A^2: {% widthratio A 1 A %} 計算 (A+B)^2: {% widthratio A|add:B 1 A|add:B %} 計算 (A+B) * (C+D): {% widthratio A|add:B 1 C|add:D %} #除法並保留小數 首先定義方法在templatehelper.py文件中 @register.filter def div(value, div): ''' 分轉化爲元,保留兩位小數 :param value: :param div: :return: ''' return round((value / div), 2) 而後在模板中能夠按照以下使用,固然前提是{% load templatehelper %}: <td>{{ foo.product_amount |div:100 }}</td>
3.lower
全小寫
{{value|lower}}
4.upper
全大寫
{{value|upper}}
5.title
標題,首字母大寫
{{value|title}}
6.length
計算長度
{{value|length}}
7.slice
切片
hobby = ["抽菸",'喝酒',"燙頭","唱","跳","rap",'籃球'] {{hobby|slice:'-2:0:-1'}} #["rap","跳","唱","燙頭",'喝酒']
8.first和last
9.join
使用字符串拼接列表。同python的str.join(list)。
{{ value|join:" // " }}
10.truncatechars
若是字符串字符多於指定的字符數量,那麼會被截斷。截斷的字符串將以可翻譯的省略號序列(「...」)結尾。
參數:截斷的字符數 {{ value|truncatechars:9}}
long_str = "you have 13 years to go to anthers" {{long_str|truncatechars:10}} # you hav... {{long_str|truncatechars:3}} # ... {{long_str|truncatewords:3}} # you have 13 years... long_str = "咱也不知道,咱也不敢問" {{long_str|truncatewords:3}} #咱也不知道,咱也不敢問 (不識別中文) {{long_str|truncatechars:3}} # ... {{long_str|truncatechars:4}} # 咱...
11.date
日期格式化
{{ value|date:"Y-m-d H:i:s"}}
可格式化輸出的字符連接網址:https://docs.djangoproject.com/en/1.11/ref/templates/builtins/#date
另外一種修改方式
setting中的配置:
USE_L10N = False DATETIME_FORMAT = 'Y-m-d H:i:s'
12.safe
Django的模板中會對HTML標籤和JS等語法標籤進行自動轉義,緣由顯而易見,這樣是爲了安全。可是有的時候咱們可能不但願這些HTML元素被轉義,好比咱們作一個內容管理系統,後臺添加的文章中是通過修飾的,這些修飾多是經過一個相似於FCKeditor編輯加註了HTML修飾符的文本,若是自動轉義的話顯示的就是保護HTML標籤的源文件。爲了在Django中關閉HTML的自動轉義有兩種方式,若是是一個單獨的變量咱們能夠經過過濾器「|safe」的方式告訴Django這段代碼是安全的沒必要轉義。
value = "<a href='#'>點我</a>" {{ value|safe}}
1.在app01下建立一個名爲templatetags的文件包(必須爲此名字)
2.在該python包建立py文件,文件名自定義(my_tags.py);
3..在py文件中寫:
from django import template register = template.Library() # register也不能變
4.寫函數+裝飾器
@register.filter def add_xx(value, arg): # 最多有兩個 return '{}-{}'.format(value, arg)
5.使用:
{% load my_tags %} {{ 'alex'|add_xx:'dsb' }}
錯誤
解決: 一:重啓項目
1.for
<ul> {% for hobby in hobby_list %} <li> {{ forloop.counter }}.{{ hobby }} </li> {% endfor %} </ul>
for循環可用的一些參數:
Variable | Description |
---|---|
forloop.counter |
當前循環的索引值(從1開始) |
forloop.counter0 |
當前循環的索引值(從0開始) |
forloop.revcounter |
當前循環的倒序索引值(到1結束) |
forloop.revcounter0 |
當前循環的倒序索引值(到0結束) |
forloop.first |
當前循環是否是第一次循環(布爾值) |
forloop.last |
當前循環是否是最後一次循環(布爾值) |
forloop.parentloop |
本層循環的外層循環 |
偶數列爲紅色
<table border="1"> <tbody> {% for hobby_list1 in hobby_list2 %} <tr> {% for hobby in hobby_list1 %} {% if forloop.counter|divisibleby:2 %} <td style="color: red;">{{ hobby }}</td> {% else %} <td >{{ hobby }}</td> {% endif %} {% endfor %} </tr> {% endfor %} </tbody> </table>
2.for....empty
<ul> {% for user in user_list %} <li>{{ user.name }}</li> {% empty %} <li>空空如也</li> {% endfor %} </ul>
3.if
if,elif和else
if,else
if語句支持 and 、or、==、>、<、!=、<=、>=、in、not in、is、is not判斷。
{% if age < 73 %} 還沒到73歲 {% elif age == 73 %} 恰好73歲 {% elif age > 73 %} 過了73歲 {% endif %}
注意 :
python中 :10>5>1 =》 10>5 and 5>1 true
js :10>5>1 =》 10>5 =》 true =》 1>1 false
模板中 不支持連續連續判斷 也不支持算數運算(可用過濾器判斷)
4.with
#寫法一:只在with裏生效 {% with hobby_list2.2.3 as hobby %} {{ hobby }} {{ hobby }} {{ hobby }} {% endwith %} <br> #寫法二:只在with裏生效 {% with hobby=hobby_list2.2.3 %} {{ hobby }} {{ hobby }} {{ hobby }} {% endwith %}
<!--{{'不顯示'}}-->
1.母版
就是一個普通HTML提取多個頁面的公共部分 定義block塊
繼承母版和塊(block)
{% extends ‘base.html’ %}
重寫block塊 —— 寫子頁面獨特的內容
#注意: 1.{% extends 'base.html' %} 寫在第一行 前面不要有內容 有內容會顯示 2.把要顯示的內容寫在block塊中 3.{% extends 'base.html' %} 'base.html' 須要加上引號 否則當作變量去查找 4.定義多個block塊,定義 css js 塊
能夠將經常使用的頁面內容如導航條,頁尾信息等組件保存在單獨的文件中,而後在須要使用的地方按以下語法導入便可。(例: "nav.html")
{% include 'navbar.html' %}
{% load static %} /*{% load staticfiles %} */ <link rel="stylesheet" href="{% static '/plugins/bootstrap-3.3.7/css/bootstrap.css' %}"> <link rel="stylesheet" href="{% static '/css/dsb.css' %}"> /*另外一種寫法*/ <link rel="stylesheet" href="{% get_static_prefix %}/css/dsb.css"> {% static '/plugins/bootstrap-3.3.7/css/bootstrap.css' %} {% get_static_prefix %} ——》 獲取別名
和自定義filter相似,只不過接收更靈活的參數。
@register.simple_tag def join_str(*args, **kwargs): return '{} - {} '.format('*'.join(args), '$'.join(kwargs.values()))
#使用 {% load my_tags %} {% join_str '1' '2' k1='3' k2='4' %}
返回一個html代碼段
在settings.py寫入下面代碼
STATIC_URL = '/static/' # 別名 ,HTML中使用的靜態文件夾前綴 STATICFILES_DIRS = [ os.path.join(BASE_DIR, 'static1'), ## 靜態文件存放位置,按照STATICFILES_DIRS列表的順序進行查找。 os.path.join(BASE_DIR, 'static'), os.path.join(BASE_DIR, 'static2'), ]
<link rel="stylesheet" href="/static/css/login.css"> # 別名開頭
一個視圖函數(類),簡稱視圖,是一個簡單的Python 函數(類),它接受Web請求而且返回Web響應。響應能夠是一張網頁的HTML內容,一個重定向,一個404錯誤,一個XML文檔,或者一張圖片。
不管視圖自己包含什麼邏輯,都要返回響應。代碼寫在哪裏也無所謂,只要它在你當前項目目錄下面。
爲了將代碼放在某處,你們約定成俗將視圖放置在項目(project)或應用程序(app)目錄中的名爲views.py
的文件中。
FBV function based view (基於函數的視圖)
CBV class based biew (基於類的視圖)
FBV寫法:
from django.shortcuts import HttpResponse,render,redirect #新增出版社 def add_publisher(request): #對請求方式進行判斷 error = '' if request.method == 'POST': #處理POST請求 #獲取出版社名稱 publisher_name = request.POST.get('publisher_name') #判斷出版社名稱是否重複 if models.publisher.objects.filter(name=publisher_name): error = "出版社名稱已存在" #判斷輸入值是否爲空 if not publisher_name: error = "輸入不能爲空" if not error: #使用orm將數據插入到數據庫中 obj = models.publisher.objects.create(name=publisher_name) print(obj.pk,obj.name) #跳轉到展現出版社界面 return redirect('/publisher_list/') #返回一個包含form表單的頁面 return render(request,'add_publisher.html',{'error':error})
CBV 寫法
from django.shortcuts import HttpResponse,render,redirect #類方法寫新增出版社 from django.views import View class Addpublisher(View): def get(self,request): #處理get請求 return render(request,'add_publisher.html') def post(self,request): # 處理post請求 # 處理POST請求 error = '' # 獲取出版社名稱 publisher_name = request.POST.get('publisher_name') # 判斷出版社名稱是否重複 if models.publisher.objects.filter(name=publisher_name): error = "出版社名稱已存在" # 判斷輸入值是否爲空 if not publisher_name: error = "輸入不能爲空" if not error: # 使用orm將數據插入到數據庫中 obj = models.publisher.objects.create(name=publisher_name) print(obj.pk, obj.name) # 跳轉到展現出版社界面 return redirect('/publisher_list/') return render(request,'add_publisher.html',{'error':error})
#路徑修改成 url(r'^add_publisher/', views.Addpublisher.as_view()),
as_view的流程
1.項目啓動,加載urls.py時,執行 類.as_view() ,獲得了一個view函數
2.請求到來時執行view函數
1.實例化類------->對象 selef.request = request
2.執行self.dispatch(request, *args, **kwargs)
判斷請求方式是否被容許
容許 :經過反射獲取到對應請求方式的方法,賦值給handler
不容許:將self.http_method_not_allowed賦值給handler
執行handler(request,*args,**kwargs),返回結果給jango,再給瀏覽器
FBV : 直接加裝飾器
from django.shortcuts import HttpResponse,render,redirect from app01 import models import time def timer(func): def inner(*args,**kwargs): start = time.time() ret = func(*args,**kwargs) print('函數執行時間爲{}'.format(time.time()-start)) return ret return inner #展現出版社 @timer def publisher_list(request): #從數據庫中查詢出版社信息 all_publishers = models.publisher.objects.all().order_by("pk") #返回一個包含出版社信息的頁面 return render(request,'publisher_list.html',{'all_publishers':all_publishers})
CBV :
from django.shortcuts import HttpResponse,render,redirect from app01 import models from django.utils.decorators import method_decorator import time def timer(func): def inner(*args,**kwargs): start = time.time() ret = func(*args,**kwargs) print('函數執行時間爲{}'.format(time.time()-start)) return ret return inner
加在方法上
class Addpublisher(View): @method_decorator(timer) def get(self,request): #處理get請求 return render(request,'add_publisher.html')
加在本身寫的dispatch上(推薦)
class Addpublisher(View): @method_decorator(timer) def dispatch(self,request,*args,**kwargs): ret = super().dispatch(request,*args,**kwargs) return ret
加在類上
@method_decorator(timer,name='get') @method_decorator(timer,name='post') class Addpublisher(View): def dispatch(self,request,*args,**kwargs): ret = super().dispatch(request,*args,**kwargs) return ret def get(self,request): pass def post(self,request,*args,**kwargs): pass
#還能夠這樣寫 @method_decorator(timer,name='dispatch') def get(self,request): pass def post(self,request,*args,**kwargs): pass
不使用method_decorator也會出結果
注:使用或者不使用method_decorator的區別
不使用method_decorator
func :結果爲 <function AddPublisher.get at 0x000001FC8C358598>
args : 結果爲 (<app01.views.AddPublisher object at 0x000001FC8C432C50>, <WSGIRequest: GET '/add_publisher/'>)
使用method_decorator
func ——》 <function method_decorator.<locals>.dec.<locals>.wrapper.<locals>.bound_func at 0x0000015185F7C0D0>
args ——》 (<WSGIRequest: GET '/add_publisher/'>,)
當一個頁面被請求時,Django就會建立一個包含本次請求原信息的HttpRequest對象。Django會將這個對象自動傳遞給響應的視圖函數,通常視圖函數約定俗成地使用 request 參數承接這個對象。官方文檔連接:https://docs.djangoproject.com/en/1.11/ref/request-response/
請求經常使用值
request.method 請求方法,請求中使用的HTTP方法的字符串表示,全大寫 request.GET url上攜帶的參數,包含全部HTTP GET參數的類字典對象 request.POST post請求攜帶的數據,包含全部HTTP POST參數的類字典對象 request.path request.path_info URL的路徑 不包含ip和端口 不包含參數 request.body 請求體 b''類型
屬性
django將請求報文中的請求行、頭部信息、內容主體封裝成 HttpRequest 類中的屬性。除了特殊說明的以外,其餘均爲只讀的。
序號 | 屬性 | 結果 |
---|---|---|
1 | request.scheme | 表示請求方案的字符串(一般爲http或https) |
2 | request.body | 請求體爲 b''類型 |
3 | request.path | 一個字符串,表示請求的路徑組件(不含域名)。 |
4 | request.method | 一個字符串,表示請求使用的HTTP 方法。必須使用大寫 |
5 | request.encoding | 一個字符串,表示提交的數據的編碼方式(若是爲 None 則表示使用 DEFAULT_CHARSET 的設置,默認爲 'utf-8') |
6 | request.GET | url上攜帶的參數,包含全部HTTP GET參數的QueryDict 對象 |
7 | request.POST | post請求攜帶的數據,包含全部HTTP POST參數的QueryDict對象 |
8 | request.COOKIES | 一個標準的Python 字典,包含全部的cookie。鍵和值都爲字符串 |
9 | request.FILES | 一個相似於字典的對象,包含全部的上傳文件信息。 FILES 中的每一個鍵爲<input type="file" name="" /> 中的name,值則爲對應的數據。注意,FILES 只有在請求的方法爲POST 且提交的<form> 帶有enctype="multipart/form-data" 的狀況下才會 包含數據。不然,FILES 將爲一個空的相似於字典的對象。 |
10 | request.META | 一個標準的Python 字典,包含全部的HTTP 首部。具體的頭部信息取決於客戶端和服務器 |
11 | request.user | 一個 AUTH_USER_MODEL 類型的對象,表示當前登陸的用戶。(模塊) |
12 | request.session | 一個既可讀又可寫的相似於字典的對象,表示當前的會話。只有當Django 啓用會話的支持時纔可用。 |
request.FILES
<form action="" method="post" enctype="multipart/form-data"> {% csrf_token %} <input type="file" name="f1"> <button>上傳</button> </form>
def upload(request): if request.method == 'POST': #獲取文件 print(request.FILES) #<MultiValueDict: {'f1': [<InMemoryUploadedFile: S80903-190319(1).jpg (image/jpeg)>]}> f1 = request.FILES.get('f1') #保存文件 with open(f1.name ,'wb') as f: for i in f1.chunks(): f.write(i) return render(request,'upload.html')
方法
request.get_full_path() URL的路徑 不包含ip和端口 包含參數 request.get_host() 獲取主機的ip和端口 request.is_secure() request.is_ajax() 判斷是都是ajax請求
HttpResponse('字符串') #返回字符串 content-type = 'text/html' render(request,'模板文件名',{k1:v1}) #返回一個完整的html頁面 redirect('重定向地址') #重定向 本質 : 響應頭Location:地址
from django.http.response import JsonResponse import json def json_data(request): data = {'name':'liming','age':18} ret = HttpResponse(json.dumps(data)) ret['Content-Type'] = application/json return ret #return HttpResponse(json.dumps(data)) #Content-Type: text/html; charset=utf-8 return JsonResponse(data) #Content-Type: application/json 會本身作反序列化
from django.http.response import JsonResponse def json_data(request): #當被傳入數據爲列表時,要加上safe=False data = [1,2,3,4] return JsonResponse(data,safe=False)
URL配置(URLconf)就像Django所支撐網站的目錄。它的本質是URL與要爲該URL調用的視圖函數之間的映射表。咱們就是以這種方式告訴Django,遇到哪一個URL的時候,要對應執行哪一個函數。
基本格式
from django.conf.urls import url urlpatterns = [ url(正則表達式, views視圖,參數,別名), ]
參數說明
正則表達式:一個正則表達式字符串
views視圖:一個可調用對象,一般爲一個視圖函數
參數:可選的要傳遞給視圖函數的默認參數(字典形式)
別名:一個可選的name參數
示例
#1.0寫法 from django.conf.urls import url from . import views urlpatterns = [ url(r'^articles/2003/$', views.special_case_2003), url(r'^articles/([0-9]{4})/$', views.year_archive), url(r'^articles/([0-9]{4})/([0-9]{2})/$', views.month_archive), url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.article_detail), ]
#2.0寫法 from django.urls import path,re_path urlpatterns = [ path('articles/2003/', views.special_case_2003), path('articles/<int:year>/', views.year_archive), path('articles/<int:year>/<int:month>/', views.month_archive), path('articles/<int:year>/<int:month>/<slug:slug>/', views.article_detail), ]
Django 2.0版本中的路由系統是下面的寫法官方連接:https://docs.djangoproject.com/en/1.11/topics/http/urls/
from app01 import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^blog/', views.blog), url(r'^blog/[0-9]{4}', views.blogs), ]
注意事項
1.urlpatterns中的元素按照書寫順序從上到下逐一匹配正則表達式,一旦匹配成功則再也不繼續
2.不須要添加一個簽到的反斜槓,由於每一個URL 都有。例如,應該是^articles 而不是 ^/articles。
3.每一個正則表達式前面的"r"可選但建議加上
4.若要從URL中捕獲一個值,只須要在它周圍放置一對圓括號(分組匹配)
補充說明
# 是否開啓URL訪問地址後面不爲/跳轉至帶有/的路徑的配置項 APPEND_SLASH=True
若是在settings.py中設置了 APPEND_SLASH=False,此時咱們再請求 時就會提示找不到頁面。
Django settings.py配置文件中默認沒有 APPEND_SLASH 這個參數,但 Django 默認這個參數爲 APPEND_SLASH = True。 其做用就是自動在網址結尾加'/'。
谷歌瀏覽器清除緩存方式 : ctrl + shift + delete
1.分組和命名分組
from app01 import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^blog/([0-9]{4})', views.blogs), #分組,將捕獲的參數按位置傳參傳遞給視圖函數
url(r'^blog/(?P<year>[0-9]{4})', views.blogs) #命名組,將捕獲的參數按關鍵字傳參傳遞給視圖函數
]
項目的修改:
2.捕獲的參數永遠都是字符串
每一個在URLconf中捕獲的參數都做爲一個普通的Python字符串傳遞給視圖,不管正則表達式使用的是什麼匹配方式。例如,下面這行URLconf 中:
url(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),
傳遞到視圖函數views.year_archive()
中的year
參數永遠是一個字符串類型
3.視圖函數中的指定默認值
# urls.py中 from django.conf.urls import url from . import views urlpatterns = [ url(r'^blog/$', views.page), url(r'^blog/page(?P<num>[0-9]+)/$', views.page), ] # views.py中,能夠爲num指定默認值 def page(request, num="1"): pass
在上面的例子中,兩個URL模式指向相同的view - views.page - 可是第一個模式並無從URL中捕獲任何東西。若是第一個模式匹配上了,page()函數將使用其默認參數num=「1」,若是第二個模式匹配,page()將使用正則表達式捕獲到的num值。
4.include其餘的URLconfs
urlpatterns = [ # url(r'^admin/', admin.site.urls), url(r'^app01/', include('app01.urls')), ]
app01.urls
from django.conf.urls import url from . import views urlpatterns = [ # url(r'^admin/', admin.site.urls), url(r'^blog/$', views.blog), url(r'^blog/(?P<year>[0-9]{4})/(?P<month>\d{2})/$', views.blogs), ]
django.conf.urls.url()
能夠接收一個可選的第三個參數,它是一個字典,表示想要傳遞給視圖函數的額外關鍵字參數。
from django.conf.urls import url from . import views urlpatterns = [ url(r'^blog/(?P<year>[0-9]{4})/$', views.year_archive, {'foo': 'bar'}), ]
在這個例子中,對於/blog/2005/請求,Django 將調用views.year_archive(request, year='2005', foo='bar')。 當傳遞額外參數的字典中的參數和URL中捕獲值的命名關鍵字參數同名時,函數調用時將使用的是字典中的參數,而不是URL中捕獲的參數。
1.命名
靜態路由
from django.conf.urls import url,include from django.contrib import admin from . import views urlpatterns = [ url(r'blog',views.blog,name='blog') ]
反向解析
app01 / urls.py
from django.conf.urls import url,include from django.contrib import admin from . import views urlpatterns = [ #url(r'^admin/', admin.site.urls), url(r'blog',views.blog,name='blog'), url(r'index',views.index) ]
模板
<a href="{% url 'blog' %}">博客</a>
python文件中
from django.shortcuts import reverse def blog(request): url = reverse('index') print(url,type(url)) return HttpResponse('OK')
動態路由
模板中
{% url 'blogs' 2222 12 %}" ——》 /blog/2222/12/ {% url 'blogs' year=2222 month=12 %}" ——》 /blog/2222/12/
py文件中
from django.urls import reverse reverse('blogs',args=('2019','06')) ——》 /app01/blog/2019/06/ reverse('blogs',kwargs={'year':'2019','month':'06'}) ——》 /app01/blog/2019/06/
即便不一樣的APP使用相同的URL名稱,URL的命名空間模式也可讓你惟一反轉命名的URL。
例:project中的urls.py
from django.conf.urls import url, include urlpatterns = [ url(r'^app01/', include('app01.urls', namespace='app01')), url(r'^app02/', include('app02.urls', namespace='app02')), ]
app01中的urls.py
from django.conf.urls import url from app01 import views app_name = 'app01' urlpatterns = [ url(r'^(?P<pk>\d+)/$', views.detail, name='detail')
app02中的urls.py
from django.conf.urls import url from app02 import views app_name = 'app02' urlpatterns = [ url(r'^(?P<pk>\d+)/$', views.detail, name='detail')
如今,個人兩個app中 url名稱重複了,我反轉URL的時候就能夠經過命名空間的名稱獲得我當前的URL。
語法:'命名空間名稱:URL名稱'
模板中使用:
{% url 'app01:detail' pk=12 pp=99 %}
views中的函數中使用
v = reverse('app01:detail', kwargs={'pk':11})
這樣即便app中URL的命名相同,我也能夠反轉獲得正確的URL了。
對象關係映射(Object Relational Mapping,簡稱ORM)模式是一種爲了解決面向對象與關係數據庫存在的互不匹配的現象的技術。簡單的說,ORM是經過使用描述對象和數據庫之間映射的元數據,將程序中的對象自動持久化到關係數據庫中,ORM在業務邏輯層和數據庫層之間充當了橋樑的做用。
ORM的優點 | ORM的劣勢 |
---|---|
ORM解決的主要問題是對象和關係的映射。它一般將一個類和一張表一一對應,類的每一個實例對應表中的一條記錄,類的每一個屬性對應表中的每一個字段。 ORM提供了對數據庫的映射,不用直接編寫SQL代碼,只需操做對象就能對數據庫操做數據。讓軟件開發人員專一於業務邏輯的處理,提升了開發效率。 | ORM的缺點是會在必定程度上犧牲程序的執行效率。ORM的操做是有限的,也就是ORM定義好的操做是能夠完成的,一些複雜的查詢操做是完成不了。ORM用多了SQL語句就不會寫了,關係數據庫相關技能退化... |
1.經常使用字段
序號 | 經常使用字段 | 含義 |
---|---|---|
1 | AutoField | 自增的整形字段,必填參數primary_key=True,則成爲數據庫的主鍵。無該字段時,django自動建立。一個model不能有兩個AutoField字段。 |
2 | CharField | 字符類型,必須提供max_length參數。max_length表示字符的長度。 |
3 | IntegerField | 一個整數類型。數值的範圍是 -2147483648 ~ 2147483647。 |
4 | DateField | 日期類型,日期格式爲YYYY-MM-DD,至關於Python中的datetime.date的實例。 |
5 | DatetimeField | 日期時間字段,格式爲YYYY-MM-DD HH:MM:ss[.uuuuuu],至關於Python中的datetime.datetime的實例。 |
6 | DecimalField | 10進制小數,參數:max_digits,小數總長度5位 decimal_places,小數位長度2位 |
7 | BooleanField | 布爾值類型 |
8 | TextField | 文本 |
BooleanField和DecimalField中屬性
auto_now = True:新增、修改數據的時候會自動保存當前的時間
auto_now_add = True:新增數據的時候會自動保存當前的時間
default 默認值
三者互斥,只能取其一
其它字段
AutoField(Field) - int自增列,必須填入參數 primary_key=True BigAutoField(AutoField) - bigint自增列,必須填入參數 primary_key=True 注:當model中若是沒有自增列,則自動會建立一個列名爲id的列 from django.db import models class UserInfo(models.Model): # 自動建立一個列名爲id的且爲自增的整數列 username = models.CharField(max_length=32) class Group(models.Model): # 自定義自增列 nid = models.AutoField(primary_key=True) name = models.CharField(max_length=32) SmallIntegerField(IntegerField): - 小整數 -32768 ~ 32767 PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField) - 正小整數 0 ~ 32767 IntegerField(Field) - 整數列(有符號的) -2147483648 ~ 2147483647 PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField) - 正整數 0 ~ 2147483647 BigIntegerField(IntegerField): - 長整型(有符號的) -9223372036854775808 ~ 9223372036854775807 NullBooleanField(Field): - 能夠爲空的布爾值 CharField(Field) - 字符類型 - 必須提供max_length參數, max_length表示字符長度 EmailField(CharField): - 字符串類型,Django Admin以及ModelForm中提供驗證機制 IPAddressField(Field) - 字符串類型,Django Admin以及ModelForm中提供驗證 IPV4 機制 GenericIPAddressField(Field) - 字符串類型,Django Admin以及ModelForm中提供驗證 Ipv4和Ipv6 - 參數: protocol,用於指定Ipv4或Ipv6, 'both',"ipv4","ipv6" unpack_ipv4, 若是指定爲True,則輸入::ffff:192.0.2.1時候,可解析爲192.0.2.1,開啓此功能,須要protocol="both" URLField(CharField) - 字符串類型,Django Admin以及ModelForm中提供驗證 URL SlugField(CharField) - 字符串類型,Django Admin以及ModelForm中提供驗證支持 字母、數字、下劃線、鏈接符(減號) CommaSeparatedIntegerField(CharField) - 字符串類型,格式必須爲逗號分割的數字 UUIDField(Field) - 字符串類型,Django Admin以及ModelForm中提供對UUID格式的驗證 FilePathField(Field) - 字符串,Django Admin以及ModelForm中提供讀取文件夾下文件的功能 - 參數: path, 文件夾路徑 match=None, 正則匹配 recursive=False, 遞歸下面的文件夾 allow_files=True, 容許文件 allow_folders=False, 容許文件夾 FileField(Field) - 字符串,路徑保存在數據庫,文件上傳到指定目錄 - 參數: upload_to = "" 上傳文件的保存路徑 storage = None 存儲組件,默認django.core.files.storage.FileSystemStorage ImageField(FileField) - 字符串,路徑保存在數據庫,文件上傳到指定目錄 - 參數: upload_to = "" 上傳文件的保存路徑 storage = None 存儲組件,默認django.core.files.storage.FileSystemStorage width_field=None, 上傳圖片的高度保存的數據庫字段名(字符串) height_field=None 上傳圖片的寬度保存的數據庫字段名(字符串) DateTimeField(DateField) - 日期+時間格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ] DateField(DateTimeCheckMixin, Field) - 日期格式 YYYY-MM-DD TimeField(DateTimeCheckMixin, Field) - 時間格式 HH:MM[:ss[.uuuuuu]] DurationField(Field) - 長整數,時間間隔,數據庫中按照bigint存儲,ORM中獲取的值爲datetime.timedelta類型 FloatField(Field) - 浮點型 BinaryField(Field) - 二進制類型
2.自定義字段
#app01/models.py class MyCharField(models.Field): """ 自定義的char類型的字段類 """ def __init__(self, max_length, *args, **kwargs): self.max_length = max_length super(MyCharField, self).__init__(max_length=max_length, *args, **kwargs) def db_type(self, connection): """ 限定生成數據庫表的字段類型爲char,長度爲max_length指定的值 """ return 'char(%s)' % self.max_length
#使用自定義char類型字段 class Class(models.Model): id = models.AutoField(primary_key=True) title = models.CharField(max_length=25) # 使用自定義的char類型的字段 cname = MyCharField(max_length=25)
3.字段參數
1.null 數據庫中字段是否能夠爲空 2.db_index 索引 3.blank form表單中是否容許用戶輸入爲空 4.db_index 數據庫中字段是否能夠創建索引 5.db_column 數據庫中字段的列名 6.default 數據庫中字段的默認值 7.primary_key 數據庫中字段是否爲主鍵 8.unique 數據庫中字段是否能夠創建惟一索引 9.verbose_name Admin中顯示的字段名稱 unique_for_date 數據庫中字段【日期】部分是否能夠創建惟一索引 unique_for_month 數據庫中字段【月】部分是否能夠創建惟一索引 unique_for_year 數據庫中字段【年】部分是否能夠創建惟一索引 editable Admin中是否能夠編輯(不顯示) help_text Admin中該字段的提示信息 choices Admin中顯示選擇框的內容,用不變更的數據放在內存中從而避免跨表操做
超級用戶的建立
from django.contrib import admin from app01 import models admin.site.register(models.Person)
class Person(models.Model): pid = models.AutoField(primary_key=True) name = models.CharField(max_length=32,db_column='username',verbose_name='姓名') #會將數據庫中字段名字修改成username age = models.IntegerField() birth = models.DateTimeField(auto_now_add=True) phone = MyCharField(max_length=11,blank=True,null=True,verbose_name='手機號') gender = models.BooleanField('性別',choices=((0,'女'),(1,'男')))
4.表的參數
class Person(models.Model): pid = models.AutoField(primary_key=True) age = models.IntegerField() class Meta: db_table = 'person' #表名 verbose_name = '我的信息' verbose_name_plural = '我的信息' # 聯合索引 index_together = [("name", "age"), ] # 應爲兩個存在的字段 # 聯合惟一索引 unique_together = (("name", "age"),) # 應爲兩個存在的字段
官方文檔連接:https://docs.djangoproject.com/en/1.11/ref/models/querysets/
1.通常操做(必知必會13條)
#返回 Queryset all filter exclude values values_list order_by reverse distinct() #返回對象 get first last #返回數字 count #返回布爾值 exists
import os if __name__ == '__main__': os.environ.setdefault("DJANGO_SETTINGS_MODULE", "test61.settings") import django django.setup() from app01 import models #1 .all() 獲取全部的數據 ---->>QuerySet 對象列表 ret = models.Person.objects.all() print(ret) #<QuerySet [<Person: 1-alex>, <Person: 2-eric>, <Person: 3-zhang>, <Person: 4-li>]> #2 .get(**kwargs) 獲取知足條件的一個數據 --->> 對象 #獲取不到或多個都會報錯 ret = models.Person.objects.get(pk=1) print(ret) #1-alex #3 .filter(**kwargs) 獲取知足條件的全部數據 ---->>QuerySet 對象列表 #若沒有,就返回一個空列表 ret = models.Person.objects.filter(gender=0) print(ret) #<QuerySet [<Person: 1-alex>, <Person: 2-eric>, <Person: 3-zhang>]> #4 .exclude(**kwargs) 排除不知足條件的全部數據 ---->>QuerySet 對象列表 ret = models.Person.objects.exclude(pk=1) print(ret) #<QuerySet [<Person: 2-eric>, <Person: 3-zhang>, <Person: 4-li>]> #5 .values() 拿到對象全部的字段和字段的值---->>QuerySet [{},{}.{}] 內爲字典 #.values('字段名稱') 拿到對象指定的字段和字段的值---->>QuerySet [{},{}.{}] ret = models.Person.objects.values() for i in ret: print(i) ret = models.Person.objects.values('pid','name') for i in ret: print(i) #6 .values_list() 拿到對象全部的字段和字段的值---->>QuerySet [(),().()] 內爲元組 # .values_list('字段名稱') 拿到對象指定的字段和字段的值---->>QuerySet [(),().()] 內爲元組 ret = models.Person.objects.values_list() for i in ret: print(i) ret = models.Person.objects.values_list('pid', 'name') #結果按()內給定位置排序 for i in ret: print(i) #7 .order_by('字段名稱') 對查詢結果排序---->>QuerySet ret = models.Person.objects.all().order_by('pk') #升序 print(ret) #<QuerySet [<Person: 1-alex>, <Person: 2-eric>, <Person: 3-zhang>, <Person: 4-li>]> ret = models.Person.objects.all().order_by('-pk') # 降序 print(ret) #<QuerySet [<Person: 4-li>, <Person: 3-zhang>, <Person: 2-eric>, <Person: 1-alex>]> ret = models.Person.objects.all().order_by('age','-pid') # 降序 print(ret) #<QuerySet [<Person: 1-alex>, <Person: 3-zhang>, <Person: 2-eric>, <Person: 4-li>]> #8 .reverse() 反向排序(只能對已經排序的QuerySet進行排序) ret = models.Person.objects.all() # 升序 print(ret) #<QuerySet [<Person: 1-alex>, <Person: 2-eric>, <Person: 3-zhang>, <Person: 4-li>]> ret = models.Person.objects.all().order_by('pk').reverse() print(ret) #<QuerySet [<Person: 4-li>, <Person: 3-zhang>, <Person: 2-eric>, <Person: 1-alex>]> #9 .distinct() 去重(只有在PostgreSQL中支持按字段去重)徹底相同的內容才能去重 ret = models.Person.objects.all().distinct() print(ret) #10 .count() 計數 ret = models.Person.objects.all().count() print(ret) #11 .first() 取第一個元素,沒有就爲None ret = models.Person.objects.filter(pk=1).first() print(ret) ret = models.Person.objects.filter(pk=1).values().first() print(ret) #12 .last() 取最後一個元素,沒有就爲None ret = models.Person.objects.filter(pk=1).first() print(ret) #13 .exists() 查詢的數據是否存在 ret = models.Person.objects.filter(pk=100).first() print(ret)
2.單表的雙下劃綫
import os os.environ.setdefault("DJANGO_SETTINGS_MODULE", "test61.settings") import django django.setup() from app01 import models ret = models.Person.objects.filter(pk=1) print(ret) ret = models.Person.objects.filter(pk__gt=1) #gt greater than 大於 print(ret) ret = models.Person.objects.filter(pk__lt=3) #gt less than 小於 print(ret) ret = models.Person.objects.filter(pk__gte=1) #gt greater than equal 大於等於 print(ret) ret = models.Person.objects.filter(pk__lte=3) #gt less than equal 小於等於 print(ret) ret = models.Person.objects.filter(pk__range=[2,3]) # 2<=pk<=3連續 print(ret) ret = models.Person.objects.filter(pk__in=[1,3]) # 成員判斷,在列表裏,1和3 print(ret) ret = models.Person.objects.filter(name__contains='a') # 獲取name字段包含"a"的 print(ret) ret = models.Person.objects.filter(name__contains='a') # icontains大小寫不敏感 print(ret) ret = models.Person.objects.filter(name__startswith='a') # name字段以'a'開頭 print(ret) ret = models.Person.objects.filter(name__istartswith='a') # 大小寫不敏感 print(ret) ret = models.Person.objects.filter(name__endswith='a') # name字段以'a'結尾 print(ret) ret = models.Person.objects.filter(name__iendswith='a') # 大小寫不敏感 print(ret) ret = models.Person.objects.filter(birth__year='2019') #出生年份爲2019年(不支持月份和日) print(ret) ret = models.Person.objects.filter(birth__contaits='2019-06') print(ret) ret = models.Person.objects.filter(phone__isnull=True) print(ret)
3.外鍵操做
import os os.environ.setdefault("DJANGO_SETTINGS_MODULE", "test61.settings") import django django.setup() from app01 import models #基於對象的查詢 #正向 book_obj = models.Book.objects.get(title='菊花怪大戰xcq') print(book_obj.pub) #老男孩出版社 #反向 pub_obj = models.Publisher.objects.get(pk=1) #print(pub_obj.book_set.all(),type(pub_obj.book_set)) #未指定related_name時,使用類名小寫_set set理解爲集合 #print(pub_obj.books.all(),type(pub_obj.book_set)) #指定related_name='books'時 #基於字段的查詢 ret = models.Book.objects.filter(title='菊花怪大戰xcq') print(ret) #查詢老男孩出版社的書 ret = models.Book.objects.filter(pub__name='老男孩出版社') print(ret) #查詢出版'菊花怪大戰xcq'的出版社 #有related_name='books' ret = models.Publisher.objects.filter(books__title='菊花怪大戰xcq') print(ret) #無related_name='books' 類名小寫 ret = models.Publisher.objects.filter(book__title='菊花怪大戰xcq') print(ret) #related_name='books',related_query_name='xxx' ret = models.Publisher.objects.filter(xxx__title='菊花怪大戰xcq') print(ret)
關係管理對象
import os os.environ.setdefault("DJANGO_SETTINGS_MODULE", "test61.settings") import django django.setup() from app01 import models #基於對象的查詢 mjj = models.Author.objects.get(pk=1) print(mjj.books) #關係管理對象 print(mjj.books.all()) book_obj = models.Book.objects.filter(title='桃花俠大戰菊花怪').first() #不指定related_name #print(book_obj.author_set) #print(book_obj.author_set.all()) #指定related_name print(book_obj.authors.all()) ret = models.Author.objects.filter(books__title='桃花俠大戰菊花怪') print(ret)
mjj = models.Author.objects.get(pk=1) #1 .all() 所關聯的全部對象 print(mjj.books.all()) #2 .set() 設置多對多關係 [id] [對象] #mjj.books.set([1,2,3]) mjj.books.set(models.Book.objects.filter(pk__in=[1,2,3])) #3 .add 添加多對對關係 [id] [對象] mjj.books.add(4,5) mjj.books.add(*models.Book.objects.filter(pk__in=[4,5])) #4 .remove 刪除多對多關係[id] [對象] mjj.books.remove(4,5) mjj.books.remove(*models.Book.objects.filter(pk__in=[4,5])) #5 .clear 清楚全部多對多關係 mjj.books.clear() #6 .create() obj = mjj.books.create(title='菊花怪大戰xcq',pub_id=1) print(obj)
1.在Python腳本中調用Django環境
import os if __name__ == '__main__': os.environ.setdefault("DJANGO_SETTINGS_MODULE", "BMS.settings") import django django.setup() from app01 import models books = models.Book.objects.all() print(books)
1.聚合查詢
aggregate()
是QuerySet
的一個終止子句,意思是說,它返回一個包含一些鍵值對的字典,鍵的名稱是聚合值的標識符,值是計算出來的聚合值。鍵的名稱是按照字段和聚合函數的名稱自動生成出來的 from django.db.models import Max,Min,Avg,Sum,Count
import os os.environ.setdefault("DJANGO_SETTINGS_MODULE", "test61.settings") import django django.setup() from app01 import models from django.db.models import Max,Min,Avg,Sum,Count ret = models.Book.objects.all().aggregate(Max('price')) print(ret) ret = models.Book.objects.all().aggregate(Avg('price')) print(ret) ret = models.Book.objects.all().aggregate(Avg('price'),max=Max('price')) print(ret) ret = models.Book.objects.filter(pk__gt=2).aggregate(Avg('price'),max=Max('price')) print(ret)
2.分組查詢
咱們在這裏先複習一下SQL語句的分組:
咱們使用原生SQL語句,按照部門分組求平均工資:
select dept,avg(salary) from employee group by dept;
ORM查詢:
from django.db.models import Avg Employee.objects.values("dept").annotate(avg=Avg("salary").values("dept", "avg")
SQL查詢:
select dept.name,AVG(salary) from employee inner join dept on (employee.dept_id=dept.id) group by dept_id;
ORM查詢:
from django.db.models import Avg models.Dept.objects.annotate(avg=Avg("employee__salary")).values("name", "avg")
import os os.environ.setdefault("DJANGO_SETTINGS_MODULE", "test61.settings") import django django.setup() from app01 import models from django.db.models import Max,Min,Avg,Sum,Count
#示例1:統計每一本書的做者個數 obj = models.Book.objects.annotate(Count('author')).values() #annotate註釋 for i in obj: print(i)
#示例2:統計出每一個出版社買的最便宜的書的價格 #方式一: obj = models.Publisher.objects.annotate(Min('book__price')).values() for i in obj: print(i) print("*"*30) #方式二: obj = models.Book.objects.values('pub__name').annotate(Min('price')) for i in obj: print(i)
#示例3:統計不止一個做者的圖書 obj = models.Book.objects.annotate(count=Count('author')).filter(count__gt=1) print(obj)
#示例4:根據一本圖書做者數量的多少對查詢集 QuerySet進行排序 obj = models.Book.objects.annotate(count=Count('author')).order_by('count') print(obj)
#示例5:查詢各個做者出的書的總價格 obj = models.Author.objects.annotate(Sum('books__price')).values() print(obj)
1.F查詢
F() 的實例能夠在查詢中引用字段,來比較同一個 model 實例中兩個不一樣字段的值。
book表字段信息:
#F查詢 from django.db.models import F #1.查詢售出大於庫存的(比較兩個字段的值) ret = models.Book.objects.filter(sale__gt=F('kucun')) print(ret)
#更新全部字段 obj = models.Book.objects.get(pk=1) obj.sale=100 obj.save() #只更新sale字段 models.Book.objects.filter(pk=1).update(sale=80) #取某字段的值作相應操做 models.Book.objects.all().update(sale=F('sale')*2+10)
2.Q查詢
| 或
& 與
~ 非
from django.db.models import Q ret = models.Book.objects.filter(Q(pk__gt=3)|Q(pk__lt=2)) print(ret) print('*'*30) ret = models.Book.objects.filter(Q(Q(pk__gt=3)|Q(pk__lt=2))&Q(pub__book__kucun__gt=50)) print(ret)
import os os.environ.setdefault("DJANGO_SETTINGS_MODULE", "test61.settings") import django django.setup() from app01 import models from django.db import transaction try: with transaction.atomic(): #開啓事務 #進行一系列ORM操做 models.Publisher.objects.create(name='xxx3') models.Publisher.objects.create(name='xxx4') except Exception as e: print(e)
https://www.cnblogs.com/maple-shaw/articles/9502602.html
1.Cookie的由來
你們都知道HTTP協議是無狀態的。無狀態的意思是每次請求都是獨立的,它的執行狀況和結果與前面的請求和以後的請求都無直接關係,它不會受前面的請求響應狀況直接影響,也不會直接影響後面的請求響應狀況。狀態能夠理解爲客戶端和服務器在某次會話中產生的數據,那無狀態的就覺得這些數據不會被保留。會話中產生的數據又是咱們須要保存的,也就是說要「保持狀態」。所以Cookie就是在這樣一個場景下誕生。
2.什麼叫Cookie
定義:保存在瀏覽器上的一組組鍵值對
特色 :
1.是服務器讓瀏覽器進行設置
2.瀏覽器保存在瀏覽器本地
3.下次訪問時會自動攜帶
能作什麼
1.登陸
2.保存瀏覽習慣
3..簡單投票
判斷是否登陸
from django.shortcuts import render,redirect,HttpResponse from django.views import View class Login(View): def get(self,request,*args,**kwargs): return render(request,'login.html') def post(self,request,*args,**kwargs): username = request.POST.get('username') pwd = request.POST.get('pwd') if username == 'alex' and pwd == '123': url = request.GET.get('return_url') if url: ret = redirect(url) else: ret = redirect('/index/') #ret.set_cookie('is_login','1') ret.set_signed_cookie('is_login','1','aaa') # key value sale加鹽 return ret return render(request,'login.html',{'error':'用戶名或密碼錯誤'}) def login_required(func): def inner(request,*args,**kwargs): #is_login = request.COOKIES.get('is_login') is_login = request.get_signed_cookie('is_login','aaa',default='') url = request.path_info if is_login != '1': return redirect('/login/?return_url={}'.format(url)) #已登陸 ret = func(request,*args,**kwargs) return ret return inner @login_required def index(request): #獲取到cookie is_login = request.COOKIES.get('is_login') if is_login != '1': return redirect('/login/') return HttpResponse('首頁') @login_required def home(request): return HttpResponse('home')
1.獲取Cookie
request.COOKIES['key'] request.get_signed_cookie('key', default=RAISE_ERROR, salt='', max_age=None)
get_signed_cookie方法的參數:
default: 默認值
salt: 加密鹽
max_age: 後臺控制過時時間
2.設置Cookie
rep = HttpResponse(...) rep = render(request, ...) rep.set_cookie(key,value,...) rep.set_signed_cookie(key,value,salt='加密鹽',...)
參數:
key, 鍵
value='', 值
max_age=None, 超時時間
expires=None, 超時時間(IE requires expires, so set it if hasn't been already.)
path='/', Cookie生效的路徑,/ 表示根路徑,特殊的:根路徑的cookie能夠被任何url的頁面訪問
domain=None, Cookie生效的域名
secure=False, https傳輸
httponly=False 只能http協議傳輸,沒法被JavaScript獲取(不是絕對,底層抓包能夠獲取到也能夠被覆蓋)
3.刪除Cookie
def logout(request): ret = redirect("/login/") ret.delete_cookie("is_login") # 刪除用戶瀏覽器上以前設置的user的cookie值 return ret
定義:保存在服務器上的一組組鍵值對,必須依賴與cookie使用
1.爲何要有Session
1.cookie保存在瀏覽器本地
2.大小個數受到限制(4096)
2.操做session
設置
request.session [key] = value
獲取
request.session [key]
request.session.get(key)
3.Session流程解析
4.Django中Session相關方法
# 獲取、設置、刪除Session中數據 request.session['k1'] request.session.get('k1',None) request.session['k1'] = 123 request.session.setdefault('k1',123) # 存在則不設置 del request.session['k1'] # 全部 鍵、值、鍵值對 request.session.keys() request.session.values() request.session.items() request.session.iterkeys() request.session.itervalues() request.session.iteritems() # 會話session的key request.session.session_key # 將全部Session失效日期小於當前日期的數據刪除(expired:過時) request.session.clear_expired() # 檢查會話session的key在數據庫中是否存在 request.session.exists("session_key") # 刪除當前會話的全部Session數據,不刪除會話的Cookie request.session.delete() # 刪除當前的會話數據,並刪除會話的Cookie。 request.session.flush() 這用於確保前面的會話數據不能夠再次被用戶的瀏覽器訪問 例如,django.contrib.auth.logout() 函數中就會調用它。 # 設置會話Session和Cookie的超時時間 request.session.set_expiry(value) * 若是value是個整數,session會在些秒數後失效。 * 若是value是個datatime或timedelta,session就會在這個時間後失效。 * 若是value是0,用戶關閉瀏覽器session就會失效。 * 若是value是None,session會依賴全局session失效策略。
5.Django中的Session配置
1. 數據庫Session SESSION_ENGINE = 'django.contrib.sessions.backends.db' # 引擎(默認) 2. 緩存Session SESSION_ENGINE = 'django.contrib.sessions.backends.cache' # 引擎 SESSION_CACHE_ALIAS = 'default' # 使用的緩存別名(默認內存緩存,也能夠是memcache),此處別名依賴緩存的設置 3. 文件Session SESSION_ENGINE = 'django.contrib.sessions.backends.file' # 引擎 SESSION_FILE_PATH = None # 緩存文件路徑,若是爲None,則使用tempfile模塊獲取一個臨時地址tempfile.gettempdir() 4. 緩存+數據庫 SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db' # 引擎 5. 加密Cookie Session SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies' # 引擎 其餘公用設置項: SESSION_COOKIE_NAME = "sessionid" # Session的cookie保存在瀏覽器上時的key,即:sessionid=隨機字符串(默認) SESSION_COOKIE_PATH = "/" # Session的cookie保存的路徑(默認) SESSION_COOKIE_DOMAIN = None # Session的cookie保存的域名(默認) SESSION_COOKIE_SECURE = False # 是否Https傳輸cookie(默認) SESSION_COOKIE_HTTPONLY = True # 是否Session的cookie只支持http傳輸(默認) SESSION_COOKIE_AGE = 1209600 # Session的cookie失效日期(2周)(默認) SESSION_EXPIRE_AT_BROWSER_CLOSE = False # 是否關閉瀏覽器使得Session過時(默認) SESSION_SAVE_EVERY_REQUEST = False # 是否每次請求都保存Session,默認修改以後才保存(默認)
from django.conf import global_settings
CSRF(Cross-site request forgery)跨站請求僞造,也被稱爲「One Click Attack」或者Session Riding,一般縮寫爲CSRF或者XSRF,是一種對網站的惡意利用
隱藏:
from django.views.decorators.csrf import csrf_exempt,csrf_protect,ensure_csrf_cookie from django.utils.decorators import method_decorator csrf_exempt #某個視圖不須要進行csrf校驗 csrf_protect #某個視圖須要進行csrf校驗 ensure_csrf_cookie #確保生成csrf的cookie
1.crsf中間件中執行process_request方法
1.從cookie中獲取到csrftoken
2.csrftoken中的值放到request.META中
2.執行process_view方法
1.查詢視圖函數是否使用csrf_exempt裝飾器,使用了就不進行csrf校驗
2.判斷請求方式
若是是 'GET', 'HEAD', 'OPTIONS', 'TRACE' ,不進行csrf校驗
其餘請求方式進行crsf校驗 :
獲取cookie中的csrftoken中的值
獲取csrfmiddlewaretoken的值
能獲取到----->>request_csrf_token
獲取不到----->>獲取請求頭中的 X-csrftoken的值----->>request_csrf_token
比較request_csrf_toke和cookief中的csrftoken,比較成功接受請求,比較不成功,拒絕請求
什麼是JSON
1. JSON 指的是 JavaScript 對象表示法(JavaScript Object Notation) 2. JSON 是輕量級的文本數據交換格式 3. JSON 獨立於語言 4. JSON 具備自我描述性,更易理解
不合格的json對象:
{ name: "張三", 'age': 32 } // 屬性名必須使用雙引號 [32, 64, 128, 0xFFF] // 不能使用十六進制值 { "name": "張三", "age": undefined } // 不能使用undefined { "name": "張三", "birthday": new Date('Fri, 26 Aug 2011 07:13:10 GMT'), "getName": function() {return this.name;} // 不能使用函數和日期對象 }
和XML的比較
JSON 格式有兩個顯著的優勢:書寫簡單,一目瞭然;符合 JavaScript 原生語法,能夠由解釋引擎直接處理,不用另外添加解析代碼。因此,JSON迅速被接受,已經成爲各大網站交換數據的標準格式,並被寫入ECMAScript 5,成爲標準的一部分。XML和JSON都使用結構化方法來標記數據
JSON 簡單的語法格式和清晰的層次結構明顯要比 XML 容易閱讀,而且在數據交換方面,因爲 JSON 所使用的字符要比 XML 少得多,能夠大大得節約傳輸數據所佔用得帶寬。
AJAX(Asynchronous Javascript And XML)翻譯成中文就是「異步的Javascript和XML」。即便用Javascript語言與服務器進行異步交互,傳輸的數據爲XML(固然,傳輸的數據不僅是XML)。
AJAX 不是新的編程語言,而是一種使用現有標準的新方法。
AJAX 最大的優勢是在不從新加載整個頁面的狀況下,能夠與服務器交換數據並更新部分網頁內容。(這一特色給用戶的感覺是在不知不覺中完成請求和響應過程)
AJAX 不須要任何瀏覽器插件,但須要用戶容許JavaScript在瀏覽器上執行。
同步交互:客戶端發出一個請求後,須要等待服務器響應結束後,才能發出第二個請求;
異步交互:客戶端發出一個請求後,無需等待服務器響應結束,就能夠發出第二個請求。
總結 : ajax就是使用js的技術發請求和接收響應的
特色:1.異步,2.局部刷新,3.傳輸數據量少
發請求的方式
地址欄輸入地址 GET
form請求 GET/POST
1.method 請求方式 action 地址
2.標籤要有name屬性,有的要有value
3.要有一個input type='submit' 或者button
a標籤 GET
ajax
使用 : jq發ajax
例一:頁面輸入兩個整數,經過AJAX傳輸到後端計算出結果並返回
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<input type="text" name="i1" >+
<input type="text" name="i2" >=
<input type="text" name="i3" >
<button id="b1" >計算</button>
<script src="/static/jquery.js"></script>>
<script>
$("#b1").click(function(){
//發ajax請求
$.ajax({
url:'/calc/',
type:'post',
data:{
a:$("[name='i1']").val(),
b:$("[name='i2']").val()
},
success:function(res){
$("[name='i3']").val(res)
},
error:function(error){
console.log(error)
}
})
})
</script>
</body>
</html>
from django.shortcuts import render,HttpResponse
def calc(request):
a = request.POST.get('a')
b = request.POST.get('b')
c = int(a) + int(b)
return HttpResponse(c)
例二:異步的實現
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<input type="text" name="i1" >+
<input type="text" name="i2" >=
<input type="text" name="i3" >
<button id="b1" >計算</button>
<br>
<input type="text" name="ii1" >+
<input type="text" name="ii2" >=
<input type="text" name="ii3" >
<button id="b2">計算</button>
<script src="/static/jquery.js"></script>>
<script>
$("#b1").click(function(){
//發ajax請求
$.ajax({
url:'/calc/',
type:'post',
data:{
a:$("[name='i1']").val(),
b:$("[name='i2']").val()
},
success:function(res){
$("[name='i3']").val(res)
},
error:function(error){
console.log(error)
}
})
});
$("#b2").click(function(){
//發ajax請求
$.ajax({
url:'/calc2/',
type:'post',
data:{
a:$("[name='ii1']").val(),
b:$("[name='ii2']").val()
},
success:function(res){
$("[name='ii3']").val(res)
},
error:function(error){
console.log(error)
}
})
})
</script>
</body>
</html>
from django.shortcuts import render,HttpResponse import time def calc(request): a = request.POST.get('a') b = request.POST.get('b') c = int(a) + int(b) time.sleep(2) return HttpResponse(c) def calc2(request): a = request.POST.get('a') b = request.POST.get('b') c = int(a) + int(b) return HttpResponse(c)
例三:列表元素的獲取(法一)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <button id="b3">參數</button> <script src="/static/jquery.js"></script>> <script> $("#b3").click(function(){ //發ajax請求 $.ajax({ url:'/test/', type:'post', data:{ name: 'alex', age:30, hobby:['唱','跳','rap'], }, success:function(res){ console.log(res) }, error:function(error){ console.log(error) } }) }) </script> </body> </html>
from django.shortcuts import render,HttpResponse def test(request): print(request.POST) ret = request.POST.get('hobby') print(ret) ret = request.POST.get('hobby[]') print(ret) ret = request.POST.getlist('hobby[]') print(ret) return HttpResponse('OK')
例四:列表元素的獲取(法二)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <button id="b3">參數</button> <script src="/static/jquery.js"></script>> <script> $("#b3").click(function(){ //發ajax請求 $.ajax({ url:'/test/', type:'post', data:{ name: 'alex', age:30, hobby:JSON.stringify(['唱','跳','rap']), }, success:function(res){ console.log(res) }, error:function(error){ console.log(error) } }) }) </script> </body> </html>
from django.shortcuts import render,HttpResponse import json def test(request): print(request.POST) ret = request.POST.get('hobby') print(ret) obj = json.loads(ret) print(obj,type(obj)) return HttpResponse('OK')
例五:上傳文件
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <input type="file" id="f1"> <button id="b1">上傳</button> <script src="/static/jquery.js"></script>> <script> $("#b1").click(function(){ var formobj = new FormData(); formobj.append('file',document.getElementById('f1').files[0]); formobj.append('name','alex'); //發ajax請求 $.ajax({ url:'/upload/', type:'post', data:formobj, processData:false, #不處理編碼方式 contentType:false, # success:function(res){ $("[name='i3']").val(res) }, error:function(error){ console.log(error) } }) }) </script> </body> </html>
from django.shortcuts import render,HttpResponse def upload(request): print(request.POST) print(request.FILES) return render(request,'upload.html')
例六:ajax經過csrf校驗
1.確保有csrftoken的cookie
在頁面中使用{% csrf_token%}
2.加裝飾器ensure_csrf_cookie
from django.views.decorators.csrf import csrf_exempt,csrf_protect,ensure_csrf_cookie
1.給data中添加crsfmiddlewaretoken鍵值對
data:{ 'csrfmiddlewaretoken':$('[name="csrfmiddlewaretoken"]').val(), a:$("[name='i1']").val(), b:$("[name='i2']").val() },
2.加請求頭
header:{ 'x-csrftoken':$('[name="csrfmiddlewaretoken"]').val(), },
3.使用文件(static/js)
function getCookie(name) { var cookieValue = null; if (document.cookie && document.cookie !== '') { var cookies = document.cookie.split(';'); for (var i = 0; i < cookies.length; i++) { var cookie = jQuery.trim(cookies[i]); // Does this cookie string begin with the name we want? if (cookie.substring(0, name.length + 1) === (name + '=')) { cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); break; } } } return cookieValue; } var csrftoken = getCookie('csrftoken'); function csrfSafeMethod(method) { // these HTTP methods do not require CSRF protection return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method)); } $.ajaxSetup({ beforeSend: function (xhr, settings) { if (!csrfSafeMethod(settings.type) && !this.crossDomain) { xhr.setRequestHeader("X-CSRFToken", csrftoken); } } });
<body> <div class="container"> <form class="form-signin" action="" method="post"> <h2 class="form-signin-heading">Please sign in</h2> <label for="inputEmail" class="sr-only">Email address</label> <input type="text" id="inputEmail" class="form-control" placeholder="Email address" required="" autofocus="" name="username"> <label for="inputPassword" class="sr-only">Password</label> <input type="password" id="inputPassword" class="form-control" placeholder="Password" name="passward"> <div class="checkbox"> <label> <input type="checkbox" value="remember-me"> Remember me </label> </div> <button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button> </form> </div> <!-- /container --> </body>
form表單提交數據注意的問題:
1.提交的地址action="",請求的方式 method="post"
2.全部input框都有name屬性
3.有一個input框的type="submit" 或者 有一個button
運行程序會出現如下狀況
提交POST請求,把settings中MIDDLEWARE的'django.middleware.csrf.CsrfViewMiddleware'註釋掉
from django.conf.urls import url from django.contrib import admin from django.shortcuts import render def index(request): return render(request,"index.html") def login(request): print(request.method,type(request.method)) return render(request,"login.html") urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^index/', index), url(r'^login/', login), ]
點擊路徑回車,會獲得
輸入帳號密碼提交,會獲得
from django.conf.urls import url from django.contrib import admin from django.shortcuts import render def index(request): return render(request,"index.html") def login(request): #print(request.method,type(request.method)) if request.method == 'GET': return render(request,"login.html") elif request.method == 'POST': #獲取form表單提交的數據 print(request.POST) #而後驗證用戶名和密碼 #驗證成功,跳轉到index頁面 #驗證不成功,從新登錄 urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^index/', index), url(r'^login/', login), ]
from django.conf.urls import url from django.contrib import admin from django.shortcuts import render def index(request): return render(request,"index.html") def login(request): #print(request.method,type(request.method)) if request.method == 'POST': #獲取form表單提交的數據 print(request.POST) username = request.POST['username'] print(username,type(username)) #而後驗證用戶名和密碼 #驗證成功,跳轉到index頁面 #驗證不成功,從新登錄 return render(request,"login.html") urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^index/', index), url(r'^login/', login), ]
from django.conf.urls import url from django.contrib import admin from django.shortcuts import render,redirect def index(request): return render(request,"index.html") def login(request): #print(request.method,type(request.method)) if request.method == 'POST': #獲取form表單提交的數據 print(request.POST) username = request.POST['username'] password = request.POST['password'] print(username,type(username)) #而後驗證用戶名和密碼 if username == 'alex' and password == 'sb': #驗證成功,跳轉到index頁面 return redirect('https://www.baidu.com/') #驗證不成功,從新登錄 return render(request,"login.html") urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^index/', index), url(r'^login/', login), ]
# request.method #請求方式 POST GET # request.POST #form表單提交的數據,去數據方式 [] 或者 .get .get好處,有默認值 from django.shortcuts import redirect return redirect('https://www.baidu.com/')
1.建立項目
2.建立mysql數據庫
3.更改配置
在init中添加代碼
4.建表
class publisher(models.Model): #默認生成id #設置主鍵 pid = models.AutoField(primary_key=True) name = models.CharField(max_length=32) addr = models.CharField(max_length=32)
在終端裏作數據庫遷移命令
1.展現
設計url
from app01 import views urlpatterns = [ url(r'^admin/', admin.site.urls), #添加出版社表信息路徑 url(r'^publisher_list/', views.publisher_list), ]
寫函數
from django.shortcuts import render from app01 import models #展現出版社 def publisher_list(request): #從數據庫中查詢出版社信息 all_publisher = models.publisher.objects.all() #返回一個包含出版社信息的頁面 return render(request,'publisher_list.html',{'all_publisher':all_publisher})
寫模板
<body> <h1>出版社列表</h1> {% comment %}{{all_publisher}}{% endcomment %} <table border="1"> <thead> <tr> <th>序號</th> <th>id</th> <th>名稱</th> </tr> </thead> <tbody> {% for publisher in all_publisher %} <tr> <td>{{forloop.counter}}</td> <td>{{publisher.pk}}</td> <td>{{publisher.name}}</td> </tr> {% endfor%} </tbody> </table> </body> </html>
2.新增
#基礎 from django.shortcuts import render,redirect from app01 import models #展現出版社 def publisher_list(request): #從數據庫中查詢出版社信息 all_publisher = models.publisher.objects.all() #返回一個包含出版社信息的頁面 return render(request,'publisher_list.html',{'all_publisher':all_publisher}) #新增出版社 def add_publisher(request): #對請求方式進行判斷 if request.method == 'POST': #處理POST請求 #獲取出版社名稱 publisher_name = request.POST.get('publisher_name') #判斷出版社名稱是否重複 if models.publisher.objects.filter(name=publisher_name): return render(request, 'add_publisher.html',{'error':"出版社名稱已存在"}) #判斷輸入值是否爲空 if not publisher_name: return render(request, 'add_publisher.html', {'error': "輸入不能爲空"}) #使用orm將數據插入到數據庫中 obj = models.publisher.objects.create(name=publisher_name) print(obj.pk,obj.name) #跳轉到展現出版社界面 return redirect('/publisher_list/') #返回一個包含form表單的頁面 return render(request,'add_publisher.html')
#優化版 from django.shortcuts import render,redirect from app01 import models #展現出版社 def publisher_list(request): #從數據庫中查詢出版社信息 all_publisher = models.publisher.objects.all().order_by("pk") #返回一個包含出版社信息的頁面 return render(request,'publisher_list.html',{'all_publisher':all_publisher}) #新增出版社 def add_publisher(request): #對請求方式進行判斷 error = '' if request.method == 'POST': #處理POST請求 #獲取出版社名稱 publisher_name = request.POST.get('publisher_name') #判斷出版社名稱是否重複 if models.publisher.objects.filter(name=publisher_name): error = "出版社名稱已存在" #判斷輸入值是否爲空 if not publisher_name: error = "輸入不能爲空" if not error: #使用orm將數據插入到數據庫中 obj = models.publisher.objects.create(name=publisher_name) #print(obj.pk,obj.name) #跳轉到展現出版社界面 return redirect('/publisher_list/') #返回一個包含form表單的頁面 return render(request,'add_publisher.html',{'error':error})
3.刪除
obj_list = models.Publisher.objects.filter(pk=pk) obj_list.delete() obj = models.Publisher.objects.get(pk=pk) obj.delete()
#刪除出版社 def del_publisher(request): #獲取要刪除的去數據 pk = request.GET.get('id') obj_list = models.publisher.objects.filter(pk=pk) if not obj_list: #沒有要刪除的數據(直接輸入) return HttpResponse('要刪除的數據不存在') #刪除該數據 #obj.delete() obj_list.delete() #跳轉到展現頁面 return redirect('/publisher_list/')
4.編輯
#編輯出版社 def edit_publisher(request): error = '' #查找要編輯的頁面 pk = request.GET.get('id') obj_list = models.publisher.objects.filter(pk=pk) if not obj_list: return HttpResponse('要編輯的數據不存在') obj = obj_list[0] if request.method == 'POST': #處理POST請求 #獲取新提交的出版社名稱 publisher_name = request.POST.get('publisher_name') if models.publisher.objects.filter(name=publisher_name): #新修改的名稱已存在 error = '新修改的名稱已存在' if obj.name == publisher_name: error = '名稱未修改' if not publisher_name: error = '提交名稱不能爲空' if not error: #修改數據 obj.name = publisher_name #保存數據到數據庫 obj.save() #跳轉到出版社展現頁面 return redirect('/publisher_list/') #返回一個包含原始數據的頁面 return render(request,'edit_publisher.html',{'obj':obj,'error':error})
1.結構
class Book(models.Model): name = models.CharField(max_length=32,unique=True) pub_id = models.ForeignKey('publishe',on_delete=models.CASCADE) #models.CASCADE 級聯刪除 #on_delete參數 #1.11版本以前不用填寫.默認是on_delete=models.CASCADE),但在2.0版本以後必填 #on_delete=models.SET(value)設置成某個值 SET_DEFAULT 設置成默認值 SET_NULL
執行數據庫遷移命令
#展現書籍 def book_list(request): #獲取全部書籍對象 books = models.Book.objects.all() for i in books: i,type(i) i.pk, type(i.pk) i.name, type(i.name) i.pub, type(i.pub) #所關聯對象 i.pub.pk #所關聯對象id i.pub_id #所關聯對象id(推薦使用)
#新增書籍
def add_book(request):
if request.method == 'POST':
#獲取提交數據
new_name = request.POST.get('new_name')
pub_id = request.POST.get('pub')
#插入到數據庫中
models.Book.objects.create(name=new_name,pub=models.publisher.objects.get(pk=pub_id))
#跳轉到展現頁面
return redirect('/book_list/')
#全部的出版社信息
publisher = models.publisher.objects.all()
return render(request,'add_book.html',{'publisher':publisher})
#編輯書籍
def edit_book(request):
#查詢要編輯書籍的對象
pk=request.GET.get('pk')
edit_obj=models.Book.objects.get(pk=pk)
if request.method == 'POST':
#獲取提交數據
new_name=request.POST.get('new_name')
pub_id = request.POST.get('pub')
#編輯數據
edit_obj.name=new_name
edit_obj.pub_id = pub_id #id
#edit_obj.pub= models.publisher.objects.get(pub=pub_id) 對象
#保存到數據庫
edit_obj.save()
#重定向到展現界面
return redirect('/book_list/')
#查詢全部出版社
publisher = models.publisher.objects.all()
return render(request,'edit_book.html',{'edit_obj':edit_obj,'publisher':publisher})
建表
class Author(models.Model): name = models.CharField(max_length=32) books = models.ManyToManyField('Book')
展現做者
設計url
url(r'^author_list/', views.author_list),
寫函數
#展現做者 def author_list(request): #查詢全部做者 all_author = models.Author.objects.all() for author in all_author: print(author) print(author.pk) print(author.name,type(author.name)) print(author.books,type(author.books)) #關係管理對象 print(author.books.all(), type(author.books.all())) print("*"*20) return render(request,'author_list.html',{'all_author':all_author})
寫模板
<body> <h1>做者列表</h1> <table border="1"> <thead> <tr> <th>序號</th> <th>做者id</th> <th>做者姓名</th> <th>表明做</th> </tr> </thead> <tbody> {% for author in all_author %} <tr> <td>{{ forloop.counter }}</td> <td>{{ author.pk }}</td> <td>{{ author.name }}</td> <td> {% for book in author.books.all %} {% if forloop.last %} <<{{ book.name }}>> {% else %} <<{{ book.name }}>>, {% endif %} {% endfor %} </td> </tr> {% endfor %} </tbody> </table> </body>
增長
class Author(models.Model): name = models.CharField(max_length=32) books = models.ManyToManyField('Book')
寫函數
#增長做者 def add_author(request): if request.method == 'POST': #獲取post請求提交數據 author_name = request.POST.get('author_name') books = request.POST.get('books') """ print(request.POST) print(author_name) print(books) """ #存到數據庫 author_obj = models.Author.objects.create(name=author_name ) #只插入book表中內容 author_obj.books.set(books) #設置做者和書籍多對對關係 #跳轉到展現界面 return redirect('/author_list/') #查詢全部書籍 all_books = models.Book.objects.all() return render(request,'add_author.html',{"all_books":all_books})
寫模板
<body> <form action="" method="POST"> <p>做者姓名:<input type="text" name="author_name"></p> <p>做品: <select name="books" id="" multiple> <option value=""></option> {% for book in all_books %} <option value="{{ book.pk }}">{{ book.name }}</option> {% endfor %} </select> </p> <button>提交</button> </form> </body>
編輯
class Author(models.Model): name = models.CharField(max_length=32) books = models.ManyToManyField('Book')
寫對象
#編輯做者 def edit_author(request): #查詢要編輯做者對象 pk = request.GET.get('pk') author_obj = models.Author.objects.get(pk=pk) if request.method == 'POST': #獲取提交的數據 name = request.POST.get('author_name') books = request.POST.getlist('books') #修改對象的數據 author_obj.name = name author_obj.save() #多對多的關係 author_obj.books.set(books) #每次從新設置 #重定向 return redirect('/author_list/') #查詢全部書籍 all_book = models.Book.objects.all() return render(request,'edit_author.html',{'author_obj':author_obj,'all_book':all_book})
<body> <form action="" method="post"> <p>做者姓名:<input type="text" name="author_name" value="{{ author_obj.name }}"></p> <p>做品: <select name="books" id="" multiple> {% for book in all_book %} {% if book in author_obj.books.all %} <option selected value="{{ book.pk }}">{{ book.name }}</option> {% else %} <option value="{{ book.pk }}">{{ book.name }}</option> {% endif %} {% endfor %} </select> </p> <button>提交</button> </form> </body>
1.django幫咱們生成第三張表
class Author(models.Model): name = models.CharField(max_length=32) books = models.ManyToManyField('Book') # 不在Author表中生產字段,生產第三張表
2.本身建立第三張表
class AuthorBook(models.Model): author = models.ForeignKey(Author, on_delete=models.CASCADE) book = models.ForeignKey(Book, on_delete=models.CASCADE) #可任意添加字段 date = models.DateField()
3.自建的表和 ManyToManyField 聯合使用
class Author(models.Model): name = models.CharField(max_length=32) books = models.ManyToManyField('Book',through='AuthorBook',through_fields=['author','book']) # 不在Author表中生產字段,生產第三張表 class AuthorBook(models.Model): author = models.ForeignKey(Author,related_name='a', on_delete=models.CASCADE) book = models.ForeignKey(Book,related_name='b', on_delete=models.CASCADE) tuijian = models.ForeignKey(Author, on_delete=models.CASCADE) date = models.DateField()
12.2.12.5
def delete(request,table,pk): print(table,pk) #查找對應對象 table_class = getattr(models,table.capitalize()) table_class.objects.filter(pk=pk).delete() #刪除 #重定向到對應展現界面 return redirect(reverse(table))
https://www.cnblogs.com/maple-shaw/articles/9537309.html
# 1.生成input標籤 #2.對提供的數據進行校驗 #3.提供錯誤提示
1.定義form組件
from django import forms class Regform(forms.Form): username = forms.CharField(label='用戶名') #label 改成中文 pwd = forms.CharField(label='密碼',widget=forms.PasswordInput) #widget 密文
2.使用
視圖裏
def reg2(request): form_obj = Regform() if request.method == 'POST': form_obj = Regform(data=request.POST) if form_obj.is_valid(): #對數據進行校驗 #插入數據 return HttpResponse('註冊成功') return render(request,'reg2.html',{'form_obj':form_obj})
模板裏
<form action="" method="post" novalidate> {# novalidate:不在前端進行校驗 #} {% csrf_token %} {{ form_obj.as_p }} # #生成一個個p標籤(包含input label) {{ form_obj.errors }} <button>註冊</button> </form>
{{ form_obj.as_p }} # 生成一個個p標籤(包含input label) {{ form_obj.errors }} #生成全部錯誤 {{ form_obj.username }} #一個字段所對應的input框 {{ form_obj.username.label }} #該字段的中文提示 {{ form_obj.username.id_for_label }} #該字段input的id {{ form_obj.username.errors }} #該字段的全部錯誤 {{ form_obj.username.errors.0 }} #該字段的第一個錯誤
1.initial
初始值,input框裏面的初始值
class LoginForm(forms.Form): username = forms.CharField( min_length=8, label="用戶名", initial="張三" # 設置默認值 ) pwd = forms.CharField(min_length=6, label="密碼")
2.error_messages
錯誤提示
class LoginForm(forms.Form): username = forms.CharField( min_length=8, label="用戶名", initial="張三", required=True, error_messages={ "required": "不能爲空", "invalid": "格式錯誤", "min_length": "用戶名最短8位" } ) pwd = forms.CharField(min_length=6, label="密碼")
3.password
密文顯示
class LoginForm(forms.Form): pwd = forms.CharField(label='密碼',widget=forms.PasswordInput) #widget 密文
4. radioSelect
class LoginForm(forms.Form): gender = forms.fields.ChoiceField( choices=((1, "男"), (2, "女"), (3, "保密")), label="性別", initial=3, widget=forms.RadioSelect )
5.單選Select
class LoginForm(forms.Form): ... hobby = forms.fields.ChoiceField( choices=((1, "籃球"), (2, "足球"), (3, "雙色球"), ), label="愛好", initial=3, widget=forms.widgets.Select() )
6.多選Select
lass LoginForm(forms.Form): ... hobby = forms.fields.MultipleChoiceField( choices=((1, "籃球"), (2, "足球"), (3, "雙色球"), ), label="愛好", initial=[1, 3], widget=forms.MultipleChoiceField( choices=((1, "籃球"), (2, "足球"), (3, "雙色球"), ),) )
7.單選checkbox
class LoginForm(forms.Form): ... keep = forms.fields.ChoiceField( label="是否記住密碼", initial="checked", widget=forms.widgets.CheckboxInput() )
8.多選checkbox
class LoginForm(forms.Form): ... hobby = forms.fields.MultipleChoiceField( choices=((1, "籃球"), (2, "足球"), (3, "雙色球"),), label="愛好", initial=[1, 3], widget=forms.widgets.CheckboxSelectMultiple() )
Field
required=True, 是否容許爲空
widget=None, HTML插件
label=None, 用於生成Label標籤或顯示內容
initial=None, 初始值
help_text='', 幫助信息(在標籤旁邊顯示)
error_messages=None, 錯誤信息 {'required': '不能爲空', 'invalid': '格式錯誤'}
validators=[], 自定義驗證規則
localize=False, 是否支持本地化
disabled=False, 是否能夠編輯
label_suffix=None Label內容後綴
CharField(Field)
max_length=None, 最大長度
min_length=None, 最小長度
strip=True 是否移除用戶輸入空白
IntegerField(Field)
max_value=None, 最大值
min_value=None, 最小值
FloatField(IntegerField)
...
DecimalField(IntegerField)
max_value=None, 最大值
min_value=None, 最小值
max_digits=None, 總長度
decimal_places=None, 小數位長度
BaseTemporalField(Field)
input_formats=None 時間格式化
DateField(BaseTemporalField) 格式:2015-09-01
TimeField(BaseTemporalField) 格式:11:12
DateTimeField(BaseTemporalField)格式:2015-09-01 11:12
DurationField(Field) 時間間隔:%d %H:%M:%S.%f
...
RegexField(CharField)
regex, 自定製正則表達式
max_length=None, 最大長度
min_length=None, 最小長度
error_message=None, 忽略,錯誤信息使用 error_messages={'invalid': '...'}
EmailField(CharField)
...
FileField(Field)
allow_empty_file=False 是否容許空文件
ImageField(FileField)
...
注:須要PIL模塊,pip3 install Pillow
以上兩個字典使用時,須要注意兩點:
- form表單中 enctype="multipart/form-data"
- view函數中 obj = MyForm(request.POST, request.FILES)
URLField(Field)
...
BooleanField(Field)
...
NullBooleanField(BooleanField)
...
ChoiceField(Field)
...
choices=(), 選項,如:choices = ((0,'上海'),(1,'北京'),)
required=True, 是否必填
widget=None,