Qingquan-Li / blog

My Blog
https://Qingquan-Li.github.io/blog/
132 stars 16 forks source link

Django Cookies and Session #165

Open Qingquan-Li opened 3 years ago

Qingquan-Li commented 3 years ago

参考:📖 Django文档-如何使用会话:https://docs.djangoproject.com/zh-hans/3.1/topics/http/sessions/


一、Django操作Cookies

参考:🎬Day69-05 django操作cookie:https://www.bilibili.com/video/BV1Sp4y1U7Jr?p=792 第13分钟

简单需求:简易管理员登录表单,需要获取Cookies(登录状态)后才能访问管理后台页面,直接访问管理后台页面URL(没有获得Cookies)无效并自动跳转回登录页面:

def login(request):
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')
        if username == 'root' and password == 'root123':
            # return redirect('/admin/')
            # 保存用户登录状态:
            obj = redirect('/admin/')
            # 让浏览器记录Cookies数据。设置过期时间为3秒(可选),expires参数针对IE浏览器起作用
            obj.set_cookie('is_allow_to_next_page', 'true', max_age=3, expires=3)
            # 跳转到一个需要管理员登录后,才能看到的页面
            return obj
    return render(request, 'login.html')

def admin(request):
    # 获取cookie信息(从登录页面保存过来的)
    if request.COOKIES.get('username') == 'root':
        return HttpResponse('这是admin页面,只有登录的用户才能查看')
    return redirect('/login/')




二、Django操作Session

参考:📖如何使用会话:https://docs.djangoproject.com/zh-hans/3.1/topics/http/sessions/

参考:🎬Day69-06 session操作:https://www.bilibili.com/video/BV1Sp4y1U7Jr?p=793

2.1 设置Session

def set_session(request):
    """ `requset.session['key'] = value` 这行代码的作用:
    1. Django内部自动生成一个随机字符串(django_session表中的session_key,浏览器Cookies中sessionid对应的Value)
    2. Django内部自动将随机字符串(session_key)和对应的数据存储到django_session表中
        2.1. 先在内存中产生操作数据库的缓存
        2.2 在响应经过Django中间件(django.contrib.sessions.middleware.SessionMiddleware)的时候,才真正操作数据库
    3. 将(服务器)产生的随机字符串(session_key)返回给(客户端)浏览器保存(Cookies中sessionid对应的Value)
    """
    request.session['hobby'] = 'coding'
    return HttpResponse('设置Session成功!')

def get_sesssion(request):
    """ `request.session.get('key')` 这行代码的作用:
    1. 自动从浏览器请求中获取sessionid对应的随机字符串
    2. 拿着该随机字符串去django_session表中查找对应的数据(存储在django_session表中的session_data:包含编码encode和序列化会话字典的字符串)
    3. 如果查找到对应的数据(session_data),则将对应的数据取出,并以字典的形式封装到request.session中;如果查找不到对应的数据,则request.session.get('key')返回None
    """
    print(request.session.get('hobby'))
    return HttpResponse('获取Session成功!')



2.2 django_session表中,一个浏览器只会有一条对应的(未过期)session记录

在同一台计算机上的同一个浏览器上操作,即使设置了多个 session 键值对,例如:

def set_session(request):
    request.session['hobby'] = 'coding'
    requset.session['hobby02'] = 'basketball'
    requset.session['hobby03'] = 'travel'
    return HttpResponse('设置Session成功!')

django_session 表中只会有一条对应的记录,而不会产生多条记录对应同一个浏览器(除非对应该浏览器的session记录过期了,会重新生成一条新的记录对应同一个浏览器)。

⚠️ 注意:假设此时 django_session 表中因为用户登录而产生了一条 session 记录,此时执行以上代码新增了 3 个 session 数据: django_session 表的这条记录中的 session_key 字段(对应浏览器 Cookies 中 sessionid 的值)不会改变,但是这条记录中 session_data (包含编码encode和序列化会话字典的字符串)字段将会发生更新



2.3 设置Session过期时间

Django 默认的 Session 过期时间是 14 天。

2.3.1 在settings.py中设置Session过期时间

# 设置每次请求都保存Session(更新django_session表记录中的的expire_date),默认值为False。
# 参考:https://docs.djangoproject.com/zh-hans/3.1/topics/http/sessions/#when-sessions-are-saved
SESSION_SAVE_EVERY_REQUEST = True
# 设置session过期时间(默认登录状态过期失效为14天)
# 参考:https://docs.djangoproject.com/zh-hans/3.1/topics/http/sessions/#browser-length-sessions-vs-persistent-sessions
# SESSION_COOKIE_AGE = 1209600  # 1209600 seconds(2 weeks)
SESSION_COOKIE_AGE = 60*60*24*365  # 365 days, refer to instagram.com

2.3.2 在视图函数中设置Session过期时间

参考:https://docs.djangoproject.com/zh-hans/3.1/topics/http/sessions/#django.contrib.sessions.backends.base.SessionBase.set_expiry

def set_session(request):
    """ `request.session.set_expiry()` 括号内可以放4种类型的参数:
    1. 整数:多少秒后过期失效
    2. 日期对象:到指定日期就过期失效
    3. 0:当前浏览器关闭后就过期失效
    4. 不写:使用Django默认的session过期失效时间(14天)
    """
    # 设置session过期时间为10秒
    # 此时访问该视图,settings.py中设置的SESSION_COOKIE_AGE配置将会无效。
    # 此时不是访问该视图(如访问Django默认的登录视图),session过期时间则为SESSION_COOKIE_AGE配置的值。
    # 如果访问了Django默认的登录视图后,再访问该视图,并且此时session未过期,django_session表中expire_date的值将由SESSION_COOKIE_AGE配置的值更新为该视图设置的10秒后过期。如果此时session记录已经过期,则会新增一条session记录。
    request.session.set_expiry(10)
    request.session['hobby'] = 'coding'
    return HttpResponse('设置Session成功!')

def get_session(request):
    if request.session.get('hobby'):
        print(request.session.get('hobby'))
        return HttpResponse('获取Session成功!')
    return HttpResponse('获取Session(hobby的值)失败!')



2.4 删除session记录

参考:📖 flush():https://docs.djangoproject.com/zh-hans/3.1/topics/http/sessions/#django.contrib.sessions.backends.base.SessionBase.flush

参考:📖 clearsessions:https://docs.djangoproject.com/zh-hans/3.1/topics/http/sessions/#clearing-the-session-store

flush():

request.session.flush() :删除当前会话和会话cookie,即服务器 django_session 表和客户的浏览器的Cookies 中的 sessionid 记录。如果你想确保早先的会话数据不能被用户的浏览器再次访问时,可以使用这个方法(比如,django.contrib.auth.logout() 函数调用它)。

也就是说,用户 logout ,会删除django_session中对应的(未过期的)记录。

clearsessions:

但是,Django 没有提供过期会话自动清除的功能。也就是说,如果 django_session 表中对应的记录已经过期,此时即使用户 logout,也无法删除该记录了。

因此,你需要定期清除过期会话。Django 提供了一个清除管理命令:clearsessions 。推荐在定期清除时使用该命令,例如在日常的定时任务中。或命令行中手动执行:$ python manage.py clearsessions