第17章:保护视图
优质
小牛编辑
124浏览
2023-12-01
前言
欢迎来到本系列教程的第5部分,在这节课,我们将学习如何保护视图防止未登录的用户访问,以及在视图和表单中访问已经登录的用户,我们还将实现主题列表和回复列表视图,最后,将探索 Django ORM 的一些特性和数据迁移的简单介绍。
保护视图
我们必须保护视图防止那些未认证(登录)的用户访问,下面是发起一个新话题的页面
在上图中,用户还没有登录,尽管他们可以看到页面和表单。Django 有一个内置的 视图装饰器 来避免它被未登录的用户访问:
boards/views.py(完整代码)
from django.contrib.auth.decorators import login_required @login_required def new_topic(request, pk): # ...
现在如果用户没有登录,将被重定向到登录页面:
注意查询字符串 ?next=/boards/1/new/ ,我们可以改进登录模板以便利用 next 变量来改进我们的用户体验,(译注:实际上这步操作不加也没问题)
配置登录后的重定向地址
templates/login.html (查看完整内容)
<form method="post" novalidate> {% csrf_token %} <input type="hidden" name="next" value="{{ next }}"> {% include 'includes/form.html' %} <button type="submit" class="btn btn-primary btn-block">Log in</button> </form>
现在尝试登录,登录成功后,应用程序会跳转到原来所在的位置。
next 参数是内置功能的一部分(译注:详情请参考Django官方文档)
测试
现在添加一个测试用例确保主题发布视图被 @login_required
装饰器保护了,不过,我们还是先来重构一下 boards/tests/test_views.py 文件。
把test_views.py拆分成3个文件:
- test_view_home.py 包含 HomeTests 类 (完整代码)
- test_view_board_topics.py 包含 BoardTopicsTests 类(完整代码)
- test_view_new_topic.py 包含 NewTopicTests 类(完整代码)
myproject/ |-- myproject/ | |-- accounts/ | |-- boards/ | | |-- migrations/ | | |-- templatetags/ | | |-- tests/ | | | |-- __init__.py | | | |-- test_templatetags.py | | | |-- test_view_home.py <-- here | | | |-- test_view_board_topics.py <-- here | | | +-- test_view_new_topic.py <-- and here | | |-- __init__.py | | |-- admin.py | | |-- apps.py | | |-- models.py | | +-- views.py | |-- myproject/ | |-- static/ | |-- templates/ | |-- db.sqlite3 | +-- manage.py +-- venv/ ``` 重新运行测试,确保一切正常。 现在在 **test_view_new_topic.py** 中添加一个新测试用例,用来检查试图是否被`@login_required`保护: **boards/tests/test_view_new_topic.py** ([完成代码](https://gist.github.com/itorfs/13e75451396d76354b476edaefadbdab#file-test_view_new_topic-py-L84)) ```python from django.test import TestCase from django.urls import reverse from ..models import Board class LoginRequiredNewTopicTests(TestCase): def setUp(self): Board.objects.create(name='Django', description='Django board.') self.url = reverse('new_topic', kwargs={'pk': 1}) self.response = self.client.get(self.url) def test_redirection(self): login_url = reverse('login') self.assertRedirects(self.response, '{login_url}?next={url}'.format(login_url=login_url, url=self.url))
在测试用例中,我们尝试在没有登录的情况下发送请求给 new topic 视图,期待的结果是请求重定向到登录页面。