HTTP 請求/響應的步驟:php
客戶端鏈接到Web服務器css
一個HTTP客戶端,一般是瀏覽器,與Web服務器的HTTP端口(默認爲80)創建一個TCP套接字鏈接。例如,http://www.luffycity.com。html
發送HTTP請求前端
經過TCP套接字,客戶端向Web服務器發送一個文本的請求報文,一個請求報文由請求行、請求頭部、空行和請求數據4部分組成。python
服務器接受請求並返回HTTP響應mysql
Web服務器解析請求,定位請求資源。服務器將資源複本寫到TCP套接字,由客戶端讀取。一個響應由狀態行、響應頭部、空行和響應數據4部分組成。web
釋放鏈接TCP鏈接正則表達式
若connection 模式爲close,則服務器主動關閉TCP鏈接,客戶端被動關閉鏈接,釋放TCP鏈接;若connection 模式爲keepalive,則該鏈接會保持一段時間,在該時間內能夠繼續接收請求;sql
客戶端瀏覽器解析HTML內容shell
客戶端瀏覽器首先解析狀態行,查看代表請求是否成功的狀態代碼。而後解析每個響應頭,響應頭告知如下爲若干字節的HTML文檔和文檔的字符集。客戶端瀏覽器讀取響應數據HTML,根據HTML的語法對其進行格式化,並在瀏覽器窗口中顯示。
HTTP/1.1協議中共定義了八種方法(也叫「動做」)來以不一樣方式操做指定的資源:
get:
head:
post:
向指定資源提交數據,請求服務器進行處理(例如提交表單或者上傳文件)。數據被包含在請求本文中。這個請求可能會建立新的資源或修改現有資源,或兩者皆有。
<form action="http://127.0.0.1:8001" method="post"> 默認是get請求 <input type="text" name="user"> <input type="password" name="pwd"> <input type="submit"> </form>
put:
delete:
trace:
options:
connect:
全部HTTP響應的第一行都是狀態行,依次是當前HTTP版本號,3位數字組成的狀態代碼,以及描述狀態的短語,彼此由空格分隔
狀態代碼的第一個數字表明當前響應的類型:
超文本傳輸協議(HTTP)的統一資源定位符將從因特網獲取信息的五個基本元素包括在一個簡單的地址中:
傳送協議。
層級URL標記符號(爲[//],固定不變)
訪問資源須要的憑證信息(可省略)
服務器。(一般爲域名,有時爲IP地址)
端口號。(以數字方式表示,若爲HTTP的默認值「:80」可省略)
路徑。(以「/」字符區別路徑中的每個目錄名稱)
查詢。(GET模式的窗體參數,以「?」字符爲起點,每一個參數以「&」隔開,再以「=」分開參數名稱與數據,一般以UTF8的URL編碼,避開字符衝突的問題)
片斷。以「#」字符爲起點
以http://www.luffycity.com:80/news/index.html?id=250&page=1 爲例, 其中: http,是協議; www.luffycity.com,是服務器; 80,是服務器上的默認網絡端口號,默認不顯示; /news/index.html,是路徑(URI:直接定位到對應的資源); ?id=250&page=1,是查詢
import socket from threading import Thread sk = socket.socket() sk.bind(('127.0.0.1',8008)) sk.listen() def html(conn): with open('demo2.html', 'rb') as f: data = f.read() conn.send(data) conn.close() def css(conn): with open('test.css', 'rb') as f: data = f.read() conn.send(data) conn.close() def js(conn): with open('test.js', 'rb') as f: data = f.read() conn.send(data) conn.close() def jpg(conn): with open('1.png', 'rb') as f: data = f.read() conn.send(data) conn.close() def ico(conn): with open('jd.ico', 'rb') as f: data = f.read() conn.send(data) conn.close() urlpatterns = [ ('/',html),('/test.css',css), ('/1.png',jpg),('/test.js',js),('/jd.ico',ico),] while True: conn,addr = sk.accept() mes = conn.recv(1024).decode('utf-8') path = mes.split('\r\n')[0].split(' ')[1] print(path) conn.send(b'http/1.1 200 ok \r\n\r\n') for i in urlpatterns: if path == i[0]: t = Thread(target=i[1],args=(conn,)) t.start() # <link rel="icon" href="jd.ico"> 在head標籤中設置ico,(小圖標)
# 在上面的基礎上修改 def html(conn): time_tag = str(time.time()) with open('demo2.html', 'r',encoding='utf-8') as f: data = f.read() # html中隨便添加一個內容,而後將其替換 data = data.replace('xxoo',time_tag).encode('utf-8') conn.send(data) conn.close()
wsgiref自己就是個web框架,提供了一些固定的功能(請求和響應信息的封裝,不須要咱們本身寫原生的socket了也不須要我們本身來完成請求信息的提取了,提取起來很方便
environ : 是所有加工好的請求信息,加工成了一個字典,經過字典取值的方式就能拿到不少你想要拿到的信息
start_response: 幫你封裝響應信息的(響應行和響應頭),注意下面的參數
import time from wsgiref.simple_server import make_server def html(): time_tag = str(time.time()) with open('demo2.html', 'r',encoding='utf-8') as f: data = f.read() data = data.replace('xxoo',time_tag).encode('utf-8') return data def css(): with open('rr.css', 'rb') as f: data = f.read() return data def js(): with open('test.js', 'rb') as f: data = f.read() return data def jpg(): with open('1.jpg', 'rb') as f: data = f.read() return data def ico(): with open('jd.ico', 'rb') as f: data = f.read() return data urlpatterns = [ ('/',html),('/rr.css',css), ('/1.jpg',jpg),('/test.js',js),('/jd.ico',ico),] def application(environ, start_response): start_response('200 OK', [('Content-Type', 'text/html'),('k1','v1')]) path = environ['PATH_INFO'] # 拿到每一個請求 print(path) for i in urlpatterns: if path == i[0]: ret = i[1]() break else: ret = b'404 not found!!!!' return [ret] httpd = make_server('127.0.0.1', 8080, application) print('Serving HTTP on port 8080...') httpd.serve_forever()
# HTML文件 <h1>{{userinfo}}</h1> <ul> {% for k,v in userinfo.items()%} <li>{{k}}--{{v}}</li> {% endfor %} </ul> # py文件 在上面基礎上修改 from jinja2 import Template def html(): user = showdata() with open('demo2.html', 'r',encoding='utf-8') as f: data = f.read() tem = Template(data) data = tem.render({'userinfo':user}) data = data.encode('utf-8') return data
所謂的mvc就是把web應用分爲模型(M),控制器(C),和視圖(V),他們之間以一種插件式的,鬆耦合的方式鏈接在一塊兒的,模型負責業務對象與數據庫的映射(ORM),視圖負責與用戶的交互,控制器接收用戶的輸入調用模型和視圖完成用戶的請求
Django的MTV模式本質上和mvc是同樣的,也是爲了各組件保持鬆耦合的關係,只是定義上有些不一樣,Django的MTV分別是值
除了以上三層外,還須要一個URL分發器,它的做用是將一個URL的頁面請求分發給不一樣的View處理,View在調用相應的Model和Template,響應模式以下
https://www.djangoproject.com/download/
1 建立項目 first_pro 2 建立app app01 作一個登陸頁面的web項目,瀏覽器輸入一個網址獲得一個web頁面 用戶: http:127.0.0.1:8001/login/ 1 urls.py from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ # url(r'^admin/', admin.site.urls), url(r'^index/', views.index), #配置路徑,r'^/index/',這個前置導航斜槓不須要添加. ] # urls.py裏面須要注意的問題 url(r'^index/', views.index), 第一個參數:路徑正則字符串 第二個參數:對應的視圖函數 2 寫邏輯視圖(Views) from django.shortcuts import render,HttpResponse # Create your views here. def index(request): print(request.method) # 'POST' 'GET' if request.method == 'GET': return render(request,'login.html') else: username = request.POST.get('username') password = request.POST.get('password') if username == 'xin' and password == '123': return HttpResponse('登陸成功!') else: return HttpResponse('登陸失敗!') 3 建立html文件(Template文件下) 在templates文件夾中建立一個login.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>Bootstrap 101 Template</title> </head> <body> <form action="/login/" method="post"> 姓名:<input type="text" name="username"> 密碼:<input type="password" name="password"> <input type="submit"> </form> </body> </html> 4. views.py from django.shortcuts import render,HttpResponse # Create your views here. def login(request): if request.method == 'GET': return render(request,'login.html') else: name = request.POST.get('username') ped = request.POST.get('password') if name== 'xin' and ped == '666': return HttpResponse('成功') else: return HttpResponse('失敗')
基本格式
from django.conf.urls import url #循環urlpatterns,找到對應的函數執行,匹配上一個路徑就找到對應的函數執行,就再也不往下循環了,並給函數傳一個參數request,和wsgiref的environ相似,就是請求信息的全部內容 urlpatterns = [ url(正則表達式, views視圖函數,參數,別名), ]
參數說明
基本配置
urls.py: from django.conf.urls import url from django.contrib import admin from app02 import views urlpatterns = [ url(r'^books/(\d{4})/$', views.books), # 匹配年 url(r'^books/(\d{4})/(\d{1,2})/', views.books), # 匹配年月 ] views.py: # 第一個參數必須是request,後面跟的三個參數是對應着上面分組正則匹配的每一個參數的 def books(request,year,month): return HttpResponse(year+month)
補充說明:
# 是否開啓URL訪問地址後面不爲/跳轉至帶有/的路徑的配置項 APPEND_SLASH=True
from django.conf.urls import url from app01 import views urlpatterns = [ url(r'^articles/(\d{4})/$', views.year_archive), # year_archive(request,n),小括號爲分組,有分組,那麼這個分組獲得的用戶輸入的內容,就會做爲對應函數的位置參數傳進去,別忘了形參要寫兩個了 url(r'^articles/(?P<year>\d{4})/$', views.year_archive),#某年的,(?P<year>[0-9]{4})這是命名參數,那麼函數year_archive(request,year),形參名稱必須是year這個名字。並且注意若是你這個正則後面沒有寫$符號,即使是輸入了月份路徑,也會被它攔截下拉,由於它的正則也能匹配上 url(r'^articles/(?P<year>\d{4})/(?P<month>\d{2})/$', views.month_archive),#某年某月的 url(r'^articles/(?P<year>\d{4})/(?P<month>\d{2})/(?P<day>\d{2})/$', views.article_detail), #某年某月某日的 ]
視圖函數中指定默認值
# urls.py中 from django.conf.urls import url from app01 import views urlpatterns = [ url(r'^blog/$', views.page), url(r'^blog/page(?P<num>\d+)/$', views.page), ] # views.py中,能夠爲num指定默認值 def page(request, num="1"): pass
# 項目文件夾下的urls.py文件中的url寫法: from django.conf.urls import url,include from django.contrib import admin from app01 import views urlpatterns = [ #首頁 url(r'^$', views.base), url(r'^app01/', include('app01.urls')), url(r'^app02/', include('app02.urls')), ] # app01下urls.py內容寫法 from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(r'^$', views.app01base), ] # app02下urls.py內容寫法 from django.conf.urls import url from django.contrib import admin from app02 import views urlpatterns = [ url(r'^$', views.app02base), ]
def index(request): # http相關請求信息---封裝--HttpRequest對象 if request.method == 'GET': print(request.body) # 獲取post請求提交過來的原始數據 print(request.GET) # 獲取GET請求提交的數據 # print(request.META) # 請求頭相關信息,就是一個大字典 print(request.path) # /index/ 路徑 print(request.path_info) # /index/ 路徑 print(request.get_full_path()) # /index/?username=dazhuang&password=123 return render(request,'index.html') else: print(request.body) # b'username=dazhuang' print(request.POST) # 獲取POST請求提交的數據 return HttpResponse('男賓三位,拿好手牌!')
HttpResponse --- 回覆字符串的時候來使用 render --- 回覆一個html頁面的時候使用 redirect -- 重定向 示例: # views.py from django.shortcuts import render,HttpResponse,redirect def login(request): if request.method == 'GET': return render(request,'login.html') else: username = request.POST.get('username') password = request.POST.get('password') if username == 'taibai' and password == 'dsb': return redirect('/home/') # 重定向 else: return HttpResponse('滾犢子,趕忙去充錢!!!') def home(request): return render(request,'home.html') # urls.py urlpatterns = [ url(r'^test/', views.test), url(r'^home/', views.home), ]
1)301和302的區別。 301和302狀態碼都表示重定向,就是說瀏覽器在拿到服務器返回的這個狀態碼後會自動跳轉到一個新的URL地址,這個地址能夠從響應的Location首部中獲取 (用戶看到的效果就是他輸入的地址A瞬間變成了另外一個地址B)——這是它們的共同點。 他們的不一樣在於。301表示舊地址A的資源已經被永久地移除了(這個資源不可訪問了),搜索引擎在抓取新內容的同時也將舊的網址交換爲重定向以後的網址; 302表示舊地址A的資源還在(仍然能夠訪問),這個重定向只是臨時地從舊地址A跳轉到地址B,搜索引擎會抓取新的內容而保存舊的網址。 SEO302好於301 2)重定向緣由: (1)網站調整(如改變網頁目錄結構); (2)網頁被移到一個新地址; (3)網頁擴展名改變(如應用須要把.php改爲.Html或.shtml)。 這種狀況下,若是不作重定向,則用戶收藏夾或搜索引擎數據庫中舊地址只能讓訪問客戶獲得一個404頁面錯誤信息,訪問流量白白喪失;再者某些註冊了多個域名的 網站,也須要經過重定向讓訪問這些域名的用戶自動跳轉到主站點等。
臨時重定向(響應狀態碼:302)和永久重定向(響應狀態碼:301)對普通用戶來講是沒什麼區別的,它主要面向的是搜索引擎的機器人。
FBV(function based views) : 就是在視圖裏使用函數處理
def home(request): print('home!!!') return render(request,'home.html')
CBV(class based views) : 在視圖裏使用類處理請求
views.py from django.views import View class LoginView(View): # 經過請求方法找到本身寫的視圖類裏面對應的方法 def get(self,request): return render(request,'login2.html') def post(self,request): username = request.POST.get('uname') password = request.POST.get('pwd') print(username,password) return HttpResponse('登陸成功!') urls.py url(r'^login2/', views.LoginView.as_view()),
FBV加裝飾器
def wrapper(f): def inner(*args,**kwargs): print('請求以前') ret = f(*args,**kwargs) print('請求以後') return ret return inner @wrapper def home(request): print('home!!!') return render(request,'home.html')
CBV加裝飾器
from django.views import View from django.utils.decorators import method_decorator def wrapper(f): def inner(*args,**kwargs): print('請求以前') ret = f(*args,**kwargs) print('請求以後') return ret return inner @method_decorator(n1,name='get') # 方式三 class LoginView(View): @method_decorator(n1) # 方式2 給全部方法加裝飾器 def dispatch(self, request, *args, **kwargs): # print('請求來啦') ret = super().dispatch(request, *args, **kwargs) # print('到點了,走人了') return ret @method_decorator(n1) # 方式1 def get(self,request): print('get方法執行了') return render(request,'login2.html') def post(self,request): username = request.POST.get('uname') password = request.POST.get('pwd') return HttpResponse('登陸成功!')
CBV的dispatch方法
from django.views import View class LoginView(View): # GET def dispatch(self, request, *args, **kwargs): print('請求來啦') ret = super().dispatch(request, *args, **kwargs) print('到點了,走人了') return ret def get(self,request): print('get方法執行了') return render(request,'login2.html') def post(self,request): username = request.POST.get('uname') password = request.POST.get('pwd') print(username,password) return HttpResponse('登陸成功!')
# 示例 html代碼: <p>{{ num }}</p> <p>{{ name }}</p> <p>{{ name_list.2 }}</p> # 經過 .索引 來取值 <p>{{ d1.age }}</p> # 經過 .鍵 取值 <p>{{ a.kind }}</p> <p>{{ a.eat }}</p> # 調用類中方法 views.py代碼 def index(request): num = 100 name = 'shige' name_list = ['大壯','小壯','壯壯'] d1 = {'name':'大壯','age':73,'hobby':'xuefei+xiangxi'} class Animal: def __init__(self): self.kind = 'dog' def eat(self): return 'shi' a = Animal() return render(request,'index.html',{'num':num,'name':name,'namelist':name_list,'d1':d1,'a':a}) # return render(request,'index.html',locals()) locals() 獲取函數內部全部變量的值,並加工成{'變量名':'變量值'....}這樣一個字典
default : 若是一個變量是false或者爲空,使用給定的默認值.不然使用變量的值
{{ value|default:"nothing"}}
length : 返回值的長度,做用於字符串和列表。
mes = 'I love you three thousand times' {{ mes|length }} # 31
filesizeformat : 將值格式化爲一個 「人類可讀的」 文件尺寸 (例如 '13 KB'
, '4.1 MB'
, '102 bytes'
, 等等)
filesize = 234352452 {{ filesize|filesizeformat }} # 223.5 MB
slice : 切片,若是 value="hello world",還有其餘可切片的數據類型
{{value|slice:"2:-1"}}
date : 格式化,若是 value=datetime.now()
{{ value|date:"Y-m-d H:i:s"}}
safe : 將字符串識別成標籤
val = '<a href="http://www.baidu.com">百度</a>' ret = "<script>alert('123')</script>" {{ val|safe }} # 生成a標籤的樣式 {{ ret|safe }} # 有js的樣式
truncatechars : 若是字符串字符多於指定的字符數量,那麼會被截斷。截斷的字符串將以可翻譯的省略號序列(「...」)結尾。
mes = 'I love you three thousand times' {{ value|truncatechars:10}} #注意:最後那三個省略號也是9個字符裏面的,也就是這個9截斷出來的是6個字符+3個省略號,獲得結果 : I love ... (空格一算一個字符)
truncatewords : 在必定數量的字後截斷字符串,是截多少個單詞。
mes = 'I love you three thousand times' {{ value|truncatewords:3}} # I love you ...
cut : 移除全部的與給出變量相同的字符串
mes = 'I love you three thousand times' {{ value|cut:' ' }} # Iloveyouthreethousandtimes
join : 使用字符串鏈接列表,相似於python中str.join(list)
lis = [11,22,33] {{ lis|join:'-' }} # 11-22-33
for標籤
遍歷每個元素: 寫個for,而後 tab鍵自動生成for循環的結構
dic = {'name':'alex','age':77} {% for k,v in dic.items %} # 循環字典 <li>{{ k }} - {{ v }}</li> {% endfor %} # name - alex # age - 77
for循環的其餘方法
forloop.counter 當前循環的索引值(從1開始),forloop是循環器,經過點來使用功能 forloop.counter0 當前循環的索引值(從0開始) forloop.revcounter 當前循環的倒序索引值(從1開始) forloop.revcounter0 當前循環的倒序索引值(從0開始) forloop.first 當前循環是否是第一次循環(布爾值) forloop.last 當前循環是否是最後一次循環(布爾值) forloop.parentloop 本層循環的外層循環的對象,再經過上面的幾個屬性來顯示外層循環的計數等 forloop.parentloop.counter
{# {% for key,value in d1.items %}#} {# {{ forloop.counter }}#} {# <li>{{ key }} -- {{ value }}</li>#} {# {% endfor %}#} {# {% for key,value in d1.items %}#} {# {{ forloop.counter0 }}#} {# <li>{{ key }} -- {{ value }}</li>#} {# {% endfor %}#} {# {% for key,value in d1.items %}#} {# {{ forloop.revcounter }}#} {# <li>{{ key }} -- {{ value }}</li>#} {# {% endfor %}#} {# {% for key,value in d1.items %}#} {# {{ forloop.revcounter0 }}#} {# <li>{{ key }} -- {{ value }}</li>#} {# {% endfor %}#} {# {% for key,value in d1.items %}#} {# {{ forloop.first }}#} {# <li>{{ key }} -- {{ value }}</li>#} {# {% endfor %}#} <!-- forloop.parentloop示例 --> {#<ul>#} {# {% for dd2 in d2 %}#} {# <li>#} {# {% for ddd2 in dd2 %}#} {# {{ forloop.parentloop.counter }}#} {# {{ forloop.counter }}#} {# <a href="">{{ ddd2 }}</a>#} {# {% endfor %}#} {##} {# </li>#} {# {% endfor %}#} {#</ul>#} <!-- empty示例 --> {#<ul>#} {# {% for foo in d3 %}#} {# <li>{{ foo }}</li>#} {# {% empty %}#} {# <li>查詢的內容啥也沒有</li>#} {# {% endfor %}#} {##} {#</ul>#}
if 標籤
{% if num > 100 %} <p>excellent</p> {% elif num == 100 %} <p>beautiful</p> {% else %} <p>nice</p> {% endif %} 1. Django的模板語言不支持連續判斷,即不支持如下寫法: {% if a > b > c %} ... {% endif %} 2. Django的模板語言中屬性的優先級大於方法(瞭解) def xx(request): d = {"a": 1, "b": 2, "c": 3, "items": "100"} return render(request, "xx.html", {"data": d})
with標籤
使用一個簡單地名字緩存一個複雜的變量,多用於給一個複雜的變量起別名,當你須要使用一個「昂貴的」方法(好比訪問數據庫)不少次的時候是很是有用的,注意等號不要加空格
# 兩種方式 {% with total=business.employees.count %} {{ total }} <!--只能在with語句體內用--> {% endwith %} {% with business.employees.count as total %} {{ total }} {% endwith %}
csrf_token
安全認證機制 咱們以post方式提交表單的時候,會報錯,還記得咱們在settings裏面的中間件配置裏面把一個csrf的防護機制給註銷了啊,自己不該該註銷的,而是應該學會怎麼使用它,而且不讓本身的操做被forbiden,經過這個東西就能搞定。 這個標籤用於跨站請求僞造保護, 在頁面的form表單裏面(注意是在form表單裏面)任何位置寫上{% csrf_token %},這個東西模板渲染的時候替換成了<input type="hidden" name="csrfmiddlewaretoken" value="8J4z1wiUEXt0gJSN59dLMnktrXFW0hv7m4d40Mtl37D7vJZfrxLir9L3jSTDjtG8">,隱藏的,這個標籤的值是個隨機字符串,提交的時候,這個東西也被提交了,首先這個東西是咱們後端渲染的時候給頁面加上的,那麼當你經過我給你的form表單提交數據的時候,你帶着這個內容我就認識你,不帶着,我就禁止你,由於後臺咱們django也存着這個東西,和你這個值相同的一個值,能夠作對應驗證是否是我給你的token,存儲這個值的東西咱們後面再學,你先知道一下就好了,就像一個咱們後臺給這個用戶的一個通行證,若是你用戶沒有按照我給你的這個正常的頁面來post提交表單數據,或者說你沒有先去請求我這個登錄頁面,而是直接模擬請求來提交數據,那麼我就能知道,你這個請求是非法的,反爬蟲或者惡意攻擊個人網站。
模板繼承
{% extends "base.html" %} # 寫在開始 鉤子:{% block title %} xxx {% endblock %} 鉤子:{% block title %} xxx {% endblock title %} 鉤子:{% block title %} {{ block.super }} # 顯示繼承模板的內容 xxx
組件
{% include 'navbar.html' %} # 引用組件的html文件 組件是提供某一完整功能的模塊,如:編輯器組件,QQ空間提供的關注組件 等。 而插件更傾向封閉某一功能方法的函數。 這二者的區別在 Javascript 裏區別很小,組件這個名詞用得很少,通常統稱插件。
自定義過濾器
在settings中的 INSTALL_APPS 配置當前的app,否則Django沒法找到自定義的過濾器
app應用文件夾中建立一個templatetags文件件,必須是這個名字
templatetags文件夾中建立一個 xx.py 文件,文件名字隨便起
在新建的 xx.py 文件中建立自定義過濾器
from Django import template register = template.Library() # register固定名字,註冊器 @register.filter def oo(v1): # 不帶參數的過濾器,第一個參數v1是views視圖函數中傳過來的 s = v1 + 'xxoo' return s @register.filter def oo(v1,v2): # 帶參數的過濾器 s = v1 + v2 return s
使用html文件中的數據
{% load xx %} {{ values|oo }} -- 無參數 {{ values|oo:'asdf' }} -- 有參數
參數最多兩個
自定義標籤
在settings中的 INSTALL_APPS 配置當前的app,否則Django沒法找到自定義的過濾器
app應用文件夾中建立一個templatetags文件件,必須是這個名字
templatetags文件夾中建立一個 xx.py 文件,文件名字隨便起
在新建的 xx.py 文件中建立自定義過濾器
from Django import template register = template.Library() # register固定名字,註冊器 @register.simple_tag def mytag(v1,v2,v3): # 第一個參數v1是views視圖函數中傳過來的 s = v1 + v2 + v3 return s
使用
{% load xx %} {% mytag s1 '啦啦' '呵呵' %}
inclusion_tag : 多用於返回html代碼片斷
# views.py def index(request): lis = [11,22,33,44,55,66] return render(request,'index.html',{'lis':lis}) # index.html {% load one %} {% func lis %} # one.py from django import template register = template.Library() @register.inclusion_tag('test.html') # 將test.html裏面的內容用下面函數的返回值渲染,而後做爲一個組件同樣,加載到使用這個函數的HTML裏面 def func(v1): return {'data':v1} # v1 是傳過來的lis列表 # test.html <ul> {% for d in data %} <li>{{ d }}</li> {% endfor %} </ul> 流程: 先執行index函數,將lis傳給index.html,index.html中將lis做爲func的參數傳進去,v1=lis,在one.py中,將v1傳給test.html進行渲染,最後將渲染的結果返回給index.html,在頁面顯示出來
js,css,img 等都叫作靜態文件,那麼在關於jango中靜態文件的配置,咱們就須要在settings配置文件中寫上下面內容
# 在項目目錄下建立一個文件用來存放靜態文件,一般名稱爲 : static STATIC_URL = '/static/' # 別名 STATICFILES_DIRS = [ os.path.join(BASE_DIR,'static'), # 注意別忘了寫逗號,第二個參數就是項目中你存放靜態文件的文件夾名稱 ]
目錄 : 別名也是一種安全機制,瀏覽器上經過調試臺你能看到的是別名的名字,這樣別人就不知道你靜態文件的名字了,否則別人就能經過這個文件夾路徑進行攻擊
前端頁面引入靜態文件的寫法,由於別名也可能會修改,因此使用路徑的時候經過load static來找別名,經過別名映射路徑的方式來獲取靜態文件
{% static %}
{% load static %} <img src="{% static "images/hi.jpg" %}" alt="Hi!" />
引用JS文件時使用
{% load static %} <script src="{% static "mytest.js" %}"></script>
某個文件多處被用到的能夠存爲一個變量
{% load static %} {% static "/images/hi.jpg" as myphoto %} <img src="{{ myphoto }}"></img>
注意:
一個html文件中寫相對路徑是須要注意一個問題
<form action="/login/"></form> <img src="/static/1.jpg" alt=""> 等標籤須要寫路徑的地方,若是寫的是相對路徑,那麼前置的/這個斜槓必須寫上,否則這個請求會拼接當前網頁的路徑來發送請求,就不能匹配咱們的後端路徑了
ORM是 對象--關係--映射 的簡稱.實現了數據模型與數據庫的解耦,即數據庫的設計不須要依賴特定的數據庫,經過簡單的配置就能夠輕鬆更換數據庫
類對象 --> sql --> pymysql --> mysql服務端 --> 磁盤,orm其實就是將類對象的語法翻譯成sql語句的一個引擎
在python中orm的對應關係有三種: 類 ---------->表 類對象 ---------->行(記錄) 類屬性 ---------->表的字段(重點
建立表
# app 應用下的 models.py 文件中寫 from django.db import models class UserInfo(models.Model): # UserInfo 爲表名 id = models.AutoField(primary_key=True) name = models.CharField(max_length=10) age = models.IntegerField() current_date = models.DateField()
更多字段和參數
字段
<1> CharField 字符串字段, 用於較短的字符串. CharField 要求必須有一個參數 maxlength, 用於從數據庫層和Django校驗層限制該字段所容許的最大字符數. <2> IntegerField 用於保存一個整數. <3> DecimalField 一個浮點數. 必須 提供兩個參數: <4> AutoField 一個 IntegerField, 添加記錄時它會自動增加. 你一般不須要直接使用這個字段; 自定義一個主鍵:my_id=models.AutoField(primary_key=True) 若是你不指定主鍵的話,系統會自動添加一個主鍵字段到你的 model.
參數
(1)null 若是爲True,Django 將用NULL 來在數據庫中存儲空值。 默認值是 False. (1)blank 若是爲True,該字段容許不填。默認爲False。 要注意,這與 null 不一樣。null純粹是數據庫範疇的,而 blank 是數據驗證範疇的。 若是一個字段的blank=True,表單的驗證將容許該字段是空值。若是字段的blank=False,該字段就是必填的。 (2)default 字段的默認值。能夠是一個值或者可調用對象。若是可調用 ,每有新對象被建立它都會被調用,若是你的字段沒有設置能夠爲空,那麼未來若是咱們後添加一個字段,這個字段就要給一個default值 (3)primary_key 若是爲True,那麼這個字段就是模型的主鍵。若是你沒有指定任何一個字段的primary_key=True, Django 就會自動添加一個IntegerField字段作爲主鍵,因此除非你想覆蓋默認的主鍵行爲, 不然不必設置任何一個字段的primary_key=True。 (4)unique 若是該值設置爲 True, 這個數據字段的值在整張表中必須是惟一的 (5)choices 由二元組組成的一個可迭代對象(例如,列表或元組),用來給字段提供選擇項。 若是設置了choices ,默認的表單將是一個選擇框而不是標準的文本框,<br>並且這個選擇框的選項就是choices 中的選項。 (6)db_index 若是db_index=True 則表明着爲此字段設置數據庫索引。 DatetimeField、DateField、TimeField這個三個時間字段,均可以設置以下屬性。 (7)auto_now_add 配置auto_now_add=True,建立數據記錄的時候會把當前時間添加到數據庫。 (8)auto_now 配置上auto_now=True,每次更新數據記錄的時候會更新該字段,標識這條記錄最後一次的修改時間。
settings配置
若想將模型轉爲mysql數據庫中的表,須要在 settings.py 中配置:
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME':'庫名', # 要鏈接的數據庫,鏈接前須要建立好 'USER':'root', # 鏈接數據庫的用戶名 'PASSWORD':'', # 鏈接數據庫的密碼 'HOST':'127.0.0.1', # 鏈接主機,默認本級 'PORT':3306 , # 端口 默認3306 } }
項目文件夾下的 init.py文件中,寫下面兩句
import pymysql pymysql.install_as_MySQLdb()
執行數據庫同步指令
python manage.py makemigrations # 生成記錄,每次修改了models裏面的內容或者添加了新的app,新的app裏面寫了models裏面的內容,都要執行這兩條 python manage.py migrate # 執行上面這個語句的記錄來建立表,生成的表名字前面會自帶應用的名字,例如:你的book表在mysql裏面叫作app01_book表
model.py :
from django.db import models class Data(models.Model): name = models.CharField(max_length=10) age = models.IntegerField() current_data = models.DateField() def __str__(self): return self.name
建立方式一:
from app import models student_obj = models.Data( name = 'alex', age = 73, current_data= '2008-08-08' ) student_obj.save()
方式二(經常使用此建立)
from app import models new_obj = models.Data.objects.create( name = 'wusir', age = 83, current_data= '2008-08-15', ) print(new_obj) # Data object --> model對象 print(new_obj.name,new_obj.age) # .屬性 能夠獲取對應字段的數據
方式三:
from app import models lis = [] for i in range(10): obj = models.Data( name = 'xin', age = 18, current_data= '2010-10-10' ) lis.append(obj) models.Data.objects.bulk_create(lis) # 批量插入,速度快
建立方式四: update_or_create 有就更新,沒有就建立
from app import models models.Data.objects.update_or_create( name = 'taibai', # 有就更新 defaults={'age':89,'current_data':'2011-11-11'} name = 'xuefei', # 沒有就建立 defaults={'age':18,'current_data':'2000-08-08'} )
# all() 查詢全部的數據,返回的是queryset集合 all_objs = models.Data.objects.all() print(all_objs) for i in all_objs: print(i.name) # 拿到每個名字 # 條件查詢: filter()方法, 返回的也是queryset集合,查詢不到內容不會報錯,返回一個<QuerySet []>空的queryset objs = models.Data.objects.filter(id=15) print(objs) objs = models.Data.objects.filter(id=1,name='alex').update(name='eva',age=20) print(objs) 打散的形式傳參 objs = models.Data.objects.filter(**{'id':15,'name':'xuefei'}) print(objs) # 條件查詢 : get()方法,返回的是model對象,並且get方法有且必須只有一個結果 objs = models.Data.objects.get(id=15) print(objs) 查詢的數據不存在會報錯,獲得的結果有兩個時會報錯 # exclude(**kwargs):排除的意思,包含了與所給篩選條件不匹配的對象,沒有不等於操做, objects控制器和queryset集合均可以調用,返回值是queryset類型. ex = models.Data.objects.exclude(name='xin') ex = models.Data.objects.all().exclude(name='xin') print(ex) # order_by(): queryset類型的數據來調用,查詢結果進行排序,默認是按照id的升序排序的,返回值仍是queryset類型,在字段前面加個 - 號,就是降序排序 ord = models.Data.objects.order_by('-age','id') # 多條件排序,按照age進行降序,age相同的按照id升序排序 print(ord) # reverse() : queryset類型的數據來調用,對查詢結果反向排序,返回值仍是queryset類型 rev = models.Data.objects.order_by('id').reverse() print(rev) # count() : queryset類型的數據來調用,返回數據庫中匹配查詢(QuerySet)的對象數量。 con = models.Data.objects.all().count() print(con) # first() : queryset類型的數據來調用,返回第一條記錄,獲得的都是model對象 obj = models.Data.objects.all().first() print(obj) # last(): queryset類型的數據來調用,返回最後一條記錄,結果爲model對象類型 obj = models.Data.objects.all().last() print(obj) # exists() : queryset類型的數據來調用,若是QuerySet包含數據,就返回True,不然返回False,空的queryset類型數據也有布爾值True和False,可是通常不用它來判斷數據庫裏面是否是有數據,若是有大量的數據,你用它來判斷,那麼就須要查詢出全部的數據,效率太差了,用count或者exits # values(*field) : 用的比較多,queryset類型的數據來調用,返回一個ValueQuerySet——一個特殊的QuerySet,運行後獲得的並非一系列,model的實例化對象,而是一個可迭代的字典序列,只要是返回的queryset類型,就能夠繼續鏈式調用queryset類型的其餘的查找方法,其餘方法也是同樣的。 # values_list(*field): 它與values()很是類似,它返回的是一個元組序列 obj = models.Data.objects.all().filter(age=16).values('name','age') print(obj) obj = models.Data.objects.all().filter(age=16).values_list('name','age') print(obj) # distinct(): values和values_list獲得的queryset類型的數據來調用,從返回結果中剔除重複紀錄,結果仍是queryset query = models.Data.objects.all().values('age').distinct() print(query)
mes = models.Data.objects.filter(price__in=[100,200,300]) # price值等於這三個裏面的任意一個的對象 mes = models.Data.objects.filter(price__gt=100) # 大於,大於等因而price__gte=100,別寫price>100,這種參數不支持 mes = models.Data.objects.filter(price__lt=100) # 小於 mes = models.Data.objects.filter(price__range=[100,200]) # sql的between and,大於等於100,小於等於200 mes = models.Data.objects.filter(title__contains="python") #title值中包含python的 mes = models.Data.objects.filter(title__icontains="python") #不區分大小寫 mes = models.Data.objects.filter(title__startswith="py") #以什麼開頭,istartswith 不區分大小寫 all_books = models.Book.objects.filter(pub_date__year=2012) #找2012年的全部書籍 all_books = models.Book.objects.filter(pub_date__year__gt=2012) # 找大於2012年的全部書籍 all_books = models.Book.objects.filter(pub_date__year=2019,pub_date__month=2) #找2019年月份的全部書籍
delete queryset 和model對象均可以調用 models.Student.objects.get(id=3).delete() # model對象來調用的delete方法 models.Student.objects.filter(name='Alex').delete() models.Student.objects.all().delete() # 刪除全部
model對象不能調用更新方法 報錯信息'Student' object has no attribute 'update' 只能queryset調用 models.Student.objects.get(name='alex').update(age=38) # 報錯 models.Student.objects.filter(name='alex').update(age=38)