• Django 设置cookies与获取cookies.


    在Django里面,使用Cookie和Session看起来好像是一样的,使用的方式都是request.COOKIES[XXX]和request.session[XXX],其中XXX是您想要取得的东西的key, 很久以前,写过一篇 django怎么处理session 的文章: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

    图片来源:http://blog.csdn.net/tzjly/article/details/6986268

    cookie机制采用的是在客户端保持状态的方案,而session机制采用的是在服务器端保持状态的方案,由于采用服务器端保持状态的方案在客户端也需要保存一个标识,所以session机制可能需要借助于cookie机制来达到保存标识的目的.

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

    思路参考: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.安装&配置

    (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
  • 相关阅读:
    Android studio ocr初级app开发问题汇总(含工程代码)
    面试题思路,25匹马 5个跑道取前三,前五,最少比赛次数--七次
    中国计算机学会推荐国际学术会议和期刊目录(CCF)2019年
    swift 数组部分排序
    SceneKit下关于修改SCNNode 的Shader展示自定义图形
    汇编语言实现字母下落效果
    组合数计算-java
    miniblast_hash算法c语言实现
    日常开发知识点备忘
    骑士周游问题跳马问题C#实现(附带WPF工程代码)
  • 原文地址:https://www.cnblogs.com/skying555/p/4964112.html
Copyright © 2020-2023  润新知