在Django裏面,使用Cookie和Session看起來好像是同樣的,使用的方式都是request.COOKIES[XXX]和request.session[XXX],其中XXX是您想要取得的東西的key, 好久之前,寫過一篇 django怎麼處理session 的文章:django 自定義session 處理, 今天對cookies 進行了一樣的操做:javascript
使用模板的狀況和不使用模板的狀況都作了測試, 能夠向瀏覽器設置cookies, 在客戶端能夠用javascript 取出來:html
用上面的javascript 函數能夠取出cookies, 若是須要在django 裏面取出 cookies 呢,也很簡單:java
一樣的道理,也能夠用 javascript 寫 cookies,python
上面總結了用 django 讀寫cookies 與 用javascript 讀寫cookies. 根據不一樣的狀況, 這兩種方法是常常混合在一塊兒使用的.mysql
django authentication提供了一個便利的user api接口,不管在py中 request.user
,參見Request and response objects.仍是模板中的{{user}}
都能隨時隨地使用,若是從web開發角度來看,其實無非就是cookie與session的運用.nginx
在項目首頁,在登錄和註銷狀態下分別輸出全部session,如:git
print request.session.items() # 登錄狀態下輸出 [('domain', 'http://beginman.sinaapp.com'), ('_auth_user_backend', 'django.contrib.auth.backends.ModelBackend'), ('_auth_user_id', 1L)] # 註銷狀態下輸出 [('domain', 'http://beginman.sinaapp.com')]
從輸出結果中可知曉,若是項目中settings.py配置以下:github
#中間件 MIDDLEWARE_CLASSES = ( 'django.middleware.common.CommonMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', #看這裏 # 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', #看這裏 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.gzip.GZipMiddleware', # 處理gzip壓縮,減輕服務器壓力 'pagination.middleware.PaginationMiddleware', # django 第三方分頁 'common.mymiddleware.Mymiddleware', # Uncomment the next line for simple clickjacking protection: # 'django.middleware.clickjacking.XFrameOptionsMiddleware', ) #TEMPLATE_CONTEXT_PROCESSORS # 注意django1.5的這個玩意兒與低版本的不一樣 # 參考:https://docs.djangoproject.com/en/1.3/ref/settings/#std:setting-TEMPLATE_CONTEXT_PROCESSORS TEMPLATE_CONTEXT_PROCESSORS = ( "django.contrib.auth.context_processors.auth", "django.core.context_processors.debug", "django.core.context_processors.i18n", "django.core.context_processors.media", "django.core.context_processors.static", "django.core.context_processors.request", "django.contrib.messages.context_processors.messages" ) INSTALLED_APPS = ( 'django.contrib.auth', #this 'django.contrib.contenttypes', #this 'django.contrib.sessions', #this 'django.contrib.sites', 'django.contrib.messages', 'django.contrib.staticfiles', # Uncomment the next line to enable the admin: 'django.contrib.admin', # Uncomment the next line to enable admin documentation: # 'django.contrib.admindocs', 'mysite', )
那麼就會有這樣的輸出,固然這只是針對單用戶(這裏拿個人博客開刀).在登錄後同時在首頁輸出cookies:web
print request.COOKIES {'csrftoken': '9fBE9Kh0uuzXEMzWdc4z4aIOoZg1EaoI', 'sessionid': 'lf4dd7xjlyzrh4yvzbtltlbujy3ipp1f', 'Hm_lvt_c65358e73ce306691a49ae5119f58783': '1405408338'}
登錄成功後Django會自動在客戶端生成一個sessionid,且這個sessionid在未註銷前一直不變,當註銷後就改變了該sessionid了. Cookie中保存一個Session的索引編號(sessionid),其重要信息都保存在服務器端,Session控制.便可.redis
經過Cookie保存的sessionid與服務器端比較,當等於時則表示用戶已登錄,若不等於或二者有一方不存在或都不存在則用戶處於註銷狀態.
圖片來源:http://blog.csdn.net/tzjly/article/details/6986268
cookie機制採用的是在客戶端保持狀態的方案,而session機制採用的是在服務器端保持狀態的方案,因爲採用服務器端保持狀態的方案在客戶端也須要保存一個標識,因此session機制可能須要藉助於cookie機制來達到保存標識的目的.
關於session和cookie,這裏有篇文章說的很清楚,傳送門.
每一個HttpRequest
對象都對應一個COOKIES
對象,該對象是字典形式.
request.COOKIES['sessionid'] # 獲取 request.COOKIES.get('sessionid', None) # 獲取
對COOKIES的設置經過HttpResponse
對象的set_cookie
來完成,文檔傳送門
HttpResponse.set_cookie(key, value='', max_age=None, expires=None, path='/', domain=None, secure=None, httponly=False)
參數以下:
(1).`max_age默認:None ,cookie須要延續的時間(以秒爲單位) 若是參數是\
None`` ,這個cookie會延續到瀏覽器關閉爲止。
(2).`expires默認None ,cookie失效的實際日期/時間。 它的格式必須是:\
"Wdy, DD-Mth-YY HH:MM:SS GMT"。若是給出了這個參數,它會覆蓋\
max_age`` 參數。
(3).path
默認是"/"
,cookie生效的路徑前綴。 瀏覽器只會把cookie回傳給帶有該路徑的頁 面,這樣你能夠避免將cookie傳給站點中的其餘的應用,當你不是控制你的站點的頂層時,這樣作是特別有用的。
(4).domain
默認None,這個cookie有效的站點。 你可使用這個參數設置一個跨站點(cross-domain)的cookie。 好比,\ domain=".example.com"
能夠設置一個在\ www.example.com
、\ www2.example.com
以及\ an.other.sub.domain.example.com
站點下均可讀到的cookie。
若是這個參數被設成\ None
,cookie將只能在設置它的站點下能夠讀到。
(5).False
默認False ,若是設置爲 True ,瀏覽器將經過HTTPS來回傳cookie。
文檔傳送門,
若是想讓django項目支持session,則必須在settings.py中指定,見上.默認狀況django使用 django.contrib.sessions.models.Session將session存儲在你的數據庫中.,這裏咱們查看下,如一個多用戶的網站的django_session表:
mysql> select * from django_session;
+----------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------+
| session_key | session_data | expire_date |
+----------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------+
| 1x5fxr1upboyiw4ny640tgdl2mto6i6i | NjJkNzBiYjE2NjBlYTBkMGZmY2QzYmIxOGE5MDRmNTE1YTgzM2FmNzqAAn1xAS4= | 2014-07-16 02:21:35 | ..................
很長一大段,這裏省略了.若是在settings.py的 INSTALLED_APPS中添加了django.contrib.sessions
則運行manage.py syncdb
將會生成數據庫級別的session,表名爲django-session.
爲了提高性能,咱們可使用緩存級別的session,這點會在後面說起.
每一個HttpRequest對象都有session屬性,那麼咱們能夠在views中使用:
fav_color = request.session['fav_color'] #get request.session['fav_color'] = 'blue' #set del request.session['fav_color'] #del 'fav_color' in request.session #contains fav_color = request.session.get('fav_color', 'red') fav_color = request.session.pop('fav_color') # pop
session對象字典形式,有keys(),items(),setdefault(),clear()等方法,如下方法是經常使用的:
(1).flush()
從session中刪除數據,而後再生數據,好比django的logout()函數就會調用它.
(2).set_test_cookie()
設置一個test cookie來判斷用戶瀏覽器是否接受cookie.
(3).test_cookie_worked()
當設置了test cookie後返回True或Flase判斷用戶瀏覽器是否接受cookie.因此要先執行set_test_cookie()
來下個套.
(4).delete_test_cookie()
刪除test cookie,測試完成後要收回本身下的套.
(5).set_expiry(value)
設置過時時間,若是value是整數則表示N秒後過時,若是是時間或時間戳對象則表示指定到某一時間過時;若是value是0則在瀏覽器關閉後過時(會話session); 若是value 是None則使用全局session過時策略.
(6).get_expiry_age()
返回session過時時間
def login(request): if request.method == 'POST': if request.session.test_cookie_worked(): # 測套 request.session.delete_test_cookie() # 收套 return HttpResponse("You're logged in.") else: return HttpResponse("Please enable cookies and try again.") request.session.set_test_cookie() # 下套 return render_to_response('foo/login_form.html')
若是在views設置了session,如request.session['ms']
, 那麼在模板中能夠經過{{ request.session.key }}
的形式使用:
{{ request.session.ms }}
從mysql檢索出來的django_session表來看,包含字段以下:
mysql> describe django_session;
+--------------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------------+-------------+------+-----+---------+-------+
| session_key | varchar(40) | NO | PRI | NULL | | | session_data | longtext | NO | | NULL | | | expire_date | datetime | NO | MUL | NULL | | +--------------+-------------+------+-----+---------+-------+ 3 rows in set (0.01 sec)
那麼可使用django 數據庫API來訪問session,注意使用get_decoded() 來讀取實際的session數據,以下:
>>> from django.contrib.sessions.models import Session >>> s=Session.objects.all() >>> s [<Session: Session object>, <Session: Session object>, <Session: Session object>, <Session: Session object>, <Session: Session object>,....] >>> for i in s: ... print i.get_decoded() ... {'domain': 'http://beginman.sinaapp.com'} {'domain': 'http://beginman.sinaapp.com', '_auth_user_backend': 'django.contrib.auth.backends.ModelBackend', '_auth_user_id': 1L} {'domain': 'http://beginman.sinaapp.com'} ....
ession 字典接受任何支持序列化的Python對象。 參考Python內建模塊pickle的文檔以獲取更多信息。
Session 數據存在數據庫表 django_session 中
Session 數據在須要的時候纔會讀取。 若是你從不使用 request.session , Django不會動相關數據庫表的一根毛。11
Django 只在須要的時候才送出cookie。 若是你壓根兒就沒有設置任何會話數據,它不會 送出會話cookie(除非 SESSION_SAVE_EVERY_REQUEST 設置爲 True )。
Django session 框架徹底並且只能基於cookie。 它不會後退到把會話ID編碼在URL中(像某些工具(PHP,JSP)那樣)。
這是一個有意而爲之的設計。 把session放在URL中不僅是難看,更重要的是這讓你的站點 很容易受到攻擊——經過 Referer header進行session ID」竊聽」而實施的攻擊。
session能夠在數據庫級別,緩存級別,文件級別,cookie級別基礎上存取,對於緩存級別而言無疑是最提高性能的,咱們能夠放在django緩存系統中,也能夠在memcache中,也能夠在Redis中. 這裏比較推薦Redis.咱們徹底能夠用Redis實現Session功能.
1.咱們知道session實際上是在cookie中保存了一個sessionid,用戶每次訪問都將sessionid發給服務器,服務器經過ID查找用戶對應的狀態數據。在這裏個人處理方式也是在cookie中定義一個sessionid,程序須要取得用戶狀態時將sessionid作爲key在Redis中查找。
2.同時session支持用戶在必定時間不訪問將session回收。
思路參考:http://www.cnblogs.com/ddyq/p/3151284.html
第三方庫:django-redis-sessions
,github地址,提供了Redis database backend for your sessions. 另外一個第三方庫Redis Django Cache Backend ,A cache backend for Django using the Redis datastructure server.用Redis存儲緩存數據.
對此咱們能夠應用到本身的項目中,如上篇Redis key的設計模式 & django登錄 提到的實例,那麼接下來咱們在此基礎上實現session,cookie,Redis定製的用戶系統.
注意要實現配置好Redis服務.
(1).首先安裝配置django-redis-sessions:
pip install django-redis-sessions
在settings.py中設置SESSION_ENGINE
,它默認是: django.contrib.sessions.backends.db 這裏設置以下:
SESSION_ENGINE = 'redis_sessions.session'
而後在settings.py中設置Redis數據庫信息:
SESSION_REDIS_HOST = 'localhost' SESSION_REDIS_PORT = 6379 SESSION_REDIS_DB = 0 SESSION_REDIS_PASSWORD = 'password' SESSION_REDIS_PREFIX = 'session' # If you prefer domain socket connection, you can just add this line instead of SESSION_REDIS_HOST and SESSION_REDIS_PORT. SESSION_REDIS_UNIX_DOMAIN_SOCKET_PATH = '/var/run/redis/redis.sock'
配置完成後可測試以下:
$ pip install django nose redis
# Make sure you have redis running on localhost:6379 (poem)[beginman@beginman poem]$ nosetests ---------------------------------------------------------------------- Ran 0 tests in 0.001s OK
(2).安裝配置django-redis-cache
pip install django-redis-cache
而後在settings.py配置CACHES
#On Django < 1.3:
CACHE_BACKEND = 'redis_cache.cache://:'
#On Django >= 1.3: # When using TCP connections CACHES = { 'default': { 'BACKEND': 'redis_cache.RedisCache', 'LOCATION': '<host>:<port>', 'OPTIONS': { 'DB': 1, 'PASSWORD': 'yadayada', 'PARSER_CLASS': 'redis.connection.HiredisParser', 'CONNECTION_POOL_CLASS': 'redis.BlockingConnectionPool', 'CONNECTION_POOL_CLASS_KWARGS': { 'max_connections': 50, 'timeout': 20, } }, }, } # When using unix domain sockets # Note: ``LOCATION`` needs to be the same as the ``unixsocket`` setting # in your redis.conf CACHES = { 'default': { 'BACKEND': 'redis_cache.RedisCache', 'LOCATION': '/path/to/socket/file', 'OPTIONS': { 'DB': 1, 'PASSWORD': 'yadayada', 'PARSER_CLASS': 'redis.connection.HiredisParser' }, }, } MIDDLEWARE_CLASSES = ( 'django.middleware.cache.UpdateCacheMiddleware', # This must be first on the list 'django.middleware.common.CommonMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', (...) 'django.middleware.cache.FetchFromCacheMiddleware', # This must be last
注意關於TCP鏈接:
#這裏是TCP鏈接 CACHES = { 'default': { 'BACKEND': 'redis_cache.RedisCache', 'LOCATION': '127.0.0.1:6379', 'OPTIONS': { 'DB': 0, 'PASSWORD': '', # 這裏沒有設置密碼 # 'PARSER_CLASS': 'redis.connection.HiredisParser', # 這段可先註釋掉不然出現 :Hiredis is not installed的錯誤 'CONNECTION_POOL_CLASS': 'redis.BlockingConnectionPool', 'CONNECTION_POOL_CLASS_KWARGS': { 'max_connections': 50, 'timeout': 20, } }, }, }
至此咱們的Redis For Django算是完成了,若是不太明白,還有一篇文章Using Redis as Django's session store and cache backend能夠借鑑.
接下來咱們能夠在django中使用cache,存儲在Redis中.以下:
# Start by importing your default cache: from django.core.cache import cache # Store data under a-unique-key: cache.set('a-unique-key', 'this is a string which will be cached') # Later on you can retrieve it in another function: cache.get('a-unique-key') # Will return None if key is not found in cache # You can specify a default value: cache.get('another-unique-key', 'default value') # You can store multiple values at once: cache.set_many({'a': 1, 'b': 2, 'c': 3}) # And fetch multiple values: cache.get_many(['a', 'b', 'c']) # returns {'a': 1, 'b': 2, 'c': 3} # You can store complex types in the cache: cache.set('a-unique-key', { 'string' : 'this is a string', 'int' : 42, 'list' : [1, 2, 3, 4], 'tuple' : (1, 2, 3, 4), 'dict' : {'A': 1, 'B' : 2}, })
若是咱們選擇socket鏈接方式而非TCP,那麼在運行中可能會出現以下錯誤:Error 2 connecting to unix socket: /var/run/redis/redis.sock. No such file or directory.
這是由於redis 默認沒有開啓unix socket,須要在/etc/redis/redis.conf中修改,以下:
unixsocket /var/run/redis/redis.sock unixsocketperm 777
記住配置完成以後要重啓Redis服務:
$ sudo service redis-server restart