Skip to content

第二站练习答案 ​

返回纵览 | 专题一 | 专题二

python
# tickets/tests.py
from django.test import SimpleTestCase
from django.urls import reverse


class TicketPageTests(SimpleTestCase):
    def test_detail(self):
        response = self.client.get(reverse("tickets:detail", args=[1]))
        self.assertContains(response, "Printer offline")

    def test_missing_detail(self):
        response = self.client.get(reverse("tickets:detail", args=[999]))
        self.assertEqual(response.status_code, 404)
html
<!-- tickets/templates/tickets/base.html -->
<!doctype html>
<html lang="en">
  <head><meta charset="utf-8"><title>{% block title %}Ticket desk{% endblock %}</title></head>
  <body><nav><a href="{% url 'tickets:list' %}">Tickets</a></nav>{% block content %}{% endblock %}</body>
</html>

运行:

bash
python manage.py test tickets.tests.TicketPageTests

专题二核对 ​

  • 在 get_queryset() 中只接受 {"open", "claimed", "closed"},非法状态返回 400 或明确忽略,并用测试锁定选择。
  • /static/ 可由 CDN 或 Web 服务器公开;私有附件先做对象授权,再由受控响应或内部重定向交付。
  • 分别断言 ?page=2 的对象集合与过界页行为;若采用 Paginator.get_page(),过界会落到最后一页,不是 404。

深水边界 ​

SimpleTestCase 不允许数据库查询,适合当前内存数据阶段。第三站引入模型后应切换 TestCase;测试类型本身就是依赖边界。

开放练习(不提供答案) ​

为 /tickets/abc/、/tickets/0/ 和不存在的整数分别记录 URL resolver 与 view 产生的响应差异。

继续第三站

加码题解:URL、模板与类视图边界 ​

python
from django.shortcuts import get_object_or_404
from django.views.generic import DetailView
from .models import Ticket

class TicketDetailView(DetailView):
    model = Ticket
    slug_url_kwarg = 'ticket_id'

    def get_queryset(self):
        return Ticket.objects.select_related('owner').filter(owner=self.request.user)

关键推理 ​

把权限过滤放进 queryset,模板只接收已经确定可见的对象。

可替代方案 ​

需要返回统一 API 错误时,可使用显式 view/service,并保留相同的 queryset 合同。

典型错误 ​

只在模板隐藏按钮,或让不存在对象抛 500;URL converter 也不能代替对象权限。

复盘时请把状态码/事务/权限/资源清理中的至少一项写成自动化测试,而不是只截图成功页面。

用心记录每一步成长