CodeRoadMap
首页路线题库资源库文章社区
CodeRoadMap

程序员的学习成长路线图。内容免费开放,登录后可同步路线图与课时进度。

由 程序员柏风 独立维护 · 关于作者

学习

  • 路线图
  • 课程
  • 面试题
  • 文章
  • 我

更多

  • 资源
  • 社区
  • 关于作者
  • 内容说明

© 2026 CodeRoadMap

津ICP备2026012044号-1·津公网安备12011002026155号·coderoadmap@126.com
Django 实战入门/课时/视图层
RawBlame
课时目录12 节

Django 实战入门

  1. 01Django 概览
  2. 02项目结构
  3. 03URL 路由
  4. 04视图层
  5. 05模型与 ORM
  6. 06查询与优化
  7. 07模板 DTL
  8. 08Admin 与认证
  9. 09表单与安全
  10. 10DRF 与异步任务
  11. 11测试与部署
  12. 12综合练习

视图层

FBV/CBV 与 Generic views。

30 分钟

视图层

这一课你将能做到

  1. 写出一个处理 GET/POST/PUT/DELETE 的函数视图(FBV),并正确返回 JSON 或 HTML
  2. 用类视图(CBV)复用 Mixin 和 Generic Views,把列表页/详情页的重复代码降到最少
  3. 理解 request 对象的生命周期和常用属性(GET、POST、headers、FILES、user)

为什么要学

视图是 Django 里「接收请求 → 处理业务 → 返回响应」的核心枢纽。Spring Boot 用 @Controller 或 @RestController 注解类来定义控制器,Django 支持函数视图(FBV)和类视图(CBV)两种形态。初学者通常先写 FBV,但生产代码里 CBV 和 Generic Views 占比更高,因为它们能消灭 80% 的重复。

人话:视图就是「用户点了什么,服务器干什么,回什么给用户」。写不好视图,路由对了也白搭。

先建立图像

请求进入
   │
   ▼
中间件(认证、CSRF、Session)
   │
   ▼
urls.py → 匹配到 views.py
   │
   ├─ FBV: def article_list(request): ...
   │         手动处理 request.method
   │
   └─ CBV: class ArticleList(ListView):
   │         框架自动按 method 分发到 get/post
   │
   ▼
Model / ORM(查数据库)
   │
   ▼
Template 渲染 / JsonResponse / HttpResponse
   │
   ▼
中间件(收尾)
   │
   ▼
浏览器

跟着做

步骤 1:最基础的函数视图(FBV)

# blog/views.py
from django.http import JsonResponse, HttpResponse
from django.views.decorators.http import require_http_methods


@require_http_methods(["GET", "POST"])
def article_list(request):
    if request.method == "GET":
        data = ["文章1", "文章2"]
        return JsonResponse({"articles": data})
    elif request.method == "POST":
        title = request.POST.get("title", "")
        return JsonResponse({"created": title}, status=201)

require_http_methods 装饰器会拦截不支持的 HTTP 方法,直接返回 405 Method Not Allowed。

步骤 2:认识 request 对象

def inspect_request(request):
    ctx = {
        "method": request.method,
        "path": request.path,
        "GET": dict(request.GET),           # 查询参数 ?page=2
        "POST": dict(request.POST),         # 表单数据
        "headers": dict(request.headers),   # HTTP 头
        "is_ajax": request.headers.get("x-requested-with") == "XMLHttpRequest",
        "user": str(request.user),          # 已登录用户或 AnonymousUser
        "session_key": request.session.session_key,
    }
    return JsonResponse(ctx)

关键属性:

  • request.GET:QueryDict,URL 参数。不是只给 GET 请求用,POST 请求里也能读 request.GET。
  • request.POST:只处理 application/x-www-form-urlencoded 和 的表单数据。JSON 提交不走这里。
multipart/form-data
  • request.body:原始字节流,适合读 JSON payload:json.loads(request.body)。
  • request.FILES:上传的文件字典。
  • request.user:当前用户实例。request.user.is_authenticated 判断是否登录。
  • request.META:CGI 风格的环境变量字典,如 HTTP_USER_AGENT、REMOTE_ADDR。
  • 步骤 3:类视图(CBV)基础

    from django.http import JsonResponse
    from django.views import View
    
    
    class ArticleView(View):
        def get(self, request, *args, **kwargs):
            return JsonResponse({"msg": "GET articles"})
    
        def post(self, request, *args, **kwargs):
            return JsonResponse({"msg": "POST article"}, status=201)
    
        def put(self, request, *args, **kwargs):
            return JsonResponse({"msg": "PUT article"})
    
        def delete(self, request, *args, **kwargs):
            return JsonResponse({"msg": "DELETE article"}, status=204)
    

    路由注册:

    # urls.py
    from django.urls import path
    from . import views
    
    urlpatterns = [
        path("articles/", views.ArticleView.as_view(), name="articles"),
    ]
    

    CBV 的核心是 as_view() 返回一个函数,Django 用该函数接收 request,再按 request.method 分发给 get/post/put/delete 等方法。和 Spring Boot 的 @RequestMapping + 方法分发逻辑同构。

    步骤 4:Generic Views 速通列表/详情

    from django.views.generic import ListView, DetailView
    from .models import Article
    
    
    class ArticleListView(ListView):
        model = Article
        template_name = "blog/article_list.html"
        context_object_name = "articles"
        paginate_by = 10
    
    
    class ArticleDetailView(DetailView):
        model = Article
        template_name = "blog/article_detail.html"
        context_object_name = "article"
        slug_url_kwarg = "slug"
    

    Generic Views 自动做以下事:

    • 查数据库:Article.objects.all()(ListView)或 get(slug=...)(DetailView)
    • 按主键或 slug 过滤
    • 分页(paginate_by)
    • 把查询结果注入模板上下文
    • 渲染模板并返回 HttpResponse

    你只需指定 model 和 template_name,就能跑通列表和详情页。

    步骤 5:Mixin 复用通用逻辑

    from django.contrib.auth.mixins import LoginRequiredMixin
    from django.views.generic import ListView
    
    
    class DashboardView(LoginRequiredMixin, ListView):
        model = Article
        template_name = "blog/dashboard.html"
        login_url = "/admin/login/"
    

    LoginRequiredMixin 会检查 request.user.is_authenticated,未登录直接重定向到 login_url。相当于 Spring Security 的 @PreAuthorize("isAuthenticated()")。

    讲清楚要点

    1. FBV 好理解,CBV 好复用:FBV 像一个线性脚本,适合一次性逻辑。CBV 用继承和 Mixin 组合功能,适合 CRUD 这种高度重复的场景。
    2. request 不是普通 dict:它是 HttpRequest 对象,封装了 WSGI/ASGI 环境变量、中间件注入的 session/user/csrf 等信息。不要把它当纯字典用 request["key"]。
    3. POST 和 body 的区别:前端用 fetch 发 JSON(Content-Type: application/json)时,数据在 request.body,不在 request.POST。request.POST 只处理传统 HTML 表单。
    4. CBV 的 self.kwargs 和 self.args:URL 路由捕获的命名参数进 self.kwargs,位置参数进 self.args。重写 get_queryset 时常用 self.kwargs.get("pk")。
    5. Generic Views 的扩展点:get_queryset()、get_context_data()、get_object(),复写这些方法而不是重写 get(),能保持 Generic Views 的内建行为。
    6. 返回响应不是只能 HttpResponse:JsonResponse(自动序列化 dict)、HttpResponseRedirect(302)、HttpResponseNotFound(404)、StreamingHttpResponse(大文件流式下载)。

    你可能会懵的地方

    • CBV 里 self.request 从哪来的? as_view() 在创建实例后把 request 注入为实例属性。不是全局变量,是每次请求新建一个 CBV 实例。

    • 为什么 CBV 比 FBV 更适合 Generic CRUD? ListView/DetailView/CreateView/UpdateView/DeleteView 已经把 80% 的查库、分页、模板注入、表单处理写好了,你只填 model 和 template_name。FBV 得自己一行行写。

    • Spring Boot @RestController 对应 Django 的什么? 没有直接等价物。Django 最常用的是 FBV 返回 JsonResponse,或 DRF 的 @api_view(第 10 课)。Django 原生 CBV 默认渲染模板,做纯 API 需要手动返回 JSON。

    • 视图里抛异常会怎样? Django 会把未捕获异常交给 middleware 的 process_exception,最终返回 500 页面(DEBUG=True 时带详细堆栈)。生产环境配置 ADMINS 和日志收集。

    • 能不能在视图里直接操作 raw SQL? 能。from django.db import connection; with connection.cursor() as cursor:。但除非 ORM 搞不定(复杂统计、CTE),否则别用 raw SQL,丧失跨数据库能力和自动转义保护。

    错法对照

    错法问题正解
    request.POST.get("json_field") 读 JSON bodyrequest.POST 不处理 JSONjson.loads(request.body)
    CBV 里直接重写 get() 而不用框架扩展点丢失分页、权限检查等 Mixin 行为重写 get_queryset()、get_context_data()
    视图返回 Python dict客户端收到 500 或空响应用 JsonResponse(data)
    return None 或忘记 returnDjango 抛 ValueError所有分支必须有 return
    request.GET["page"] 不写默认值KeyErrorrequest.GET.get("page", "1")

    卡点急救

    1. CBV 报 TypeError: get() got an unexpected keyword argument 'pk':URL 路由捕获了参数,但 CBV 没传 **kwargs 或 Generic View 的 pk_url_kwarg 没配置。检查 DetailView 是否把 pk_url_kwarg 设对。
    2. POST 请求 403 Forbidden:Django 默认开启 CSRF 防护。前端发 POST 时要带上 X-CSRFToken header(Ajax)或模板里用 {% csrf_token %}(表单)。API 场景第 10 课讲怎么豁免。
    3. request.user 是 AnonymousUser:用户没登录。视图加 @login_required 或 CBV 加 LoginRequiredMixin。检查 settings.py 的 AUTHENTICATION_BACKENDS。

    面试常问

    • Django 的 FBV 和 CBV 怎么选? 一次性逻辑、需要大量条件分支、或和中间件紧密交互的场景用 FBV。标准化 CRUD、需要复用权限/分页/查询逻辑的场景用 CBV + Mixin。团队风格统一更重要。

    • 类视图里 as_view() 到底做了什么? 它是一个类方法,返回一个闭包函数。每次请求进来,Django 调用这个函数,函数内部实例化 CBV 类(self = cls(**initkwargs)),然后把 request 传给 self.dispatch(),再由 dispatch 按 HTTP 方法分发到 get/post/put/delete。

    • Generic Views 的 get_queryset() 和 queryset 属性有什么区别? queryset = Article.objects.all() 是静态属性,类定义时就固定。get_queryset() 是方法,每次请求都会调用,可以动态过滤(如只查当前用户的数据)。需要动态过滤时一定重写方法。

    自测三问

    1. request.POST 和 request.body 分别适用于什么 Content-Type?
    2. 为什么 CBV 更适合重复性高的 CRUD?请说出一个具体例子。
    3. LoginRequiredMixin 和 @login_required 的区别和使用场景?

    小结一句话

    视图是 Django 的业务枢纽:FBV 灵活直观,CBV 和 Generic Views 靠继承消灭重复;理解 request 对象和响应类型,就能处理绝大多数 HTTP 交互场景。

    延伸

    • Django 官方文档 - 视图
    • Django 官方文档 - 通用视图
    • 下一课:模型与 ORM——用 Python 代码定义数据库表。
    加载本节练习…
    ← 上一课URL 路由下一课 →模型与 ORM