一.FBV和CBV
1.基於函數的view,就叫FBV(Function Based View)
示例:
def add_book(request):
pub_obj=models.Publisher.objects.all() #從數據庫獲取所有出版社對象
if request.method=='POST':
add_name=request.POST.get('book_name')
pub_id=request.POST.get('pub_id')
models.Book.objects.create(name=add_name,publisher_id=pub_id)
return redirect('/book/')
return render(request,'add_book.html',{"pub_obj":pub_obj})
2.基於類的view,就叫CBV (Class Based View)
先在urls.py 中修改對應關係
如 : url(r'^add_book',views.Addbook.as_view()),=======>url(r'^add_book',view)
解析過程:
as_view是一個類方法 return view,
view 是一個函數 實例化一個對象; 封裝request屬性;return self.dispatch(self, request, *args, **kwargs)
dispatch是一個函數:
if request.method.lower() in self.http_method_names:
handler = getattr(self, request.method.lower(), self.http_method_not_allowed) 經過反射來操做對象屬性或方法
return handler(request, *args, **kwargs)
補充: 八種請求方法
http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
views中寫類
from django.views import View
示例:
class Addbook(View):
def dispatch(self, request, *args, **kwargs):
# print("函數以前")
ret=super(Addbook, self).dispatch(request, *args, **kwargs)
# print("函數以後")
return ret
def get(self,request):
pub_obj = models.Publisher.objects.all()
return render(request,'add_book.html',{"pub_obj":pub_obj})
def post(self,request):
add_name = request.POST.get('book_name')
pub_id=request.POST.get('pub_id')
models.Book.objects.create(name=add_name,publisher_id=pub_id)
return redirect('/book/')
二.加裝飾器
裝飾器
def wrapper(func):
def inner(*args,**kwargs):
start=time.time()
ret=func(*args,**kwargs)
print("執行時間爲:{}".format(time.time()-start))
return ret
return inner
(一)FBV
@wrapper #加裝飾器
def add_book(request):
pub_obj=models.Publisher.objects.all() #從數據庫獲取所有出版社對象
if request.method=='POST':
add_name=request.POST.get('book_name')
pub_id=request.POST.get('pub_id')
models.Book.objects.create(name=add_name,publisher_id=pub_id)
return redirect('/book/')
return render(request,'add_book.html',{"pub_obj":pub_obj})
(二).CBV
首先導入:from django.utils.decorators import method_decorator
1.直接給類加裝飾器
@method_decorator(wrapper,name="post") #給post加裝飾器
@method_decorator(wrapper,name="get") #給get加裝飾器
class Addbook(View):
...
2.給dispatch加裝飾器(同時給get和post加裝飾器)
@method_decorator(wrapper) #同時給get和post加裝飾器
def dispatch(self, request, *args, **kwargs):
...
3.分別給get和post加裝飾器
a. @method_decorator(wrapper) #只給get方法加裝飾器
def get(self,request):
...
b. @method_decorator(wrapper) #只給post方法加裝飾器 能夠同時存在
def post(self,request):
...
三.Request對象和Response對象
(一)Request 對象
當一個頁面被請求時,Django就會建立一個包含本次請求原信息的HttpRequest對象。
Django會將這個對象自動傳遞給響應的視圖函數,通常視圖函數約定俗成地使用 request 參數承接這個對象。
def test(request):
1.屬性
print(request,type(request)) #<WSGIRequest: GET '/test/'> <class 'django.core.handlers.wsgi.WSGIRequest'>
print(request.method) #GET
print(request.GET) #<QueryDict: {}>
print(request.POST) #<QueryDict: {}>
print(request.path_info) #/test/JHHK (不包括域名,只有路徑)
print(request.body) #若是是get: b''; 若是是post:b'請求體'
print(request.scheme) # 協議 http
print(request.encoding) #None表示提交的數據的編碼方式
# (若是爲 None 則表示使用 DEFAULT_CHARSET 的設置,默認爲 'utf-8')。
print(request.COOKIES) # 一個標準的Python 字典,包含全部的cookie。鍵和值都爲字符串
print(request.FILES)
文件上傳 Request.FILES
views:
def upload(request):
if request.method=='POST':
file_obj=request.FILES.get('upload')
print(file_obj.name)
with open(file_obj.name, 'wb') as f:
for chunk in file_obj.chunks():
f.write(chunk)
return render(request,'upload.html')
html:
<form action="" method="post" enctype="multipart/form-data">
<input type="file" name="upload">
<button type="submit">提交</button>
</form>
# 注意: form中必定要寫 enctype="multipart/form-data"
補充:
一個相似於字典的對象,包含全部的上傳文件信息。
FILES 中的每一個鍵爲<input type="file" name="" /> 中的name,值則爲對應的數據。
注意,FILES 只有在請求的方法爲POST 且提交的<form> 帶有enctype="multipart/form-data" 的狀況下才會
包含數據。不然,FILES 將爲一個空的相似於字典的對象。
POST 請求中用到
file_obj = request.FILES.get('file_name')
2.方法
(1)print(request.get_host()) # 127.0.0.1:8000
根據從HTTP_X_FORWARDED_HOST(若是打開 USE_X_FORWARDED_HOST,默認爲False)和 HTTP_HOST 頭部信息返回請求的原始主機。
若是這兩個頭部沒有提供相應的值,則使用SERVER_NAME 和SERVER_PORT,在PEP 3333 中有詳細描述。
USE_X_FORWARDED_HOST:一個布爾值,用於指定是否優先使用 X-Forwarded-Host 首部,僅在代理設置了該首部的狀況下,才能夠被使用。
例如:"127.0.0.1:8000"
注意:當主機位於多個代理後面時,get_host() 方法將會失敗。除非使用中間件重寫代理的首部。
(2)print(request.get_full_path()) # /test/123456789?asdafd=2143242&sdsdsf=sdsdfdsf(路徑+?+查詢內容)
返回 path,若是能夠將加上查詢字符串。
例如:"/music/bands/the_beatles/?print=true"
(3) print(request.is_secure()) #False
若是請求時是安全的,則返回True;即請求通是過 HTTPS 發起的。
(4)print(request.is_ajax()) #False
若是請求是經過XMLHttpRequest 發起的,則返回True,方法是檢查 HTTP_X_REQUESTED_WITH 相應的首部是不是字符串'XMLHttpRequest'。
大部分現代的 JavaScript 庫都會發送這個頭部。若是你編寫本身的 XMLHttpRequest 調用(在瀏覽器端),你必須手工設置這個值來讓 is_ajax() 能夠工做。
若是一個響應須要根據請求是不是經過AJAX 發起的,而且你正在使用某種形式的緩存例如Django 的 cache middleware,
你應該使用 vary_on_headers('HTTP_X_REQUESTED_WITH') 裝飾你的視圖以讓響應可以正確地緩存
(5)HttpRequest.get_signed_cookie(key, default=RAISE_ERROR, salt='', max_age=None)
返回簽名過的Cookie 對應的值,若是簽名再也不合法則返回django.core.signing.BadSignature。
若是提供 default 參數,將不會引起異常並返回 default 的值。
可選參數salt 能夠用來對安全密鑰強力攻擊提供額外的保護。max_age 參數用於檢查Cookie 對應的時間戳以確保Cookie 的時間不會超過max_age 秒。
代碼示例:
>>> request.get_signed_cookie('name')
'Tony'
>>> request.get_signed_cookie('name', salt='name-salt')
'Tony' # 假設在設置cookie的時候使用的是相同的salt
>>> request.get_signed_cookie('non-existing-cookie')
...
KeyError: 'non-existing-cookie' # 沒有相應的鍵時觸發異常
>>> request.get_signed_cookie('non-existing-cookie', False)
False
>>> request.get_signed_cookie('cookie-that-was-tampered-with')
...
BadSignature: ...
>>> request.get_signed_cookie('name', max_age=60)
...
SignatureExpired: Signature age 1677.3839159 > 60 seconds
>>> request.get_signed_cookie('name', False, max_age=60)
False
(二)Response對象( HttpResponse , JsonResponse )
與由Django自動建立的HttpRequest對象相比,HttpResponse對象是咱們的職責範圍了。咱們寫的每一個視圖都須要實例化,
填充和返回一個HttpResponse。
1.HttpResponse對象 HttpResponse類位於django.http模塊中。
屬性:
(1) print(HttpResponse.content) #<property object at 0x000001C0A0182638>響應內容
(2)print(HttpResponse.charset) #<property object at 0x000001C0A01648B8>響應內容編碼
(3)print(HttpResponse.status_code) #200響應內容的編碼
使用:
(1).傳遞字符串
from django.http import HttpResponse
response = HttpResponse("Here's the text of the Web page.")
(2).設置或刪除響應頭信息
response = HttpResponse()
response['Content-Type'] = 'text/html; charset=UTF-8'
del response['Content-Type']
2.JsonResponse JsonResponse是HttpResponse的子類,專門用來生成JSON編碼的響應。
(1)from django.http import JsonResponse 導入
response = JsonResponse({'foo': 'bar'})
print(response.content) # b'{"foo": "bar"}'
print(response.charset) # utf-8
print(esponse.status_code) #200
注意:
默認只能傳遞字典類型,若是要傳遞非字典類型須要設置一下safe關鍵字參數。
response = JsonResponse([1, 2, 3], safe=False)
四.Django shortcut functions
(一).render()
參數:
request: 用於生成響應的請求對象。
template_name:要使用的模板的完整名稱,可選的參數
context:添加到模板上下文的一個字典。默認是一個空字典。若是字典中的某個值是可調用的,視圖將在渲染模板以前調用它。
content_type:生成的文檔要使用的MIME類型。默認爲 DEFAULT_CONTENT_TYPE 設置的值。默認爲'text/html'
status:響應的狀態碼。默認爲200。
useing: 用於加載模板的模板引擎的名稱。
示例:
簡潔版
from django.shortcuts import render
def my_view(request):
# 視圖的代碼寫在這裏
return render(request, 'myapp/index.html', {'foo': 'bar'})
原版:
結合一個給定的模板和一個給定的上下文字典,並返回一個渲染後的 HttpResponse 對象
from django.http import HttpResponse
from django.template import loader
def my_view(request):
# 視圖代碼寫在這裏
t = loader.get_template('myapp/index.html')
c = {'foo': 'bar'}
return HttpResponse(t.render(c, request))
(二).redirect()
參數能夠是:
一個模型:將調用模型的get_absolute_url() 函數
一個視圖,能夠帶有參數:將使用urlresolvers.reverse 來反向解析名稱
一個絕對的或相對的URL,將原封不動的做爲重定向的位置。
默認返回一個臨時的重定向;傳遞permanent=True 能夠返回一個永久的重定向。
使用:
(1)傳遞一個具體的ORM對象(瞭解便可)
from django.shortcuts import redirect
def my_view(request):
...
object = MyModel.objects.get(...)
return redirect(object)
(2)傳遞一個視圖的名稱
def my_view(request):
...
return redirect('some-view-name', foo='bar')
(3)傳遞要重定向到的一個具體的網址
def my_view(request):
...
return redirect('/some/url/')
(4)一個完整的網址
def my_view(request):
...
return redirect('http://example.com/')
補充:
臨時重定向(響應狀態碼:302)和永久重定向(響應狀態碼:301)對普通用戶來講是沒什麼區別的,它主要面向的是搜索引擎的機器人。
五.路由系統
URL配置(URLconf)就像Django所支撐網站的目錄。它的本質是URL與要爲該URL調用的視圖函數之間的映射表。
(一).URLconf配置基本語法
from django.conf.urls import url
urlpatterns = [
url(正則表達式, views視圖,參數,別名),
]
(二)參數說明:
正則表達式:一個正則表達式字符串
views視圖:一個可調用對象,一般爲一個視圖函數
參數:可選的要傳遞給視圖函數的默認參數(字典形式)
別名:一個可選的name參數
注意:
Django 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),
]
(三)正則詳解
1.基本配置
from django.conf.urls import url
from app01 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.注意事項
(1)urlpatterns中的元素按照書寫順序從上往下逐一匹配正則表達式,一旦匹配成功則再也不繼續。
(2)若要從URL中捕獲一個值,只須要在它周圍放置一對圓括號(分組匹配)
(3)不須要添加一個前導的反斜槓,由於每一個URL 都有。例如,應該是^articles 而不是 ^/articles。
(4)每一個正則表達式前面的'r' 是可選的可是建議加上.
3.補充說明
(1)是否開啓URL訪問地址後面不爲/跳轉至帶有/的路徑的配置項
APPEND_SLASH=True
(2)Django settings.py配置文件中默認沒有 APPEND_SLASH 這個參數,但 Django 默認這個參數爲 APPEND_SLASH = True。
其做用就是自動在網址結尾加'/'。
示例:
from django.conf.urls import url
from app01 import views
urlpatterns = [
url(r'^blog/$', views.blog),
]
效果 : 訪問 http://www.example.com/blog 時,默認將網址自動轉換爲 http://www.example/com/blog/ 。
若是在settings.py中設置了 APPEND_SLASH=False,此時咱們再請求 http://www.example.com/blog 時就會提示找不到頁面
(四)分組命名匹配
使用簡單的正則表達式分組匹配(經過圓括號)來捕獲URL中的值並以位置參數形式傳遞給視圖
一樣還可使用分組命名匹配的正則表達式組來捕獲URL中的值並以關鍵字參數形式傳遞給視圖
在Python的正則表達式中,分組命名正則表達式組的語法是(?P<name>pattern),其中name是組的名稱,pattern是要匹配的模式。
經過(?P<name>pattern)捕獲的值做爲關鍵字參數而不是位置參數傳遞給視圖函數
1.URLconf匹配的位置
URLconf 在請求的URL 上查找,將它當作一個普通的Python 字符串。不包括GET和POST參數以及域名。
例如,http://www.example.com/myapp/ 請求中,URLconf 將查找 /myapp/ 。
在http://www.example.com/myapp/?page=3 請求中,URLconf 仍將查找 /myapp/ 。
URLconf 不檢查請求的方法。換句話講,全部的請求方法 —— 同一個URL的POST、GET、HEAD等等 —— 都將路由到相同的函數。
2.捕獲的參數永遠都是字符串
每一個在URLconf中捕獲的參數都做爲一個普通的Python字符串傳遞給視圖,不管正則表達式使用的是什麼匹配方式
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'^page/$', views.page), 先匹配上它,沒有獲取到值,使用默認值
url(r'^page/(?P<num>[0-9]{4})/$', views.page)
]
# views.py中,
能夠爲num指定默認值
def page(request,num=1):
print(num)
return HttpResponse('ok')
在上面的例子中,兩個URL模式指向相同的view - views.page - 可是第一個模式並無從URL中捕獲任何東西。
若是第一個模式匹配上了,page()函數將使用其默認參數num=「1」,若是第二個模式匹配,page()將使用正則表達式捕獲到的num值。
4.include其餘的URLconfs
from django.conf.urls import include, url
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^blog/', include('blog.urls')), # 能夠包含其餘的URLconfs文件
]
(五)傳遞額外的參數給視圖函數
URLconfs 具備一個鉤子,讓你傳遞一個Python 字典做爲額外的參數傳遞給視圖函數。
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中捕獲的參數。
示例:
url(r'^book/([0-9]{4})/([0-9]{2})/$', views.book,{'foo':'bar'})
def book(request,*args,**kwargs):
#http://127.0.0.1:8000/book/2018/09/
# print(args) #('2018', '09')
# print(kwargs) # {'foo': 'bar'} 額外加參數
return HttpResponse('ok')
六.include urlconfs include其餘的URLconfs from django.conf.urls import include, url urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^blog/', include('blog.urls')), # 能夠包含其餘的URLconfs文件]七.命名URL和反向解析(一).命名 name url(r'^home/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/',views.home, name='home')(二)反向解析(include)無重名狀況下: 系統的url.py 文件中 url(r'^app01/', include('app01.urls')), app01 的url.py文件中: url(r'^home/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/',views.home, name='home') views.py 文件中 reverse('home',kwargs={"year":'1994','month':'08'})) url最終形式打印結果 /app01/home/1994/08/八.命名空間namespace語法:'命名空間名稱:URL名稱'使用狀況:個人兩個app中 url名稱重複了,我反轉URL的時候就能夠經過命名空間的名稱獲得我當前的URL。重名覆蓋現象: 系統的url.py 文件中 url(r'^app01/', include('app01.urls')), url(r'^app02/', include('app02.urls')) app01.py文件中 url(r'^home/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/',views.home, name='home') app02.py文件中 url(r'^home/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/',views.home, name='home' views.py 文件中 reverse('home',kwargs={"year":'1994','month':'08'}) url最終形式打印結果 /app02/home/1994/08/重名問題說明: 兩個app下的urlde name屬性都是home,當反向解析時解釋器默認找系統url中最後一個匹配的home,覆蓋前面的內容.解決辦法: 命名空間namespace 系統的url.py 文件中 url(r'^app01/', include('app01.urls'),namespace='app01'), url(r'^app02/', include('app02.urls'),namespace='app02'), views.py文件中 reverse('app01:home',kwargs={"year":'1994','month':'08'}) 反向解析時:"namespace:name" 目標app下的url:對應的name url最終形式打印結果 /app01/home/1994/08/ 深坑: 只要設置了namespace="xxx" views中反向解析時必定要寫reverse('xxx:name',args=())示例: (多個刪除合併) 涉及到的分別加上那麼屬性 url: url(r'^del_(publisher|book|author)/(\d+)/$',views.delete) views: def delete(request,table,del_id): # table_dict={ # 'publisher': models.Publisher, # 'book': models.Book, # 'author': models.Author, # } # table_class=table_dict.get(table) table_class=getattr(models,table.capitalize()) print(table_class) table_class.objects.get(id=del_id).delete() return redirect(reverse(table))