Bootstrap

Django项目中的session存储

参考Django项目中的session存储

一、启用Session

Django项目默认启用Session。

可以在settings.py文件中查看,如图所示
在这里插入图片描述
如需禁用session,将上图中的session中间件注释掉即可。

二、 存储方式

在settings.py文件中,可以设置session数据的存储方式,可以保存在数据库、本地缓存等。

1、存在在默认数据库中

默认存储在数据库中,如下设置可以写,也可以不写,这是默认存储方式。

SESSION_ENGINE='django.contrib.sessions.backends.db'

django.contrib.sessions.backends.db会使用DATABASES 设置的数据库,例如

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',  # 连接数据库的类型
        'NAME': 'luckybaseline',  # 数据库名
        'HOST': '127.0.0.1',  # 数据库主机
        'PORT': 3306,
        "USER": 'root',
        'PASSWORD': '123456',
    }
}

数据库中会创建django_session这个表
在这里插入图片描述
表结构如下,包括三个数据:键,值,过期时间
在这里插入图片描述

2、本地缓存

存储在本机内存中,如果丢失则不能找回,比数据库的方式读写更快。

SESSION_ENGINE='django.contrib.sessions.backends.cache'

3 混合存储

优先从缓存中存取,如果没有则从数据库中存取。

SESSION_ENGINE='django.contrib.sessions.backends.cached_db'

4、redis 缓存

在settings.py文件中SESSION_ENGINE开启缓存,并设置CACHES地址为redis

SESSION_ENGINE = "django.contrib.sessions.backends.cache"
CACHES = {
    "default": {
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": "redis://127.0.0.1:6379/1",
        "OPTIONS": {
            "CLIENT_CLASS": "django_redis.client.DefaultClient",
        }
    }
}
SESSION_CACHE_ALIAS = "default"

三、Session操作

通过HttpRequest对象的session属性进行会话的读写操作。

1、以键值对的格式写session。

request.session['键']=

2、根据键读取值。

request.session.get('键',默认值)

3、清除所有session,在存储中删除值部分。

request.session.clear()

4、清除session数据,在存储中删除session的整条数据。

request.session.flush()

5、删除session中的指定键及值,在存储中只删除某个键及对应的值。

del request.session['键']

6、设置session的有效期

request.session.set_expiry(value)
  • 如果value是一个整数,session将在value秒没有活动后过期。
  • 如果value为0,那么用户session的Cookie将在用户的浏览器关闭时过期。
  • 如果value为None,那么session有效期将采用系统默认值,默认为两周,可以通过在settings.py中设置SESSION_COOKIE_AGE来设置全局默认值。
# COOKIE过期时间设为30天
SESSION_COOKIE_AGE = 60 * 60 * 24 * 30

四、实践

1、缓存设置,我这里使用混合存储优先从redis中取

SESSION_ENGINE = "django.contrib.sessions.backends.cache"
CACHES = {
    "default": {
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": "redis://127.0.0.1:6379/1",
        "OPTIONS": {
            "CLIENT_CLASS": "django_redis.client.DefaultClient",
        }
    }
}
SESSION_CACHE_ALIAS = "default"

2、用户登录创建session

首先访问登陆的接口,使用session的前提是用户有进行登陆,接口里调用django的login函数会为用户创建session。这里登陆接口不再描述。

# 如果认证成功,判断user表中是否存在该用户
user = User.objects.filter(username=email)
# 如果用户存在,则设置session
if user.exists():
   login(request, user[0])

查看redis中有为用户创建key
在这里插入图片描述
查看mysql中django_session表中为用户创建了一条新的记录
在这里插入图片描述
说明设置混合存储后,session会同时写到redis和mysql中。

3、用户登出注销session

登出调用django的logout函数

    #登陆示例
    def post(self,request):
        username= request.user.username
        #print(username)
        logout(request)
        return Response({"message":"退出成功","username":username},status=status.HTTP_200_OK)

查看redis,刚才那个key已经没了
在这里插入图片描述
查看mysql,刚才那条记录也没了
在这里插入图片描述
说明设置混合存储后,session删除会同时到redis和mysql中删除。

4、自定义session内容

定义get post delete三个接口来定义session

class TestSessionAPIView(APIView):
    def get(self,request):
        print(request.session.get("testsession"))
        return Response(request.session.get("testsession"))
    def post(self,request):
        request.session['testsession']="23333"
        return Response("post test interface")
    def delete(self,request):
        del request.session["testsession"]
        return Response("delete test interface")

首先请求post接口,创建session的testsession这个key值
在这里插入图片描述
然后请求get接口,获取session的key值
在这里插入图片描述

然后调用delete接口,删除刚才创建的key值
在这里插入图片描述
再获取就获取不到了
在这里插入图片描述

五、存储优先级测试

1、登陆并创建key

首先进行登陆生成用户的session,然后调用上面的post接口创建testsession这个key,这个时候redis和mysql中都有存储session。
在这里插入图片描述

在这里插入图片描述

2、将redis中该用户的session删除

127.0.0.1:6379> key *
(error) ERR unknown command `key`, with args beginning with: `*`, 
127.0.0.1:6379> keys *
1) "_kombu.binding.celeryev"
2) "_kombu.binding.default"
3) ":1:django.contrib.sessions.cacheavh5lzcneh0ydg5k97lsqykfpn90oaoy"
4) "_kombu.binding.celery"
5) "_kombu.binding.app_task1"
6) ":1:django.contrib.sessions.cached_dbp6i3ex1tgup92m8tdwptvvhuaq22stlb"
7) "_kombu.binding.app_task2"
8) "_kombu.binding.celery.pidbox"
127.0.0.1:6379> del :1:django.contrib.sessions.cached_dbp6i3ex1tgup92m8tdwptvvhuaq22stlb
(integer) 1
127.0.0.1:6379> get :1:django.contrib.sessions.cached_dbp6i3ex1tgup92m8tdwptvvhuaq22stlb
(nil)

在这里插入图片描述

然后再访问get接口,获取testsession这个key值,可以获取到,并且redis中的session数据又重新生成了。
说明当redis缓存中没有session时,会到mysql中获取,如果获取到了,还会将session重新写入到redis缓存中。
在这里插入图片描述
在这里插入图片描述

3、将mysql中session删除

现在先将mysql中的session删除
在这里插入图片描述
然后调用get获取key值,可以获取到
在这里插入图片描述
但是查看mysql中的session信息并没有重新写入,说明是先读取的redis缓存中的session信息,如果读取到了则直接返回,不会再去验证mysql中的。
在这里插入图片描述

然后再调用post接口设置key,报错了,查看后台报错,提示用户请求的session已经被删除了,这个用户可能已经登出了。
在这里插入图片描述
而查看redis中的数据并没有变化,说明在写入是可能是先写入到mysql,再写入redis缓存,如果mysql报错了则直接返回了,不会再写入redis。
在这里插入图片描述

综上所述,使用混合缓存是,mysql中的数据是很重要的,如果删除或损坏了,session可能就无法恢复了

;