Django中的session是一個高級工具,它可以讓用户存儲個人信息以便在下次訪問網站中使用這些信息。session的基礎還是cookie,但是它提供了一些更加高級的功能。請看下面的一個例子:

使用session:

這個例子中實現了一個簡單的計數功能:

def test_count_session(request):
    if 'count' in request.session:
        request.session['count'] += 1
        return HttpResponse('new count=%s' % request.session['count'])
    else:
        request.session['count'] = 1
        return HttpResponse('No count in session. Setting to 1')

比較session和cookie的使用我們可以發現他們有一下幾點不同:

  • session管理更加統一和方便:每個session中的屬性值可以使用查詢以及修改操作。
  • 雖然我們在例子中只是使用了一個整數的屬性,但實際上session中還可以包含很多類型的屬性,比如字典屬性,並且它可以很方便地用Python中的內建方法訪問它們。

雖然我們在session中設置了一個計數器count,但是如果我們抓取當前的cookie時會發現,竟然沒有count這個屬性!而只是設置了一個看起來似乎是唯一標識的sesionid,這當然是處於安全方面的考慮。假定用户不停地訪問一個頁面,比如訪問了10次,那我們是不是就要對他的計數器+10次呢?顯然這樣做不符合實際情況,有了這個sessionid,我們就可以判斷是否是同一個用户訪問一個頁面了。

Set-Cookie:sessionid=a92d67e44a9b92d7dafca67e507985c0;
           expires=Thu, 07-Jul-2011 04:16:28 GMT;
           Max-Age=1209600;
           Path=/

深入瞭解sessionid:

默認情況下,Django會將session保存在django_session這個表中:

CREATE TABLE "django_session" (
    "session_key" varchar(40) NOT NULL PRIMARY KEY,
    "session_data" text NOT NULL,
    "expire_date" datetime NOT NULL
);

其中的session_key就相當於cookie中保存的sessionid,而session_data就包含了當前session中的屬性。如果想詳細看看我們上面創建的session的信息,可以像下面這樣:

from django.contrib.sessions.models import Session
#...
sess = Session.objects.get(pk='a92d67e44a9b92d7dafca67e507985c0')
print(sess.session_data)
print(sess.get_decoded()) 

 它或許會輸出類似下面的信息:

ZmEyNDVhNTBhMTk2ZmRjNzVlYzQ4NTFjZDk2Y2UwODc3YmVjNWVjZjqAAn1xAVUFY291bnRxAksG
cy4=

{'count': 11}

Django會保存request.session的相關信息到數據庫,然後用户可以通過cookie中的sessionid對它進行各種操作。當然這些操作我們可以通過Django自帶的session模塊輕鬆操作,從而簡化了程序員的工作。下面我們來詳細瞭解一下Django中的session。

session中間件:

首先看看Django中的django.http.HttpRequest,瞭解一下它是如何取得session並對其屬性進行操作的。the Django Book中對它有詳細的介紹,我們這裏就簡單的説一下原理吧 ! Django中的頁面請求的簡單模型就像下面這樣:

視圖方法接受一個httprequest後,對它進行一系列的操作,然後返回一個httpresponse。而中間件增加一些額外的操作:

Django的中間件框架就是一些所謂的hook類,它設置在Django項目中的settings中的MIDDLEWARE_CLASSES內。當然您也可以添加自己的MIDDLEWARE_CLASSES。默認情況下,django.contrib.sessions.middleware.SessionMiddleware 是自動添加的。查看它的源代碼,我們可以發現它實際上就是實現了2個hooks:process_request和process_response。

process_request提取當前cookie中的session KEY(也就是sessionid),其中SESSION_COOKIE_NAME就是我們説的sessionid。而request.session則包含了"session store"對象。

process_response負責保存"session store"對象並將它返回給客户端。

session的存儲:

Django中可以通過設置SESSION_ENGINE屬性來指定後台引擎來處理session。默認是django.contrib.sessions.backends.db。在Django安裝目錄中的sessions/backends下可以找到很多其他的引擎,這裏就不再贅述。

不管是哪一種引擎,它都實現了一個StorageSession類,其中包含了對session的各種操作方法。

為了理解它的工作原理,假定用户想訪問request.session,來看看它的工作流程:

  1. Session中間件的process_request實例化一個request.session,並將db.SessionStore附帶session_key保存到構造函數(姑且這麼叫吧,實在想不到好聽的名字)。
  2. SessionStore的構造函數會保存session key以便用户訪問。
  3. process_request的工作就算完成了,接着session中間件會將request傳給view方法。
  4. SessionBase是一個類字典實例,我們可以通過Python內建的字典方法對它進行操作,例如__getitem__。它還有一個很有用的方法:_get_session(它用到了load方法,load方法是由db.SessionStore來執行的,而不是SessionBase,期間還有一些對數據的編碼工作)

下面來看一個簡單的例子:

def encode(self, session_dict):
    "Returns the given session dictionary pickled and encoded as a string."
    pickled = pickle.dumps(session_dict, pickle.HIGHEST_PROTOCOL)
    hash = self._hash(pickled)
    return base64.encodestring(hash + ":" + pickled)

結論:

Django基於最簡單的HTTP request和HTTP response而實現session的使用。希望上面的一些東西能給您帶來一些靈感,如果需要詳細瞭解session,讀者可以當django官網的session文檔中去找。