本文实例讲述了Django框架设置cookies与获取cookies操作。分享给大家供大家参考,具体如下:
在Django里面,使用Cookie和Session看起来好像是一样的,使用的方式都是request.COOKIES[XXX]和request.session[XXX],其中XXX是您想要取得的东西的key, 很久以前,写过一篇 django怎么处理session 的文章:django 自定义session 处理, 今天对cookies 进行了同样的操作:
1
2
3
4
5
6
7
8
9
10
11
12
|
from django.template import loader ,Context
from django.http import HttpResponse
def main(request):
#不用模板
response = HttpResponse( 'test' )
response.set_cookie( 'my_cookie' , 'cookie value' )
return response
def main(request):
#用模板
response = render_to_response( 'xxxx.html' , {})
response.set_cookie( 'my_cookie' , 'cookie value' )
return response
|
使用模板的情况和不使用模板的情况都做了测试, 可以向浏览器设置cookies, 在客户端可以用javascript 取出来:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
function getCookie(c_name)
{
if (document.cookie.length> 0 )
{
c_start = document.cookie.indexOf(c_name + "=" )
if (c_start! = - 1 )
{
c_start = c_start + c_name.length + 1
c_end = document.cookie.indexOf( ";" ,c_start)
if (c_end = = - 1 ) c_end = document.cookie.length
return unescape(document.cookie.substring(c_start,c_end))
}
}
return ""
}
|
用上面的javascript 函数可以取出cookies, 如果需要在django 里面取出 cookies 呢,也很简单:
1
|
value = request.COOKIES[ "cookie_key" ]
|
同样的道理,也可以用 javascript 写 cookies,
1
2
3
4
5
6
7
|
function setCookie(c_name,value,expiredays)
{
var exdate = new Date()
exdate.setDate(exdate.getDate() + expiredays)
document.cookie = c_name + "=" + escape(value) +
((expiredays = = null) ? " " : " ;expires = " + exdate.toGMTString())
}
|
上面总结了用 django 读写cookies 与 用javascript 读写cookies. 根据不同的情况, 这两种方法是经常混合在一起使用的.
一.Django authentication
django authentication 提供了一个便利的user api接口,无论在py中 request.user,参见Request and response objects.还是模板中的{{user}}都能随时随地使用,如果从web开发角度来看,其实无非就是cookie与session的运用.
在项目首页,在登陆和注销状态下分别输出所有session,如:
1
2
3
4
5
|
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配置如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
#中间件
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:
1
2
|
print request.COOKIES
{ 'csrftoken' : '9fBE9Kh0uuzXEMzWdc4z4aIOoZg1EaoI' , 'sessionid' : 'lf4dd7xjlyzrh4yvzbtltlbujy3ipp1f' , 'Hm_lvt_c65358e73ce306691a49ae5119f58783' : '1405408338' }
|
登陆成功后Django会自动在客户端生成一个sessionid,且这个sessionid在未注销前一直不变,当注销后就改变了该sessionid了. Cookie中保存一个Session的索引编号(sessionid),其重要信息都保存在服务器端,Session控制.即可.
通过Cookie保存的sessionid与服务器端比较,当等于时则表示用户已登陆,若不等于或两者有一方不存在或都不存在则用户处于注销状态.
二.Session 与Cookie
cookie机制采用的是在客户端保持状态的方案,而session机制采用的是在服务器端保持状态的方案,由于采用服务器端保持状态的方案在客户端也需要保存一个标识,所以session机制可能需要借助于cookie机制来达到保存标识的目的.
补充:关于session和cookie的区别:
二者的定义:
当你在浏览网站的时候,WEB 服务器会先送一小小资料放在你的计算机上,Cookie 会帮你在网站上所打的文字或是一些选择,
都纪录下来。当下次你再光临同一个网站,WEB 服务器会先看看有没有它上次留下的 Cookie 资料,有的话,就会依据 Cookie
里的内容来判断使用者,送出特定的网页内容给你。 Cookie 的使用很普遍,许多有提供个人化服务的网站,都是利用 Cookie
来辨认使用者,以方便送出使用者量身定做的内容,像是 Web 接口的免费 email 网站,都要用到 Cookie。
具体来说cookie机制采用的是在客户端保持状态的方案,而session机制采用的是在服务器端保持状态的方案。
同时我们也看到,由于采用服务器端保持状态的方案在客户端也需要保存一个标识,所以session机制可能需要借助于cookie机制
来达到保存标识的目的,但实际上它还有其他选择。
cookie机制。正统的cookie分发是通过扩展HTTP协议来实现的,服务器通过在HTTP的响应头中加上一行特殊的指示以提示
浏览器按照指示生成相应的cookie。然而纯粹的客户端脚本如JavaScript或者VBScript也可以生成cookie。而cookie的使用
是由浏览器按照一定的原则在后台自动发送给服务器的。浏览器检查所有存储的cookie,如果某个cookie所声明的作用范围
大于等于将要请求的资源所在的位置,则把该cookie附在请求资源的HTTP请求头上发送给服务器。
cookie的内容主要包括:名字,值,过期时间,路径和域。路径与域一起构成cookie的作用范围。若不设置过期时间,则表示这
个cookie的生命期为浏览器会话期间,关闭浏览器窗口,cookie就消失。这种生命期为浏览器会话期的cookie被称为会话cookie。
会话cookie一般不存储在硬盘上而是保存在内存里,当然这种行为并不是规范规定的。若设置了过期时间,浏览器就会把cookie
保存到硬盘上,关闭后再次打开浏览器,这些cookie仍然有效直到超过设定的过期时间。存储在硬盘上的cookie可以在不同的浏
览器进程间共享,比如两个IE窗口。而对于保存在内存里的cookie,不同的浏览器有不同的处理方式
session机制。session机制是一种服务器端的机制,服务器使用一种类似于散列表的结构(也可能就是使用散列表)来保存信息。
当程序需要为某个客户端的请求创建一个session时,服务器首先检查这个客户端的请求里是否已包含了一个session标识
(称为session id),如果已包含则说明以前已经为此客户端创建过session,服务器就按照session id把这个session检索出来
使用(检索不到,会新建一个),如果客户端请求不包含session id,则为此客户端创建一个session并且生成一个与此session相
关联的session id,session id的值应该是一个既不会重复,又不容易被找到规律以仿造的字符串,这个session id将被在本次响应
中返回给客户端保存。保存这个session id的方式可以采用cookie,这样在交互过程中浏览器可以自动的按照规则把这个标识发送给
服务器。一般这个cookie的名字都是类似于SEEESIONID。但cookie可以被人为的禁止,则必须有其他机制以便在cookie被禁止时
仍然能够把session id传递回服务器。
经常被使用的一种技术叫做URL重写,就是把session id直接附加在URL路径的后面。还有一种技术叫做表单隐藏字段。就是服务器
会自动修改表单,添加一个隐藏字段,以便在表单提交时能够把session id传递回服务器。比如:
1
2
3
4
|
< form name = "testform" action = "/xxx" >
< input type = "hidden" name = "jsessionid" value = "ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764" >
< input type = "text" >
</ form >
|
实际上这种技术可以简单的用对action应用URL重写来代替。
cookie 和session 的区别:
1、cookie数据存放在客户的浏览器上,session数据放在服务器上。
2、cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗
考虑到安全应当使用session。
3、session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能
考虑到减轻服务器性能方面,应当使用COOKIE。
4、单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie。
5、所以个人建议:
将登陆信息等重要信息存放为SESSION
其他信息如果需要保留,可以放在COOKIE中
三.Django对于Cookie的处理方式
每个HttpRequest对象都对应一个COOKIES对象,该对象是字典形式.
1
2
|
request.COOKIES[ 'sessionid' ] # 获取
request.COOKIES.get( 'sessionid' , None ) # 获取
|
对COOKIES的设置通过HttpResponse对象的set_cookie来完成,文档传送门
1
|
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的处理
如果想让django项目支持session,则必须在settings.py中指定,见上.默认情况django使用 django.contrib.sessions.models.Session将session存储在你的数据库中.,这里我们查看下,如一个多用户的网站的django_session表:
1
2
3
4
5
6
|
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,这点会在后面提及.
1.在views中使用session
每个HttpRequest对象都有session属性,那么我们可以在views中使用:
1
2
3
4
5
6
|
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过期时间
1
2
3
4
5
6
7
8
9
|
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' )
|
2.在模板中使用session
如果在views设置了session,如request.session['ms'], 那么在模板中可以通过{{ request.session.key }}的形式使用:
1
|
{{ request.session.ms }}
|
3.在views外使用session
从mysql检索出来的django_session表来看,包含字段如下:
1
2
3
4
5
6
7
8
9
|
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数据,如下:
1
2
3
4
5
6
7
8
9
10
11
|
>>> 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' }
....
|
4.其他细节
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之存取Redis Django实现
session可以在数据库级别,缓存级别,文件级别,cookie级别基础上存取,对于缓存级别而言无疑是最提升性能的,我们可以放在django缓存系统中,也可以在memcache中,也可以在Redis中. 这里比较推荐Redis.我们完全可以用Redis实现Session功能.
1.我们知道session其实是在cookie中保存了一个sessionid,用户每次访问都将sessionid发给服务器,服务器通过ID查找用户对应的状态数据。在这里我的处理方式也是在cookie中定义一个sessionid,程序需要取得用户状态时将sessionid做为key在Redis中查找。
2.同时session支持用户在一定时间不访问将session回收。
思路参考:http://www.zzvips.com/article/25071.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.安装&配置
(1).首先安装配置django-redis-sessions:
1
|
pip install django - redis - sessions
|
在settings.py中设置SESSION_ENGINE,它默认是: django.contrib.sessions.backends.db 这里设置如下:
1
|
SESSION_ENGINE = 'redis_sessions.session'
|
然后在settings.py中设置Redis数据库信息:
1
2
3
4
5
6
7
|
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
1
|
pip install django - redis - cache
|
然后在settings.py配置CACHES
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
#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连接:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
#这里是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中.如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
# 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中修改,如下:
1
2
|
unixsocket /var/run/redis/redis .sock
unixsocketperm 777
|
记住配置完成之后要重启Redis服务:
1
|
$ sudo service redis-server restart
|
希望本文所述对大家基于Django框架的Python程序设计有所帮助。
原文链接:https://www.cnblogs.com/skying555/p/4964112.html