Django - - - -視圖層之視圖函數(views)
視圖層之視圖函數(views)
一個視圖函數,簡稱視圖,是一個簡單的Python 函數,它接受Web請求並且返回Web響應。響應可以是一張網頁的HTML內容,一個重定向,一個404錯誤,一個XML文檔,或者一張圖片. . . 是任何東西都可以。無論視圖本身包含什麽邏輯,都要返回響應。代碼寫在哪裏也無所謂,只要它在你的Python目錄下面。除此之外沒有更多的要求了——可以說“沒有什麽神奇的地方”。為了將代碼放在某處,約定是將視圖放置在項目或應用程序目錄中的名為views.py的文件中。
視圖函數:
一定包含兩個對象:
requset---->用戶請求相關的所有信息(對象)
一個簡單的視圖
下面是一個返回當前日期和時間作為HTML文檔的視圖:
from django.http import HttpResponse import datetime def current_datetime(request): now = datetime.datetime.now() html = "<html><body>It is now %s.</body></html>" % now return HttpResponse(html)
讓我們逐行閱讀上面的代碼:
-
首先,我們從 django.http模塊導入了HttpResponse類,以及Python的datetime庫。
-
接著,我們定義了current_datetime函數。它就是視圖函數。每個視圖函數都使用HttpRequest對象作為第一個參數,並且通常稱之為request。
註意,視圖函數的名稱並不重要;不需要用一個統一的命名方式來命名,以便讓Django識別它。我們將其命名為current_datetime,是因為這個名稱能夠精確地反映出它的功能。
-
這個視圖會返回一個HttpResponse對象,其中包含生成的響應。每個視圖函數都負責返回一個HttpResponse
視圖函數,圍繞著兩個對象進行:HttpResponse和HttpRequest
1.HttpRequest
request---->請求信息
屬性:
request.path # 獲取訪問文件路徑 request.method屬性 #獲取請求中使用的HTTP方式(POST/GET) request.GET #GET請求的數據(類字典對象) 請求頭中的url中?後面拿值
request.POST # POST請求的數據(類字典對象) 請求體裏拿值
request.COOKIES #包含所有cookies的標準Python字典對象;keys和values都是字符串。
request.FILES: 包含所有上傳文件的類字典對象;FILES中的每一個Key都是<input type="file" name="" />標簽中
name屬性的值,FILES中的每一個value同時也是一個標準的python字典對象,包含下面三個Keys:
filename: 上傳文件名,用字符串表示
content_type: 上傳文件的Content Type
content: 上傳文件的原始內容
request.user: 是一個django.contrib.auth.models.User對象,代表當前登陸的用戶。如果訪問用戶當前
沒有登陸,user將被初始化為django.contrib.auth.models.AnonymousUser的實例。你
可以通過user的is_authenticated()方法來辨別用戶是否登陸:
if req.user.is_authenticated();只有激活Django中的AuthenticationMiddleware
時該屬性才可用
request.session: 唯一可讀寫的屬性,代表當前會話的字典對象;自己有激活Django中的session支持時該屬性才可用
request.GET.get(‘name‘) 拿到GET請求裏name的值
如果某個鍵對應有多個值,則不能直接用get取值,需要用getlist,如:
request.POST.getlist("hobby")
請求url:http://127.0.0.1:8000/index.html/23?a=1
request.path : 請求路徑
request.path結果為:/index.html/23
request.get_full_path()
request.get_full_path()結果為:/index.html/23?a=1
方法:
1 |
get_full_path()
|
註意:鍵值對的值是多個的時候,比如checkbox類型的input標簽,select標簽,需要用:
1 |
request.POST.getlist( "hobby" )
|
2.HttpResponse
HttpResponse---->相應字符串
對於HttpRequest請求對象來說,是由django自動創建的,但是,HttpResponse響應對象就必須我們自己創建。每個view請求處理方法必須返回一個HttpResponse響應對象。HttpResponse類在django.http.HttpResponse。
在HttpResponse對象上擴展的常用方法
1.render 函數
將指定頁面渲染後返回給瀏覽器
render(request, template_name[, context])
結合一個給定的模板和一個給定的上下文字典,並返回一個渲染後的 HttpResponse 對象。
參數: request: 用於生成響應的請求對象。 template_name:要使用的模板的完整名稱,可選的參數 context:添加到模板上下文的一個字典。默認是一個空字典。如果字典中的某個值是可調用的,視圖將在渲染模板之前調用它。 content_type:生成的文檔要使用的MIME類型。默認為DEFAULT_CONTENT_TYPE 設置的值。 status:響應的狀態碼。默認為200。
from django.shortcuts import render def test(request): return render(request,‘index.html‘) #向用戶顯示一個html頁面
下面為render官方源碼,可以看出render最後也是返回了一個HttpResponse給webserver
def render(request, template_name, context=None, content_type=None, status=None, using=None): """ Returns a HttpResponse whose content is filled with the result of calling django.template.loader.render_to_string() with the passed arguments. """ content = loader.render_to_string(template_name, context, request, using=using) return HttpResponse(content, content_type, status)
細說render:
render方法主要是將從服務器提取的數據,填充到模板中,然後將渲染後的html靜態文件返回給瀏覽器。這裏一定要註意:render渲染的是模板,下面我們看看什麽叫作模板:
<!DOCTYPE html> <html lang="en"> <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> <style> li,ul,ol{ list-style: none; } a{ text-decoration: none; } </style> </head> <body> <ul> {% for book in list %} <li><a href="{{book.id}}">{{ book.btitle }}</a></li> {% endfor %} </ul> </body> </html>
上面{%%}之間包括的就是我們要從數據庫取出的數據,進行填充。對於這樣一個沒有填充數據的html文件,瀏覽器是不能進行渲染的,所以,對於上述{%%}之間的內容先要被render進行渲染之後,才能發送給瀏覽器。
下面舉個例子:
<!DOCTYPE html> <html lang="en"> <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> <style> li,ul,ol{ list-style: none; } a{ text-decoration: none; } </style> </head> <body> <ul> {% for book in list %} <li><a href="{{book.id}}">{{ book.btitle }}</a></li> {% endfor %} </ul> </body> </html>show.html
def show(request, id): book = BookInfo.objects.get(pk=id) #從數據庫中取出對應id的數據 herolist = book.heroinfo_set.all() context = {‘list‘: herolist} # 將數據保存在list return render(request, ‘booktest/show.html‘, context) #通過render進行模板渲染
2.redirect 函數
參數可以是:
- 一個模型:將調用模型的get_absolute_url() 函數
- 一個視圖,可以帶有參數:將使用urlresolvers.reverse 來反向解析名稱
- 一個絕對的或相對的URL,將原封不動的作為重定向的位置。
默認返回一個臨時的重定向;傳遞permanent=True 可以返回一個永久的重定向。
示例:
你可以用多種方式使用redirect() 函數。
傳遞一個對象
將調用get_absolute_url() 方法來獲取重定向的URL:
1 2 3 4 5 6 |
from django.shortcuts import redirect
def my_view(request):
...
object = MyModel.objects.get(...)
return redirect( object )
|
傳遞一個視圖的名稱
可以帶有位置參數和關鍵字參數;將使用reverse() 方法反向解析URL:
1 2 3 |
def my_view(request):
...
return redirect( ‘some-view-name‘ , foo = ‘bar‘ )
|
傳遞要重定向的一個硬編碼的URL
1 2 3 |
def my_view(request):
...
return redirect( ‘/some/url/‘ )
|
也可以是一個完整的URL:
1 2 3 |
def my_view(request):
...
return redirect( ‘http://example.com/‘ )
|
默認情況下,redirect() 返回一個臨時重定向。以上所有的形式都接收一個permanent 參數;如果設置為True,將返回一個永久的重定向:
1 2 3 4 |
def my_view(request):
...
object = MyModel.objects.get(...)
return redirect( object , permanent = True )
|
跳轉(重定向)應用
-----------------------------------url.py url(r"login", views.login), url(r"yuan_back", views.yuan_back), -----------------------------------views.py def login(req): if req.method=="POST": if 1: # return redirect("/yuan_back/") name="yuanhao" return render(req,"my backend.html",locals()) return render(req,"login.html",locals()) def yuan_back(req): name="苑昊" return render(req,"my backend.html",locals()) -----------------------------------login.html <form action="/login/" method="post"> <p>姓名<input type="text" name="username"></p> <p>性別<input type="text" name="sex"></p> <p>郵箱<input type="text" name="email"></p> <p><input type="submit" value="submit"></p> </form> -----------------------------------my backend.html <h1>用戶{{ name }}你好</h1>View Code
下面我們來看一個現象:
--------------------urls.py------------------------------ urlpatterns = [ url(r‘^admin/‘, admin.site.urls), url(r‘^login/‘, views.login), url(r‘^index/‘, views.index,), # url(r‘^register/‘, views.register,name=‘reg‘), ] ------------------view.py------------------------------- def login(request): if request.method==‘POST‘: username=request.POST.get(‘user‘) password=request.POST.get(‘pwd‘) if username==‘yuan‘ and password==‘123‘: # return render(request,‘index.html‘) return redirect(‘/index/‘) else: return render(request,‘login.html‘,{‘info‘:‘賬號或密碼錯誤‘}) else: return render(request,‘login.html‘) def index(request): name=‘yuan‘ return render(request,‘index.html‘,{‘a‘:name}) ---------------login.html-------------------------------- <h1>登陸界面</h1> <form action="/login/" method="post"> <p>姓名 <input type="text" name="user"></p> <p>密碼 <input type="password" name="pwd"></p> <p><input type="submit"></p> <p>{{ info }}</p> </form> ---------------login.html-------------------------------- <h1>個人主頁</h1> <h2>hello,{{ a}}</h2>代碼
首先,啟動服務器後,我們進入login頁面
正確輸入姓名,密碼後,此時執行redirect函數,結果如下
現在我們將redirect換成render,再重新走一遍看看,在login頁面,正確輸入姓名,密碼後,結果如下:
細心的人會發現,用render函數執行後的,地址欄的地址沒有變化,還是login,且頁面上的{{a}}此時也沒有被渲染,所以hello,後面沒有內容顯示!
對比render與redirect:
原因是
render: 只是返回頁面內容,但是未發送第二次請求
redirect:發送了第二次請求,url更新
總結兩者區別:
第一,render返回一個登陸成功後的頁面,刷新該頁面將回復到跳轉前頁面。而redirect則不會
第二,如果頁面需要模板語言渲染,需要的將數據庫的數據加載到html,那麽render方法則不會顯示這一部分,render返回一個登陸成功頁面,不會經過url路由分發系統,也就是說,不會執行跳轉後url的視圖函數。這樣,返回的頁面渲染不成功;而redirect是跳轉到指定頁面,當登陸成功後,會在url路由系統進行匹配,如果有存在的映射函數,就會執行對應的映射函數。
Django - - - -視圖層之視圖函數(views)