django-視圖

 

視圖

  • 視圖接受Web請求而且返回Web響應
  • 視圖就是一個python函數,被定義在views.py中
  • 響應能夠是一張網頁的HTML內容,一個重定向,一個404錯誤等等
  • 響應處理過程以下圖:

3.1.URLconf

  • 在settings.py文件中經過ROOT_URLCONF指定根級url的配置
  • urlpatterns是一個url()實例的列表
  • 一個url()對象包括:
    • 正則表達式
    • 視圖函數
    • 名稱name
  • 編寫URLconf的注意:
    • 若要從url中捕獲一個值,須要在它周圍設置一對圓括號
    • 不須要添加一個前導的反斜槓,如應該寫做'test/',而不該該寫做'/test/'
    • 每一個正則表達式前面的r表示字符串不轉義
  • 請求的url被看作是一個普通的python字符串,進行匹配時不包括get或post請求的參數及域名
    http://www.igeekhome.com/python/1/?i=1&p=new,只匹配「/python/1/」部分
  • 正則表達式非命名組,經過位置參數傳遞給視圖
    url(r'^([0-9]+)/$', views.detail, name='detail'),
  • 正則表達式命名組,經過關鍵字參數傳遞給視圖,本例中關鍵字參數爲id
    url(r'^(?P<id>[0-9]+)/$', views.detail, name='detail'),
  • 參數匹配規則:優先使用命名參數,若是沒有命名參數則使用位置參數
  • 每一個捕獲的參數都做爲一個普通的python字符串傳遞給視圖
  • 性能:urlpatterns中的每一個正則表達式在第一次訪問它們時被編譯,這使得系統至關快

包含其它的URLconfs

  • 在應用中建立urls.py文件,定義本應用中的urlconf,再在項目的settings中使用include()
    from django.conf.urls import include, url
    urlpatterns = [
        url(r'^', include('booktest.urls', namespace='booktest')),
    ]
  • 匹配過程:先與主URLconf匹配,成功後再用剩餘的部分與應用中的URLconf匹配
    請求http://www.igeekhome.com/booktest/1/
    
    在urls.py中的配置:
    
    url(r'^booktest/', include('booktest.urls', namespace='booktest')),
    
    在booktest應用urls.py中的配置
    
    url(r'^(/[0-9]+)/$', views.detail, name='detail'),
    
    匹配部分是:/booktest/1/
    
    匹配過程:在urls.py中與「booktest/」成功,再用「1/」與booktest應用的urls匹配
  • 使用include能夠去除urlconf的冗餘
  • 參數:視圖會收到來自父URLconf、當前URLconf捕獲的全部參數
  • 在include中經過namespace定義命名空間,用於反解析

URL的反向解析

  • 若是在視圖、模板中使用硬編碼的連接,在urlconf發生改變時,維護是一件很是麻煩的事情
  • 解決:在作連接時,經過指向urlconf的名稱,動態生成連接地址
  • 視圖:使用django.core.urlresolvers.reverse()函數
  • 模板:使用url模板標籤

 

3.2. 視圖函數

定義視圖

  • 本質就是一個函數
  • 視圖的參數
    • 一個HttpRequest實例
    • 經過正則表達式組獲取的位置參數
    • 經過正則表達式組得到的關鍵字參數
  • 在應用目錄下默認有views.py文件,通常視圖都定義在這個文件中
  • 若是處理功能過多,能夠將函數定義到不一樣的py文件中
    新建views1.py
    #coding:utf-8
    from django.http import HttpResponse
    def index(request):
        return HttpResponse("你好")
    
    在urls.py中修改配置
    from . import views1
    url(r'^$', views1.index, name='index'), 

錯誤視圖

  • Django原生自帶幾個默認視圖用於處理HTTP錯誤

404 (page not found) 視圖

  • defaults.page_not_found(request, template_name='404.html')
  •  認的404視圖將傳遞一個變量給模板:request_path,它是致使錯誤的URL
  • 若是Django在檢測URLconf中的每一個正則表達式後沒有找到匹配的內容也將調用404視圖
  • 在settings中DEBUG設置爲True,那麼將永遠不會調用404視圖,而是顯示URLconf 並帶有一些調試信息
  • 在templates中建立404.html
<!DOCTYPE html>
<html>
<head>
    <title></title>
</head>
<body>
找不到了
<hr/>
{{request_path}}
</body>
</html>
  • 在settings.py中修改調試
    DEBUG = False
    
    ALLOWED_HOSTS = ['*', ]
  • 請求一個不存在的地址
    http://127.0.0.1:8000/test/

500 (server error) 視圖

  • defaults.server_error(request, template_name='500.html')
  • 在視圖代碼中出現運行時錯誤
  • 默認的500視圖不會傳遞變量給500.html模板
  • 若是在settings中DEBUG設置爲True,那麼將永遠不會調用505視圖,而是顯示URLconf 並帶有一些調試信息

400 (bad request) 視圖

  • defaults.bad_request(request, template_name='400.html')
  • 錯誤來自客戶端的操做
  • 當用戶進行的操做在安全方面可疑的時候,例如篡改會話cookie

 

3.3. Request對象

  • 服務器接收到http協議的請求後,會根據報文建立HttpRequest對象
  • 視圖函數的第一個參數是HttpRequest對象
  • 在django.http模塊中定義了HttpRequest對象的API

屬性

  • 下面除非特別說明,屬性都是隻讀的
  • path:一個字符串,表示請求的頁面的完整路徑,不包含域名
  • method:一個字符串,表示請求使用的HTTP方法,經常使用值包括:'GET'、'POST'
  • encoding:一個字符串,表示提交的數據的編碼方式
    • 若是爲None則表示使用瀏覽器的默認設置,通常爲utf-8
    •  這個屬性是可寫的,能夠經過修改它來修改訪問表單數據使用的編碼,接下來對屬性的任何訪問將使用新的encoding值
  • GET:一個相似於字典的對象,包含get請求方式的全部參數
  • POST:一個相似於字典的對象,包含post請求方式的全部參數
  • FILES:一個相似於字典的對象,包含全部的上傳文件
  • COOKIES:一個標準的Python字典,包含全部的cookie,鍵和值都爲字符串
  • session:一個既可讀又可寫的相似於字典的對象,表示當前的會話,只有當Django 啓用會話的支持時纔可用,詳細內容見「狀態保持」

方法

  • is_ajax():若是請求是經過XMLHttpRequest發起的,則返回True

3.3.1. QueryDict對象

  • 定義在django.http.QueryDict
  • request對象的屬性GET、POST都是QueryDict類型的對象
  • 與python字典不一樣,QueryDict類型的對象用來處理同一個鍵帶有多個值的狀況
  • 方法get():根據鍵獲取值
    • 只能獲取鍵的一個值
    • 若是一個鍵同時擁有多個值,獲取最後一個值
      dict.get('',default)
      
      或簡寫爲
      
      dict['']
  • 方法getlist():根據鍵獲取值
    • 將鍵的值以列表返回,能夠獲取一個鍵的多個值
      dict.getlist('',default)

3.3.2. GET屬性

  • QueryDict類型的對象
  • 包含get請求方式的全部參數
  • 與url請求地址中的參數對應,位於?後面
  • 參數的格式是鍵值對,如key1=value1
  • 多個參數之間,使用&鏈接,如key1=value1&key2=value2
  • 鍵是開發人員定下來的,值是可變的
  • 示例以下
  • 建立視圖getTest1用於定義連接,getTest2用於接收一鍵一值,getTest3用於接收一鍵多值
    def getTest1(request):
    
        return render(request,'booktest/getTest1.html')
    
    def getTest2(request):
    
        return render(request,'booktest/getTest2.html')
    
    def getTest3(request):
    
        return render(request,'booktest/getTest3.html')
  • 配置url
    url(r'^getTest1/$', views.getTest1),
    
    url(r'^getTest2/$', views.getTest2),
    
    url(r'^getTest3/$', views.getTest3),
  • 建立getTest1.html,定義連接
    <html>
    <head>
        <title>Title</title>
    </head>
    <body>
    連接1:一個鍵傳遞一個值
    <a href="/getTest2/?a=1&b=2">gettest2</a><br>
    連接2:一個鍵傳遞多個值
    <a href="/getTest3/?a=1&a=2&b=3">gettest3</a>
    </body>
    </html>
  • 完善視圖getTest2的代碼
    def getTest2(request):
    
        a=request.GET['a']
    
        b=request.GET['b']
    
        context={'a':a,'b':b}
    
        return render(request,'booktest/getTest2.html',context)
  • 建立getTest2.html,顯示接收結果
    <html>
    
    <head>
    
        <title>Title</title>
    
    </head>
    
    <body>
    
    a:{{ a }}<br>
    
    b:{{ b }}
    
    </body>
    
    </html>
  • 完善視圖getTest3的代碼
    def getTest3(request):
    
        a=request.GET.getlist('a')
    
        b=request.GET['b']
    
        context={'a':a,'b':b}
    
        return render(request,'booktest/getTest3.html',context)
  • 建立getTest3.html,顯示接收結果
    <html>
    
    <head>
    
        <title>Title</title>
    
    </head>
    
    <body>
    
    a:{% for item in a %}
    
    {{ item }}
    
    {% endfor %}
    
    <br>
    
    b:{{ b }}
    
    </body>
    
    </html>

3.3.3. POST屬性

  • QueryDict類型的對象
  • 包含post請求方式的全部參數
  • 與form表單中的控件對應
  • 問:表單中哪些控件會被提交?
  • 答:控件要有name屬性,則name屬性的值爲鍵,value屬性的值爲值,構成鍵值對提交
    • 對於checkbox控件,name屬性同樣爲一組,當控件被選中後會被提交,存在一鍵多值的狀況
  • 鍵是開發人員定下來的,值是可變的

定義視圖postTest1

def postTest1(request):

    return render(request,'booktest/postTest1.html')
view1.py

配置urlhtml

url(r'^postTest1$',views.postTest1)
url.py

  建立模板postTest1.htmlpython

<html>

<head>

    <title>Title</title>

</head>

<body>

<form method="post" action="/postTest2/">

    姓名:<input type="text" name="uname"/><br>

    密碼:<input type="password" name="upwd"/><br>

    性別:<input type="radio" name="ugender" value="1"/><input type="radio" name="ugender" value="0"/>女<br>

    愛好:<input type="checkbox" name="uhobby" value="胸口碎大石"/>胸口碎大石

    <input type="checkbox" name="uhobby" value="跳樓"/>跳樓

    <input type="checkbox" name="uhobby" value="喝酒"/>喝酒

    <input type="checkbox" name="uhobby" value="登山"/>登山<br>

    <input type="submit" value="提交"/>

</form>

</body>

</html>
postTest1.html

 

建立視圖postTest2接收請求的數據程序員

def postTest2(request):

    uname=request.POST['uname']

    upwd=request.POST['upwd']

    ugender=request.POST['ugender']

    uhobby=request.POST.getlist('uhobby')

    context={'uname':uname,'upwd':upwd,'ugender':ugender,'uhobby':uhobby}

    return render(request,'booktest/postTest2.html',context)
postTest2

 

配置urlajax

url(r'^postTest2$',views.postTest2)
url.py

 

建立模板postTest2.html正則表達式

<html>

<head>

    <title>Title</title>

</head>

<body>

{{ uname }}<br>

{{ upwd }}<br>

{{ ugender }}<br>

{{ uhobby }}

</body>

</html>
postTest2.html

注意  :  使用表單提交,註釋掉settings.py中的中間件csrfredis

 

 

3.4. HttpResponse對象

  • 在django.http模塊中定義了HttpResponse對象的API
  • HttpRequest對象由Django自動建立,HttpResponse對象由程序員建立
  • 不調用模板,直接返回數據
    #coding=utf-8
    from django.http import HttpResponse
    
    def index(request):
        return HttpResponse('你好')
  • 調用模板
    from django.http import HttpResponse
    
    from django.template import RequestContext, loader
    
     
    
    def index(request):
    
        t1 = loader.get_template('polls/index.html')
    
        context = RequestContext(request, {'h1': 'hello'})
    
        return HttpResponse(t1.render(context))

屬性

  • content:表示返回的內容,字符串類型
  • charset:表示response採用的編碼字符集,字符串類型
  • status_code:響應的HTTP響應狀態碼
  • content-type:指定輸出的MIME類型

方法

  • init :使用頁內容實例化HttpResponse對象
  • write(content):以文件的方式寫
  • flush():以文件的方式輸出緩存區
  • set_cookie(key, value='', max_age=None, expires=None):設置Cookie
    • key、value都是字符串類型
    • max_age是一個整數,表示在指定秒數後過時
    • expires是一個datetime或timedelta對象,會話將在這個指定的日期/時間過時,注意datetime和timedelta值只有在使用PickleSerializer時纔可序列化
    • max_age與expires二選一
    • 若是不指定過時時間,則兩個星期後過時
from django.http import HttpResponse
from datetime import *

def index(request):
    response = HttpResponse()
    if request.COOKIES.has_key('h1'):
        response.write('<h1>' + request.COOKIES['h1'] + '</h1>')
    response.set_cookie('h1', '你好', 120)
    # response.set_cookie('h1', '你好', None, datetime(2016, 10, 31))
    return response
  • delete_cookie(key):刪除指定的key的Cookie,若是key不存在則什麼也不發生

子類HttpResponseRedirect

  • 重定向,服務器端跳轉
  • 構造函數的第一個參數用來指定重定向的地址

子類JsonResponse

  • 返回json數據,通常用於異步請求
  • _init _(data)
  • 幫助用戶建立JSON編碼的響應
  • 參數data是字典對象
  • JsonResponse的默認Content-Type爲application/json
# 在views1.py中

from django.http import HttpResponse,HttpResponseRedirect
from django.http import JsonResponse


def index(request):
  # 推薦使用反向解析
  # return HttpResponseRedirect(reverse('booktest:index2', args=(1,)))
    return HttpResponseRedirect('js/')

def index2(request, api):

    return HttpResponse('重定向')
  # 返回json數據
  return JsonResponse({'list': api})

# 在應用的urls.py中增長一個url對象

url(r'^js/$', views1.index2, name='index2'),

 

簡寫函數

render

  • render(request, template_name[, context])
  • 結合一個給定的模板和一個給定的上下文字典,並返回一個渲染後的HttpResponse對象
  • request:該request用於生成response
  • template_name:要使用的模板的完整名稱
  • context:添加到模板上下文的一個字典,視圖將在渲染模板以前調用它
from django.shortcuts import render

def index(request):
    return render(request, 'booktest/index.html', {'h1': 'hello'})

 

重定向

  • redirect(to)
  • 爲傳遞進來的參數返回HttpResponseRedirect
  • to推薦使用反向解析
from django.shortcuts import redirect
from django.core.urlresolvers import reverse


def index(request):
    return redirect(reverse('booktest:index2'))

 

獲得對象或返回404

  • get_object_or_404(klass, args, *kwargs)
  • 經過模型管理器或查詢集調用get()方法,若是沒找到對象,不引起模型的DoesNotExist異常,而是引起Http404異常
  • klass:獲取對象的模型類、Manager對象或QuerySet對象
  • **kwargs:查詢的參數,格式應該能夠被get()和filter()接受
  • 若是找到多個對象將引起MultipleObjectsReturned異常
from django.shortcuts import *

def detail(request, id):
    try:
        book = get_object_or_404(BookInfo, pk=id)
    except BookInfo.MultipleObjectsReturned:
        book = None
    return render(request, 'booktest/detail.html', {'book': book})

將settings.py中的DEBUG改成False數據庫

將請求地址輸入2和100查看效果django

 

獲得列表或返回404

  • get_list_or_404(klass, args, *kwargs)
  • klass:獲取列表的一個Model、Manager或QuerySet實例
  • **kwargs:查尋的參數,格式應該能夠被get()和filter()接受
from django.shortcuts import *

def index(request):
    # list = get_list_or_404(BookInfo, pk__lt=1)
    list = get_list_or_404(BookInfo, pk__lt=6)
    return render(request, 'booktest/index.html', {'list': list})

# 將settings.py中的DEBUG改成False

 

 

3.5. 狀態保持

  •  http協議是無狀態的:每次請求都是一次新的請求,不會記得以前通訊的狀態
  •  客戶端與服務器端的一次通訊,就是一次會話
  •  實現狀態保持的方式:在客戶端或服務器端存儲與會話有關的數據
  •  存儲方式包括cookie、session,會話通常指session對象
  •  使用cookie,全部數據存儲在客戶端,注意不要存儲敏感信息
  •  推薦使用session方式,全部數據存儲在服務器端,在客戶端cookie中存儲session_id
  •  狀態保持的目的是在一段時間內跟蹤請求者的狀態,能夠實現跨頁面訪問當前請求者的數據
  •  注意:不一樣的請求者之間不會共享這個數據,與請求者一一對應

啓用sessionjson

  • 使用django-admin startproject建立的項目默認啓用
  • 在settings.py文件中
    # 向INSTALLED_APPS列表中添加:
    'django.contrib.sessions',
    
    # 向MIDDLEWARE_CLASSES列表中添加:
    'django.contrib.sessions.middleware.SessionMiddleware',
  •  禁用會話:刪除上面指定的兩個值,禁用會話將節省一些性能消耗

使用sessionapi

  • 啓用會話後,每一個HttpRequest對象將具備一個session屬性,它是一個類字典對象
  • get(key, default=None):根據鍵獲取會話的值
  • clear():清除全部會話
  • flush():刪除當前的會話數據並刪除會話的Cookie
  • del request.session['member_id']:刪除會話

 在views.py文件中建立視圖

from django.shortcuts import render, redirect

from django.core.urlresolvers import reverse

 

def index(request):

    uname = request.session.get('uname')

    return render(request, 'booktest/index.html', {'uname': uname})

 

def login(request):

    return render(request, 'booktest/login.html')

 

def login_handle(request):

    request.session['uname'] = request.POST['uname']

    return redirect(reverse('booktest:index'))

 

def logout(request):

    # request.session['uname'] = None

    # del request.session['uname']

    # request.session.clear()

    request.session.flush()

    return redirect(reverse('booktest:index'))
views.py

配置url

# 主url:

from django.conf.urls import include, url

urlpatterns = [

    url(r'^', include('booktest.urls', namespace='booktest'))

]

 

# 應用url:

from django.conf.urls import url

from . import views

urlpatterns = [

    url(r'^$', views.index, name='index'),

    url(r'login/$', views.login, name='login'),

    url(r'login_handle/$', views.login_handle, name='login_handle'),

    url(r'logout/$', views.logout, name='logout')

]
主、應用url

建立模板index.html

<!DOCTYPE html>

<html>

<head>

    <title>首頁</title>

</head>

<body>

你好:{{uname}}

<hr/>

<a href="{%url 'booktest:login'%}">登陸</a>

<hr/>

<a href="{%url 'booktest:logout'%}">退出</a>

</body>

</html>
index.html

建立模板login.html

<!DOCTYPE html>

<html>

<head>

    <title>登陸</title>

</head>

<body>

<form method="post" action="/login_handle/">

    <input type="text" name="uname"/>

    <input type="submit" value="登陸"/>

</form>

</body>

</html>
login.html

 

會話過時時間

  • set_expiry(value):設置會話的超時時間
  • 若是沒有指定,則兩個星期後過時
  • 若是value是一個整數,會話將在values秒沒有活動後過時
  • 若果value是一個imedelta對象,會話將在當前時間加上這個指定的日期/時間過時
  • 若是value爲0,那麼用戶會話的Cookie將在用戶的瀏覽器關閉時過時
  • 若是value爲None,那麼會話永不過時
  • 修改視圖中login_handle函數,查看效果
def login_handle(request):

    request.session['uname'] = request.POST['uname']

    # request.session.set_expiry(10)

    # request.session.set_expiry(timedelta(days=5))

    # request.session.set_expiry(0)

    # request.session.set_expiry(None)

    return redirect(reverse('booktest:index'))

 

存儲session

# 使用存儲會話的方式,可使用settings.py的SESSION_ENGINE項指定
# 基於數據庫的會話:這是django默認的會話存儲方式,須要添加django.contrib.sessions到的INSTALLED_APPS設置中,
# 運行manage.py migrate在數據庫中安裝會話表,可顯示指定爲
SESSION_ENGINE='django.contrib.sessions.backends.db' # 基於緩存的會話:只存在本地內在中,若是丟失則不能找回,比數據庫的方式讀寫更快 SESSION_ENGINE='django.contrib.sessions.backends.cache' # 能夠將緩存和數據庫同時使用:優先從本地緩存中獲取,若是沒有則從數據庫中獲取 SESSION_ENGINE='django.contrib.sessions.backends.cached_db'

 

使用Redis緩存session

# 會話還支持文件、純cookie、Memcached、Redis等方式存儲,下面演# 示使用redis存儲
# 安裝包
pip install django-redis-sessions

# 修改settings中的配置,增長以下項
SESSION_ENGINE = 'redis_sessions.session'

SESSION_REDIS_HOST = 'localhost'

SESSION_REDIS_PORT = 6379

SESSION_REDIS_DB = 0

SESSION_REDIS_PASSWORD = ''

SESSION_REDIS_PREFIX = 'session'

 

管理redis的命令

  1. 啓動:sudo redis-server /etc/redis/redis.conf
  2. 中止:sudo redis-server stop
  3. 重啓:sudo redis-server restart

redis-cli:使用客戶端鏈接服務器

keys *:查看全部的鍵

get name:獲取指定鍵的值

del name:刪除指定名稱的鍵

相關文章
相關標籤/搜索