欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Django框架设置cookies与获取cookies操作详解

程序员文章站 2022-06-03 17:45:54
本文实例讲述了django框架设置cookies与获取cookies操作。分享给大家供大家参考,具体如下: 在django里面,使用cookie和session看起来好像...

本文实例讲述了django框架设置cookies与获取cookies操作。分享给大家供大家参考,具体如下:

在django里面,使用cookie和session看起来好像是一样的,使用的方式都是request.cookies[xxx]和request.session[xxx],其中xxx是您想要取得的东西的key, 很久以前,写过一篇 django怎么处理session 的文章:, 今天对cookies 进行了同样的操作:

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 取出来:

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 呢,也很简单:

value = request.cookies["cookie_key"]

同样的道理,也可以用 javascript 写 cookies,

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,如:

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配置如下:

#中间件
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:

print request.cookies
{'csrftoken': '9fbe9kh0uuzxemzwdc4z4aioozg1eaoi', 'sessionid': 'lf4dd7xjlyzrh4yvzbtltlbujy3ipp1f', 'hm_lvt_c65358e73ce306691a49ae5119f58783': '1405408338'}

登陆成功后django会自动在客户端生成一个sessionid,且这个sessionid在未注销前一直不变,当注销后就改变了该sessionid了. cookie中保存一个session的索引编号(sessionid),其重要信息都保存在服务器端,session控制.即可.

通过cookie保存的sessionid与服务器端比较,当等于时则表示用户已登陆,若不等于或两者有一方不存在或都不存在则用户处于注销状态.

二.session 与cookie

Django框架设置cookies与获取cookies操作详解

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传递回服务器。比如:

<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对象,该对象是字典形式.

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的处理

如果想让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,这点会在后面提及.

1.在views中使用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')

2.在模板中使用session

如果在views设置了session,如request.session['ms'], 那么在模板中可以通过{{ request.session.key }}的形式使用:

{{ request.session.ms }}

3.在views外使用session

从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'}
....

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回收。

思路参考:https://www.jb51.net/article/99370.htm

第三方库:django-redis-sessions,,提供了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:

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

希望本文所述对大家基于django框架的python程序设计有所帮助。