提交 e18721d8 编写于 作者: 骆昊的技术专栏's avatar 骆昊的技术专栏

更新了Django第5天和第6天的文档

上级 5bd10ce6
无法预览此类型文件
......@@ -135,3 +135,51 @@ SESSION_ENGINE = 'django.contrib.sessions.backends.cache'
SESSION_CACHE_ALIAS = 'default'
```
如果要修改session数据默认的序列化方式,可以将默认的`JSONSerializer`修改为`PickleSerializer`
```Python
SESSION_SERIALIZER = 'django.contrib.sessions.serializers.PickleSerializer'
```
### 在视图函数中读写cookie
Django封装的`HttpRequest``HttpResponse`对象分别提供了读写cookie的操作。
HttpRequest封装的属性和方法:
1. `COOKIES`属性 - 该属性包含了HTTP请求携带的所有cookie。
2. `get_signed_cookie`方法 - 获取带签名的cookie,如果签名验证失败,会产生`BadSignature`异常。
HttpResponse封装的方法:
1. `set_cookie`方法 - 该方法可以设置一组键值对并将其最终将写入浏览器。
2. `set_signed_cookie`方法 - 跟上面的方法作用相似,但是会对cookie进行签名来达到防篡改的作用。因为如果篡改了cookie中的数据,在不知道[密钥](<https://zh.wikipedia.org/wiki/%E5%AF%86%E9%92%A5>)[](<https://zh.wikipedia.org/wiki/%E7%9B%90_(%E5%AF%86%E7%A0%81%E5%AD%A6)>)的情况下是无法生成有效的签名,这样服务器在读取cookie时会发现数据与签名不一致从而产生`BadSignature`异常。需要说明的是,这里所说的密钥就是我们在Django项目配置文件中指定的`SECRET_KEY`,而盐是程序中设定的一个字符串,你愿意设定为什么都可以,只要是一个有效的字符串。
上面提到的方法,如果不清楚它们的具体用法,可以自己查阅一下Django的[官方文档](<https://docs.djangoproject.com/en/2.1/ref/request-response/>),没有什么资料比官方文档能够更清楚的告诉你这些方法到底如何使用。
刚才我们说过了,激活`SessionMiddleware`之后,每个`HttpRequest`对象都会绑定一个session属性,它是一个类似字典的对象,除了保存用户数据之外还提供了检测浏览器是否支持cookie的方法,包括:
1. `set_test_cookie`方法 - 设置用于测试的cookie。
2. `test_cookie_worked`方法 - 检测测试cookie是否工作。
3. `delete_test_cookie`方法 - 删除用于测试的cookie。
4. `set_expiry`方法 - 设置会话的过期时间。
5. `get_expire_age`/`get_expire_date`方法 - 获取会话的过期时间。
6. `clear_expired`方法 - 清理过期的会话。
下面是在执行登录之前检查浏览器是否支持cookie的代码。
```Python
def login(request):
if request.method == 'POST':
if request.session.test_cookie_worked():
request.session.delete_test_cookie()
# Add your code to perform login process here
else:
return HttpResponse("Please enable cookies and try again.")
request.session.set_test_cookie()
return render_to_response('login.html')
```
### Cookie的替代品
之前我们说过了,cookie的名声一直都不怎么好,当然我们在实际开发中是不会在cookie中保存用户的敏感信息(如用户的密码、信用卡的账号等)的,而且保存在cookie中的数据一般也会做好编码和签名的工作。即便如此,HTML5中还是给出了用于替代cookie的技术方案,其中使用得最为广泛的就是localStorage和sessionStorage,相信从名字上你就能听出二者的差别,存储在`localStorage`的数据可以长期保留;而存储在`sessionStorage`的数据会在浏览器关闭时会被清除 。关于这些cookie替代品的用法,建议大家查阅[MDN](<https://developer.mozilla.org/zh-CN/docs/Web>)来进行了解。
\ No newline at end of file
## 中间件的应用
我们继续来完善投票应用。在上一个章节中,我们在用户登录成功后通过session保留了用户信息,接下来我们可以应用做一些调整,要求在为老师投票时必须要先登录,登录过的用户可以投票,否则就将用户引导到登录页面,为此我们可以这样修改视图函数。
```Python
def praise_or_criticize(request: HttpRequest):
"""投票"""
if 'user' in request.session:
try:
tno = int(request.GET.get('tno', '0'))
teacher = Teacher.objects.get(no=tno)
if request.path.startswith('/vote/praise'):
teacher.good_count += 1
else:
teacher.bad_count += 1
teacher.save()
data = {'code': 200, 'message': '操作成功'}
except (ValueError, Teacher.DoesNotExist):
data = {'code': 404, 'message': '操作失败'}
else:
data = {'code': 401, 'message': '请先登录'}
return JsonResponse(data)
```
前端页面在收到`{'code': 401, 'message': '请先登录'}`后,可以将用户引导到登录页面。
```HTML
<script>
$(() => {
$('.comment > a').on('click', (evt) => {
evt.preventDefault()
let a = $(evt.target)
$.ajax({
url: a.attr('href'),
type: 'get',
dataType: 'json',
success: (json) => {
if (json.code == 200) {
let span = a.next()
span.text(parseInt(span.text()) + 1)
} else if (json.code == 401) {
location.href = '/vote/login/?backurl=' + location.href
} else {
alert(json.message)
}
}
})
})
})
</script>
```
> 注意:为了在登录成功之后能够回到刚才投票的页面,我们在跳转登录时设置了一个`backurl`参数,把当前浏览器中的URL作为返回的页面地址。
这样我们已经实现了用户必须登录才能投票的限制,但是一个新的问题来了。如果我们的应用中有很多功能都需要用户先登录才能执行,那么我们是不是需要在每个视图函数中添加代码来检查session中是否包含了登录用户的信息呢?答案是否定的,如果这样做了,我们的视图函数中必然会充斥着大量的重复代码。编程大师Martin Fowler曾经说过:**代码有很多种坏味道,重复是最坏的一种**。我们可以把验证用户是否登录这样的代码放到Django的中间件中。
### Django中间件概述
### 自定义中间件
......@@ -256,7 +256,7 @@
- 实现用户跟踪
- cookie和session的关系
- Django框架对session的支持
- 视图函数中实现cookie读写
- 视图函数中的cookie读写操作
#### Day46 - [中间件的应用](./Day41-55/06.中间件的应用.md)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册