Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >从入门到"精通"Django REST Framework-(六)

从入门到"精通"Django REST Framework-(六)

原创
作者头像
rxg456
发布于 2025-02-28 16:11:37
发布于 2025-02-28 16:11:37
19000
代码可运行
举报
运行总次数:0
代码可运行

一. 什么是视图集?

视图集是 DRF 提供的用于统一管理多个相关视图逻辑的类。它将常见的 CRUD 操作(如 list, create, retrieve, update, destroy)封装在一个类中,并支持通过路由器(Router)自动生成 RESTful 风格的 URL。

核心特点

  • 一个类处理多个动作(如 GET /users/GET /users/{id}/)。
  • Mixin 类结合,快速实现标准化操作。
  • 支持自定义扩展(如 @action 装饰器)。

二. 为什么要使用视图集?

优势:

  1. 代码复用:无需为每个动作(列表、详情、创建等)单独写视图类。
  2. 路由自动化:通过 Router 自动生成 URL(如 /users//users/{id}/)。
  3. 标准化接口:天然支持 RESTful 设计,适合快速开发 CRUD API
  4. 灵活扩展:通过 Mixin 组合功能,或添加自定义动作。

缺点:

  • 灵活性受限:不适合需要高度定制化逻辑的场景(如非 RESTful 接口)。

三. 视图集与 Mixin 的关系

视图集类

继承关系

支持的 Mixin

功能描述

ViewSet

直接继承 APIView

无,需手动实现所有方法(如 list, create

最基础的视图集,完全自由但需大量手动编码

GenericViewSet

继承 GenericAPIView(提供 queryset, serializer_class 等核心功能)

需手动组合 Mixin(如 ListModelMixin, CreateModelMixin

灵活组合 Mixin,适合需要自定义逻辑的场景

ModelViewSet

继承 GenericViewSet + 所有 CRUD Mixin

ListModelMixin, CreateModelMixin, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin

全功能视图集,自动支持 CRUD 操作

ReadOnlyModelViewSet

继承 GenericViewSet + 只读 Mixin

ListModelMixin, RetrieveModelMixin

仅支持 list(列表)和 retrieve(详情)操作

四. ViewSet 视图集与路由的基础用法

定义视图集

代码语言:python
代码运行次数:0
运行
AI代码解释
复制
from rest_framework.viewsets import ViewSet
from rest_framework.response import Response

class UserViewSet(ViewSet):
    def list(self, request):
        users = User.objects.all()
        serializer = UserSerializer(users, many=True)
        return Response(serializer.data)

路由绑定

使用 Router 自动生成路由:

代码语言:python
代码运行次数:0
运行
AI代码解释
复制
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register(r'users', UserViewSet, basename='user')
urlpatterns = router.urls

生成的路由:

  • GET /users/list()
  • POST /users/create()
  • 其他动作需手动实现或通过 Mixin 添加。

五. 注册路由介绍

区别

特性

DefaultRouter

SimpleRouter

API 根视图

自动生成 / 的根视图(列出所有注册的路由)

不生成根视图

格式后缀

支持 .json.api 等格式后缀(如 /users.json

不支持格式后缀

URL 路径风格

严格以斜杠 / 结尾(如 /users/

可配置是否包含斜杠(默认包含)

额外功能

提供更丰富的超链接 API 展示

轻量级,只生成基础路由

为什么路由器能自动生成列表和详情页的 API?

DRF 的路由器(如 DefaultRouterSimpleRouter)通过以下机制自动生成 URL:

  1. 视图集的标准化方法undefined视图集(如 ModelViewSet)定义了标准化的方法(list, create, retrieve, update, destroy),这些方法对应 RESTful 的 CRUD 操作:
    • list()GET /users/(获取列表)
    • create()POST /users/(创建对象)
    • retrieve()GET /users/{pk}/(获取单个对象)
    • update()PUT /users/{pk}/(全量更新)
    • partial_update()PATCH /users/{pk}/(部分更新)
    • destroy()DELETE /users/{pk}/(删除对象)
  2. 路由器的预定义映射规则undefined路由器内部预定义了 HTTP 方法视图集方法 的映射关系,例如:
代码语言:python
代码运行次数:0
运行
AI代码解释
复制
# SimpleRouter 的默认路由规则
routes = [
    # 列表路由(不带 {pk})
    Route(
        url=r'^{prefix}/$',
        mapping={'get': 'list', 'post': 'create'},
        name='{basename}-list',
        detail=False,
    ),
    # 详情路由(带 {pk})
    Route(
        url=r'^{prefix}/{lookup}/$',
        mapping={
            'get': 'retrieve',
            'put': 'update',
            'patch': 'partial_update',
            'delete': 'destroy'
        },
        name='{basename}-detail',
        detail=True,
    ),
]
  • prefix:注册时的 URL 前缀(如 users)。
  • lookup:对象标识符(默认是 pk)。
  • mapping:HTTP 方法与视图集方法的映射。
  1. 自动检测视图集支持的方法undefined当调用 router.register() 注册视图集时,路由器会检查视图集是否实现了特定方法:
    • 如果视图集包含 list 方法 → 生成列表路由(GET /users/)。
    • 如果视图集包含 create 方法 → 允许 POST /users/
    • 如果视图集包含 retrieve 方法 → 生成详情路由(GET /users/{pk}/)。
    • 其他方法(update, destroy)同理。
实现原理(源码简化版)

SimpleRouter 为例,其核心逻辑如下:

代码语言:python
代码运行次数:0
运行
AI代码解释
复制
class SimpleRouter:
    def get_urls(self):
        urls = []
        # 遍历所有预定义的路由规则(如列表路由、详情路由)
        for route in self.routes:
            # 动态生成 URL 正则表达式和视图函数
            url = route.url.format(prefix=self.prefix, lookup=self.lookup)
            view = self.viewset.as_view(route.mapping)
            urls.append(url(path=url, view=view, name=route.name))
        return urls
  • 动态生成 URL 模式:

路由器通过字符串模板(如 r'^{prefix}/$')生成具体的 URL 正则表达式。例如,注册 users 时,会生成 r'^users/$'r'^users/{pk}/$'

  • 动态绑定 HTTP 方法到视图集:

通过 viewset.as_view(mapping) 将 HTTP 方法(如 GET)映射到视图集的对应方法(如 list)。

示例:自定义路由规则

假设需要为 UserViewSet 添加一个 search 动作:

1. 定义视图集
代码语言:python
代码运行次数:0
运行
AI代码解释
复制
from rest_framework.viewsets import ModelViewSet
from rest_framework.decorators import action

class UserViewSet(ModelViewSet):
    @action(detail=False, methods=['get'], url_path='search')
    def search_users(self, request):
        # 实现搜索逻辑
        return Response(...)
2. 自定义路由器规则
代码语言:python
代码运行次数:0
运行
AI代码解释
复制
from rest_framework.routers import SimpleRouter, Route

class CustomRouter(SimpleRouter):
    routes = [
        # 默认的列表路由和详情路由
        *SimpleRouter.routes,
        # 添加自定义路由
        Route(
            url=r'^{prefix}/search/$',
            mapping={'get': 'search_users'},
            name='{basename}-search',
            detail=False,
        ),
    ]

router = CustomRouter()
router.register(r'users', UserViewSet)
3. 生成的 URL
  • GET /users/list()
  • GET /users/search/search_users()
  • GET /users/{pk}/retrieve()

路由总结
  • 为什么能自动生成路由:DRF 的路由器通过预定义的规则(如 list 对应 GET /users/),结合视图集的方法检测,动态生成 URL。
  • DefaultRouter vs SimpleRouter:
  • DefaultRouter 提供更完整的 RESTful 支持(API 根视图、格式后缀)。
  • SimpleRouter 更轻量,适合简单场景。
  • 扩展性:undefined可以通过继承路由器并修改 routes 规则,实现自定义 URL 设计。

六. api-root 的作用

  • 功能DefaultRouter 自动生成的根路径(/)会列出所有注册的视图集端点。
  • 示例:访问 / 返回:
代码语言:json
AI代码解释
复制
{
  "users": "http://localhost:8000/users/",
  "groups": "http://localhost:8000/groups/"
}
  • 自定义:通过视图集的 basename 控制链接名称。

七. 其他视图集的使用场景

GenericViewSet使用场景

  • 适用场景:需要灵活组合 Mixin 的场景(如仅支持部分操作)。
  • 示例
代码语言:python
代码运行次数:0
运行
AI代码解释
复制
from rest_framework.mixins import ListModelMixin, CreateModelMixin
class UserViewSet(ListModelMixin, CreateModelMixin, GenericViewSet):
    queryset = User.objects.all()
    serializer_class = UserSerializer

支持 GET /users/(列表)和 POST /users/(创建)。

ModelViewSet使用场景

  • 适用场景:标准 CRUD 接口(如后台管理 API)。
  • 示例
代码语言:python
代码运行次数:0
运行
AI代码解释
复制
class UserViewSet(ModelViewSet):
    queryset = User.objects.all()
    serializer_class = UserSerializer

自动支持 GET, POST, PUT, PATCH, DELETE

ReadOnlyModelViewSet使用场景

  • 适用场景:只读接口(如公开的数据查询 API)。
  • 示例
代码语言:python
代码运行次数:0
运行
AI代码解释
复制
class UserViewSet(ReadOnlyModelViewSet):
    queryset = User.objects.all()
    serializer_class = UserSerializer

仅支持 GET /users/(列表)和 GET /users/{id}/(详情)。

八. 视图集中 @action 装饰器的使用

@action 是 DRF 中用于在视图集(ViewSet)中定义自定义动作的核心装饰器,可以将任意方法暴露为 API 端点。下面通过更多场景详细说明其用法。

1. 基本用法

核心参数说明:
  • detail:
  • True:操作单个对象(如 /users/{id}/action_name/)。
  • False:操作列表或集合(如 /users/action_name/)。
  • methods: 允许的 HTTP 方法(如 ['get', 'post'])。
  • url_path: 自定义 URL 路径(默认用方法名)。
  • url_name: 路由名称(用于反向解析)。
示例 1:简单 GET 请求(列表级)
代码语言:python
代码运行次数:0
运行
AI代码解释
复制
from rest_framework.decorators import action
from rest_framework.response import Response

class UserViewSet(ModelViewSet):
    queryset = User.objects.all()
    serializer_class = UserSerializer

    # 获取所有管理员用户
    @action(detail=False, methods=['get'])
    def admins(self, request):
        admins = User.objects.filter(is_admin=True)
        serializer = self.get_serializer(admins, many=True)
        return Response(serializer.data)
  • 路由GET /users/admins/
  • 说明detail=False 表示操作对象是整个用户列表的筛选。
示例 2:带 POST 请求的列表级动作
代码语言:python
代码运行次数:0
运行
AI代码解释
复制
class UserViewSet(ModelViewSet):
    @action(detail=False, methods=['post'], url_path='bulk-delete')
    def bulk_delete(self, request):
        ids = request.data.get('ids', [])
        User.objects.filter(id__in=ids).delete()
        return Response({'status': '批量删除成功'})
  • 路由POST /users/bulk-delete/
  • 说明
  • 通过 url_path 自定义 URL 路径。
  • 从请求体中获取 ids 列表,批量删除用户。

2. 复杂示例(带参数)

示例 3:操作单个对象(detail=True
代码语言:python
代码运行次数:0
运行
AI代码解释
复制
class UserViewSet(ModelViewSet):
    @action(detail=True, methods=['post'], url_path='activate')
    def activate_user(self, request, pk=None):
        user = self.get_object()  # 自动根据 pk 获取对象
        user.is_active = True
        user.save()
        return Response({'status': '用户已激活'})
  • 路由POST /users/{pk}/activate/
  • 说明
  • detail=True 表示操作单个用户实例。
  • pk 参数自动从 URL 中捕获(如 /users/5/activate/ 中的 5)。
示例 4:混合 GET 和 POST 方法
代码语言:python
代码运行次数:0
运行
AI代码解释
复制
class ProductViewSet(ModelViewSet):
    @action(detail=True, methods=['get', 'post'], url_path='price-history')
    def price_history(self, request, pk=None):
        product = self.get_object()
        if request.method == 'GET':
            # 获取价格历史
            history = PriceHistory.objects.filter(product=product)
            serializer = PriceHistorySerializer(history, many=True)
            return Response(serializer.data)
        elif request.method == 'POST':
            # 添加新价格记录
            serializer = PriceHistorySerializer(data=request.data)
            serializer.is_valid(raise_exception=True)
            serializer.save(product=product)
            return Response(serializer.data)
  • 路由
  • GET /products/{pk}/price-history/ → 获取历史价格
  • POST /products/{pk}/price-history/ → 添加新价格
  • 说明:同一个动作处理多个 HTTP 方法。
示例 5:带 URL 参数的复杂逻辑
代码语言:python
代码运行次数:0
运行
AI代码解释
复制
class OrderViewSet(ModelViewSet):
    @action(detail=True, methods=['get'], url_path='items/(?P<category>[^/.]+)')
    def filter_items_by_category(self, request, pk=None, category=None):
        order = self.get_object()
        items = order.items.filter(category=category)
        serializer = OrderItemSerializer(items, many=True)
        return Response(serializer.data)
  • 路由GET /orders/{pk}/items/electronics/ → 筛选订单中电子类商品
  • 说明
  • url_path 中使用正则表达式捕获参数(category)。
  • 参数通过方法参数传递(category)。

3. 高级技巧

动态权限控制
代码语言:python
代码运行次数:0
运行
AI代码解释
复制
class UserViewSet(ModelViewSet):
    @action(detail=True, methods=['post'], permission_classes=[IsAdminUser])
    def promote_to_admin(self, request, pk=None):
        user = self.get_object()
        user.is_admin = True
        user.save()
        return Response({'status': '用户已升级为管理员'})
  • 说明:通过 permission_classes 覆盖视图集的默认权限。
自定义序列化器
代码语言:python
代码运行次数:0
运行
AI代码解释
复制
class UserViewSet(ModelViewSet):
    def get_serializer_class(self):
        if self.action == 'change_password':
            return ChangePasswordSerializer
        return UserSerializer

    @action(detail=True, methods=['post'])
    def change_password(self, request, pk=None):
        user = self.get_object()
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        user.set_password(serializer.validated_data['password'])
        user.save()
        return Response({'status': '密码已修改'})
  • 说明:根据动作动态选择序列化器。

4. 常见问题

Q1:如何访问 URL 中的参数?
  • 对于 detail=True 的动作,pk 自动从 URL 捕获。
  • 自定义参数可通过正则表达式在 url_path 中定义(如示例 5)。
Q2:如何控制动作的 URL 路径?
  • 使用 url_path 参数覆盖默认路径(如 url_path='custom-path')。
Q3:如何限制动作的访问频率?
  • 结合 throttle_classes:python复制
代码语言:plain
AI代码解释
复制
@action(detail=False, methods=['get'], throttle_classes=[UserRateThrottle])

@action总结

  • @action 的核心价值:扩展视图集,支持非标准业务逻辑(如 /users/{id}/activate/)。
  • 关键参数
  • detail: 区分列表级 vs 对象级操作。
  • methods: 定义支持的 HTTP 方法。
  • url_path: 自定义 URL 路径。
  • 典型场景
    • 批量操作(如批量删除)。
    • 对象状态变更(如激活/冻结用户)。
    • 关联资源的子操作(如订单中的商品筛选)。

验证自定义动作

通过 DRF 的 Web 界面或 curl 测试:

代码语言:bash
AI代码解释
复制
# 测试示例1
curl http://localhost:8000/users/admins/

# 测试示例3
curl -X POST http://localhost:8000/users/5/activate/

九. 视图集总结

组件/技术

适用场景

核心优势

ViewSet

完全自定义逻辑的非标准接口

自由度高

GenericViewSet

需要灵活组合 Mixin 的场景(如仅支持部分操作)

可定制化 + DRF 核心功能

ModelViewSet

标准 CRUD 接口(如后台管理)

全自动 + 零编码

ReadOnlyModelViewSet

只读接口(如公开数据查询)

安全 + 简洁

@action

扩展自定义动作(如 /users/active_users/

灵活扩展非标准操作

最佳实践

  1. 优先选择 ModelViewSet:快速实现标准 CRUD。
  2. 使用 @action 扩展功能:添加非标准业务逻辑。
  3. 根据需求选择 RouterDefaultRouter 适合完整 API,SimpleRouter 适合轻量级需求。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
DRF终极封装ViewSet和Router附教程PDF源码
在DRF官方教程的学习过程中,一个很明显的感受是框架在不断地进行封装,我们自己写框架/工具/脚本/平台也可以模仿模仿,先完成底层代码,再做多层封装,让使用者很容易就上手操作。本文是教程的最后一篇,介绍ViewSets和Routers。
dongfanger
2020/12/23
8930
DRF终极封装ViewSet和Router附教程PDF源码
Django Rest Framework
https://q1mi.github.io/Django-REST-framework-documentation/
vanguard
2020/07/07
2.4K0
【愚公系列】2022年04月 Python教学课程 71-DRF框架之内置路由
对于视图集ViewSet,我们除了可以自己手动指明请求方式与视图方法[官方文档中也叫action,动作]之间的对应关系外,还可以使用Routers来帮助我们自动生成路由信息。
愚公搬代码
2022/04/20
9980
【愚公系列】2022年04月 Python教学课程 70-DRF框架之视图集
ViewSet视图集类不再实现get()、post()等方法,而是实现动作 action 如 list() 、create() 等。
愚公搬代码
2022/04/19
1.7K0
【愚公系列】2022年04月 Python教学课程 70-DRF框架之视图集
Django rest-framework视图家族
总结:GenericAPIView就是在APIView基础上额外提供了三个方法和三个类属性,如果不配合视图工具类,则体现不出来优势所在
GH
2020/01/14
8030
Django rest Framework入门 四 :视图
在Django rest Framework入门 二 :DRF框架初体验中其实已经使用了视图了(book.views里面的代码),而且就是实际开发中最常用的模式,但是那是经过DRF框架高度封装的,代码的可读性不好,而且如果不了解里面的细节,当以后遇到需要定制化的工作时可能就无从下手,这一篇笔记会记录一些我自己认为比较重要切常用的实现细节。
panzhixiang
2024/10/30
1750
测试开发进阶(二十九)
rest_framework.generics.ListCreateAPIView
zx钟
2019/10/24
6880
DRF框架(十一)——路由解读。action注解的声明有什么作用
用以上的方法写路由,只能是view里面继承了试图集之后才可以使用,并且只是生成默认的增删改查的接口。如果是新增加的其他的动作的方法,是不能自动生成路由的,那么如果处理新增加的动作呢?
一写代码就开心
2021/03/02
9930
DRF视图集
我们在三级视图中,由于获取所有数据和获取一条数据都是使用GET请求,而二级视图(三级视图)只允许有一个get方法,因此我们在两个类中进行了设计,并且这样刚好将路由分开。而视图集则提供了新的路由和方法集合,来使我们将路由整合起来,方法整合起来。
zy010101
2021/12/17
9870
DRF视图集
DRF 视图组件
先来看看这其中的人情世故:两个视图基本类,五个扩展类,九个视图子类,视图集方法,视图集··
HammerZe
2022/05/09
9930
DRF 视图组件
路由是如何映射的?
路由的配置上篇我们提到了一点自动配置,对于继承了视图集ViewSet就可以自动生成路由,当然了也可以选择手动版自己配,可以使用action装饰器来指定方法等操作,屁话不多说如下:
HammerZe
2022/05/09
8030
路由是如何映射的?
DRF框架(九)——视图集ViewSet,ModelViewSet,将增删改查写到一个类里面,viewsetmixin (注意路由设置)
ViewSet,只要继承了这个,就实现了增删改查,但是要重写查询全部和详情。 最主要的就是路由的书写
一写代码就开心
2021/03/02
1.9K0
python教程
在做其他事之前,我们会用virtualenv创建一个新的虚拟环境。这将确保我们的包配置与我们正在工作的其他项目完全隔离。
用户2337871
2019/07/19
5.3K0
Rest_framework Route
一条路由规则就是一个Route对象,实例Route对象的参数不同,划分了四类(DynamicRoute也算类Route类):
py3study
2020/01/21
1.1K0
从入门到"精通"Django REST Framework-(五)
GenericAPIView 是 Django REST Framework (DRF) 中的一个基础视图类,它继承自 APIView,并添加了一些常用的功能,特别是与数据库模型交互的功能。它是 DRF 中通用视图和视图集的基础,提供了查询、序列化、分页等常用操作的标准实现。本质上它是 DRF 中所有通用视图(如 ListAPIView、RetrieveAPIView 等)的基础。
rxg456
2025/03/01
2050
从入门到"精通"Django REST Framework-(五)
Django_rest框架实践项目(一)入门helloWord项目的创建和代码的解释
在django_venv 虚拟环境里面创建一个helloworld项目,并且创建一个quickstartapp ,也就是再创建一个app。 ,并且连接数据库,现在是连接mysql数据库,将app映射到数据库里面
一写代码就开心
2021/03/02
1.3K0
Django_rest框架实践项目(一)入门helloWord项目的创建和代码的解释
drf之请求、响应、视图
drf 传入视图的request 不再是Django默认的HttpRequest对象,而是drf 提供的拓展了HttpRequest 类的Request 类的对象。
仙人技术
2020/07/09
2.3K0
drf之请求、响应、视图
Flask框架在Python面试中的应用与实战
Django REST framework (DRF) 是一个强大而灵活的工具包,用于构建Web API,特别是基于Django的应用程序。在Python面试中,对DRF的理解与实际应用能力是衡量候选人Web服务开发能力的重要指标。本篇博客将深入浅出地探讨DRF面试中常见的问题、易错点以及应对策略,并结合实例代码进行讲解。
Jimaks
2024/04/21
2260
django rest framework通用view
官方文档:http://www.django-rest-framework.org/ drf为我们提供强大的通用view的功能,本博客对这些view进行简要的总结分析。 首先,我们看一下主要的几种view以及他们之间的关系。
程序员同行者
2018/12/12
1.1K0
Django REST 框架详解 06 | 视图家族 Generics 与 Viewsets
工具视图都是 GenericAPIView 的子类,不同的子类继承不同工具类,重写请求方法。
白墨石
2021/01/12
1.4K0
推荐阅读
相关推荐
DRF终极封装ViewSet和Router附教程PDF源码
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验