DRF 路由基础 #

一、路由概述 #

1.1 什么是Router #

Router是DRF提供的URL路由工具,能够自动将ViewSet映射到URL,大大简化URL配置。

text
传统URL配置
┌─────────────────────────────────────┐
│  path('articles/', ArticleList.as_view())  │
│  path('articles/<int:pk>/', ArticleDetail.as_view())  │
│  path('articles/create/', ArticleCreate.as_view())  │
│  ...更多URL配置                      │
└─────────────────────────────────────┘

Router自动生成
┌─────────────────────────────────────┐
│  router.register('articles', ArticleViewSet)  │
│  自动生成所有CRUD URL                │
└─────────────────────────────────────┘

1.2 Router类型 #

Router 说明
DefaultRouter 包含API根视图
SimpleRouter 简洁版,无根视图

二、DefaultRouter #

2.1 基本用法 #

python
from rest_framework.routers import DefaultRouter
from .views import ArticleViewSet

router = DefaultRouter()
router.register(r'articles', ArticleViewSet)

urlpatterns = router.urls

2.2 生成的URL #

URL 方法 操作
/articles/ GET list
/articles/ POST create
/articles/{id}/ GET retrieve
/articles/{id}/ PUT update
/articles/{id}/ PATCH partial_update
/articles/{id}/ DELETE destroy
/ GET API根视图

2.3 集成到项目 #

python
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from .views import ArticleViewSet

router = DefaultRouter()
router.register(r'articles', ArticleViewSet)

urlpatterns = [
    path('api/', include(router.urls)),
]

三、SimpleRouter #

3.1 基本用法 #

python
from rest_framework.routers import SimpleRouter
from .views import ArticleViewSet

router = SimpleRouter()
router.register(r'articles', ArticleViewSet)

urlpatterns = router.urls

3.2 与DefaultRouter区别 #

特性 DefaultRouter SimpleRouter
API根视图
格式后缀 支持 支持
适用场景 完整API 简单API

四、register方法 #

4.1 基本注册 #

python
router.register(r'articles', ArticleViewSet)

4.2 指定basename #

python
router.register(r'articles', ArticleViewSet, basename='article')

basename用于生成URL名称:

  • article-list
  • article-detail

4.3 多个ViewSet注册 #

python
router = DefaultRouter()
router.register(r'articles', ArticleViewSet)
router.register(r'users', UserViewSet)
router.register(r'categories', CategoryViewSet)
router.register(r'tags', TagViewSet)

五、ViewSet URL映射 #

5.1 ModelViewSet映射 #

python
class ArticleViewSet(viewsets.ModelViewSet):
    queryset = Article.objects.all()
    serializer_class = ArticleSerializer

自动生成的URL:

URL模式 HTTP方法 ViewSet方法
{prefix}/ GET list
{prefix}/ POST create
{prefix}/{lookup}/ GET retrieve
{prefix}/{lookup}/ PUT update
{prefix}/{lookup}/ PATCH partial_update
{prefix}/{lookup}/ DELETE destroy

5.2 ReadOnlyModelViewSet映射 #

python
class ArticleViewSet(viewsets.ReadOnlyModelViewSet):
    queryset = Article.objects.all()
    serializer_class = ArticleSerializer

只生成:

URL模式 HTTP方法 ViewSet方法
{prefix}/ GET list
{prefix}/{lookup}/ GET retrieve

5.3 自定义ViewSet映射 #

python
from rest_framework import viewsets, mixins

class ArticleViewSet(mixins.ListModelMixin,
                     mixins.RetrieveModelMixin,
                     mixins.CreateModelMixin,
                     viewsets.GenericViewSet):
    queryset = Article.objects.all()
    serializer_class = ArticleSerializer

六、自定义action路由 #

6.1 detail=True #

python
class ArticleViewSet(viewsets.ModelViewSet):
    queryset = Article.objects.all()
    serializer_class = ArticleSerializer
    
    @action(detail=True, methods=['post'])
    def publish(self, request, pk=None):
        pass

生成URL:/articles/{pk}/publish/

6.2 detail=False #

python
class ArticleViewSet(viewsets.ModelViewSet):
    queryset = Article.objects.all()
    serializer_class = ArticleSerializer
    
    @action(detail=False, methods=['get'])
    def published(self, request):
        pass

生成URL:/articles/published/

6.3 自定义url_path #

python
class ArticleViewSet(viewsets.ModelViewSet):
    queryset = Article.objects.all()
    serializer_class = ArticleSerializer
    
    @action(detail=True, methods=['post'], url_path='change-status')
    def change_status(self, request, pk=None):
        pass

生成URL:/articles/{pk}/change-status/

6.4 多个HTTP方法 #

python
class ArticleViewSet(viewsets.ModelViewSet):
    queryset = Article.objects.all()
    serializer_class = ArticleSerializer
    
    @action(detail=True, methods=['get', 'post'])
    def comments(self, request, pk=None):
        if request.method == 'GET':
            pass
        elif request.method == 'POST':
            pass

七、lookup_field配置 #

7.1 使用slug #

python
class ArticleViewSet(viewsets.ModelViewSet):
    queryset = Article.objects.all()
    serializer_class = ArticleSerializer
    lookup_field = 'slug'

URL变为:/articles/{slug}/

7.2 lookup_url_kwarg #

python
class ArticleViewSet(viewsets.ModelViewSet):
    queryset = Article.objects.all()
    serializer_class = ArticleSerializer
    lookup_field = 'slug'
    lookup_url_kwarg = 'article_slug'

URL配置:

python
router.register(r'articles', ArticleViewSet)

URL变为:/articles/{article_slug}/

八、完整示例 #

8.1 视图集 #

python
from rest_framework import viewsets
from rest_framework.decorators import action
from rest_framework.response import Response
from .models import Article
from .serializers import ArticleSerializer

class ArticleViewSet(viewsets.ModelViewSet):
    queryset = Article.objects.all()
    serializer_class = ArticleSerializer
    lookup_field = 'slug'
    
    @action(detail=False, methods=['get'])
    def published(self, request):
        articles = self.get_queryset().filter(is_published=True)
        serializer = self.get_serializer(articles, many=True)
        return Response(serializer.data)
    
    @action(detail=False, methods=['get'])
    def draft(self, request):
        articles = self.get_queryset().filter(is_published=False)
        serializer = self.get_serializer(articles, many=True)
        return Response(serializer.data)
    
    @action(detail=True, methods=['post'])
    def publish(self, request, slug=None):
        article = self.get_object()
        article.is_published = True
        article.save()
        return Response({'status': 'published'})
    
    @action(detail=True, methods=['post'])
    def like(self, request, slug=None):
        article = self.get_object()
        article.likes.add(request.user)
        return Response({'status': 'liked'})

8.2 URL配置 #

python
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from .views import ArticleViewSet, UserViewSet, CategoryViewSet

router = DefaultRouter()
router.register(r'articles', ArticleViewSet)
router.register(r'users', UserViewSet)
router.register(r'categories', CategoryViewSet, basename='category')

urlpatterns = [
    path('api/v1/', include(router.urls)),
]

8.3 生成的URL列表 #

text
/api/v1/                          # API根视图
/api/v1/articles/                 # 文章列表
/api/v1/articles/published/       # 已发布文章
/api/v1/articles/draft/           # 草稿文章
/api/v1/articles/{slug}/          # 文章详情
/api/v1/articles/{slug}/publish/  # 发布文章
/api/v1/articles/{slug}/like/     # 点赞文章
/api/v1/users/                    # 用户列表
/api/v1/users/{id}/               # 用户详情
/api/v1/categories/               # 分类列表
/api/v1/categories/{id}/          # 分类详情

九、总结 #

本章学习了DRF路由基础:

  • Router类型:DefaultRouter和SimpleRouter
  • register方法:注册ViewSet
  • URL映射:自动生成CRUD URL
  • 自定义action:添加自定义路由
  • lookup_field:自定义查找字段

让我们继续学习路由进阶!

最后更新:2026-03-28