从零开始:掌握 Django REST framework (DRF) – wiki基地


从零开始:掌握 Django REST framework (DRF)

引言:API 时代与 DRF 的崛起

在现代 Web 开发的浪潮中,前后端分离、移动应用、单页应用 (SPA) 已成为主流。这些架构模式的基石,正是强大的 API(应用程序接口)。API 允许不同的软件系统相互通信,交换数据,使得后端可以专注于业务逻辑和数据处理,而前端则负责用户界面的呈现。

对于 Django 开发者而言,构建高质量、可维护且易于使用的 RESTful API 是一个常见的需求。虽然 Django 本身提供了处理 HTTP 请求和返回 JSON/XML 的基础能力,但构建一个完整的 RESTful API 需要处理序列化、反序列化、视图逻辑、认证、权限、分页、过滤、路由等诸多繁琐的任务。如果从头开始手动实现这一切,不仅耗时耗力,而且容易出错。

这时,Django REST framework (DRF) 应运而生。DRF 是一个功能强大且高度灵活的工具包,它建立在 Django 的基础上,极大地简化了构建 Web API 的过程。它提供了一系列开箱即用的组件,如序列化器、通用视图、认证和权限类、分页器、解析器和渲染器,让你能够以前所未有的效率构建功能完备的 API。

掌握 DRF,意味着你能够利用 Django 强大的 ORM 和生态系统,快速地搭建出供前端、移动应用或第三方服务调用的 API。本文将带领你从零开始,一步步深入理解 DRF 的核心概念,并通过一个实际例子,教会你如何用 DRF 构建一个简单的 API。

准备工作:基础与环境搭建

在开始学习 DRF 之前,你需要具备以下基础知识:

  1. Python 基础: 掌握 Python 的语法、数据结构、函数、类等基本概念。
  2. Django 基础: 了解 Django 项目结构、MVT(或 MTV)模式、模型 (Models)、ORM (Object-Relational Mapper)、视图 (Views)、URL 路由 (URLs) 等。你需要能够创建一个基本的 Django 项目和应用,并定义模型和执行数据库迁移。

如果你的 Django 基础还不够牢固,建议先花时间回顾一下官方文档或相关的入门教程。

环境搭建:

  1. 安装 Python: 确保你的系统已经安装了 Python 3.6 或更高版本。
  2. 创建虚拟环境 (推荐): 使用虚拟环境可以隔离不同项目的依赖,避免冲突。
    bash
    python -m venv venv
  3. 激活虚拟环境:
    • Windows: venv\Scripts\activate
    • macOS/Linux: source venv/bin/activate
  4. 安装 Django 和 DRF: 在激活的虚拟环境中安装。
    bash
    pip install Django djangorestframework

创建 Django 项目与应用

我们将创建一个简单的项目来演示 DRF 的用法。假设我们要创建一个管理产品的 API。

  1. 创建 Django 项目:
    bash
    django-admin startproject drf_project .

    (注意最后的 . 表示在当前目录下创建项目文件)
  2. 创建 Django 应用:
    bash
    python manage.py startapp products
  3. 注册应用和 DRF:drf_project/settings.pyINSTALLED_APPS 中添加 'products''rest_framework'
    “`python
    # drf_project/settings.py

    INSTALLED_APPS = [
    ‘django.contrib.admin’,
    ‘django.contrib.auth’,
    ‘django.contrib.contenttypes’,
    ‘django.contrib.sessions’,
    ‘django.contrib.messages’,
    ‘django.contrib.staticfiles’,
    ‘products’, # 注册你的应用
    ‘rest_framework’, # 注册 DRF
    ]

    … 其他设置

    “`

DRF 核心组件:序列化器 (Serializers)

API 的一个主要任务是处理数据的表示和转换。后端通常使用 Python 对象(如 Django 模型实例),而 API 请求和响应通常使用 JSON、XML 等格式。序列化器就是负责在这些格式之间进行转换的组件。

序列化 (Serialization): 将复杂的 Python 数据类型(如 Django 模型实例、QuerySet)转换为可以轻松地表示成 JSON、XML 或其他媒体类型的格式(通常是 Python 原生的字典或列表)。
反序列化 (Deserialization): 将传入的低级表示(如 JSON 请求体)转换为复杂的 Python 数据类型(如模型实例),通常用于数据校验和保存。

DRF 的序列化器类似于 Django 的 FormModelForm,但更侧重于处理 JSON 等数据格式。

创建一个产品模型:

products/models.py 中定义一个简单的 Product 模型。

“`python

products/models.py

from django.db import models

class Product(models.Model):
name = models.CharField(max_length=255)
description = models.TextField()
price = models.DecimalField(max_digits=10, decimal_places=2)
stock = models.IntegerField(default=0)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)

def __str__(self):
    return self.name

“`

执行数据库迁移:
bash
python manage.py makemigrations
python manage.py migrate

创建一个产品序列化器:

products 应用目录下创建一个 serializers.py 文件,并定义 ProductSerializer

“`python

products/serializers.py

from rest_framework import serializers
from .models import Product

class ProductSerializer(serializers.Serializer):
# 定义需要序列化/反序列化的字段
id = serializers.IntegerField(read_only=True) # read_only=True 表示该字段只用于序列化,不用于反序列化
name = serializers.CharField(max_length=255)
description = serializers.CharField()
price = serializers.DecimalField(max_digits=10, decimal_places=2)
stock = serializers.IntegerField()
created_at = serializers.DateTimeField(read_only=True)
updated_at = serializers.DateTimeField(read_only=True)

def create(self, validated_data):
    """
    根据经过验证的数据,创建并返回一个新的 `Product` 实例。
    """
    return Product.objects.create(**validated_data)

def update(self, instance, validated_data):
    """
    根据经过验证的数据,更新并返回一个已有的 `Product` 实例。
    """
    instance.name = validated_data.get('name', instance.name)
    instance.description = validated_data.get('description', instance.description)
    instance.price = validated_data.get('price', instance.price)
    instance.stock = validated_data.get('stock', instance.stock)
    instance.save()
    return instance

“`

这个 Serializer 类需要手动定义每个字段以及 create()update() 方法来处理对象的创建和更新。

使用 ModelSerializer (推荐):

DRF 提供了一个非常方便的 ModelSerializer 类,它可以根据 Django 模型自动生成字段和 create() / update() 方法。这是处理模型数据时最常用的方式。

修改 products/serializers.py 使用 ModelSerializer

“`python

products/serializers.py

from rest_framework import serializers
from .models import Product

class ProductSerializer(serializers.ModelSerializer):
class Meta:
model = Product
fields = ‘all‘ # 或者指定字段列表: [‘id’, ‘name’, ‘price’, ‘stock’]
# read_only_fields = (‘created_at’, ‘updated_at’) # 如果使用 ‘all‘, 可以通过 read_only_fields 设置只读字段
“`

这样就大大简化了序列化器的定义!__all__ 会包含模型中的所有字段(包括自动添加的 id)。如果你想排除某些字段,可以使用 exclude = [...]

DRF 核心组件:视图 (Views)

视图负责接收 HTTP 请求、处理业务逻辑(与模型和序列化器交互),并返回 HTTP 响应。DRF 提供了多种视图类型,从基本的 APIView 到功能强大的 ViewSet

1. APIView:

这是 DRF 提供的最基本的视图类,它继承自 Django 的 View 类,并添加了 DRF 特有的功能,如请求解析、响应渲染、认证、权限等。你可以像 Django 的 CBV 一样,为不同的 HTTP 方法 (GET, POST, PUT, DELETE) 定义对应的方法。

创建一个简单的产品列表和创建视图:

“`python

products/views.py

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from .models import Product
from .serializers import ProductSerializer

class ProductListCreateAPIView(APIView):
“””
产品列表和创建视图。
“””
def get(self, request, format=None):
“””
获取所有产品列表。
“””
products = Product.objects.all()
serializer = ProductSerializer(products, many=True) # many=True 表示序列化一个 QuerySet (列表)
return Response(serializer.data)

def post(self, request, format=None):
    """
    创建新产品。
    """
    serializer = ProductSerializer(data=request.data) # request.data 包含了请求体中的数据
    if serializer.is_valid(): # 验证数据
        serializer.save() # 调用 serializer 的 create() 或 update() 方法保存数据
        return Response(serializer.data, status=status.HTTP_201_CREATED)
    return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

“`

products/urls.py 中配置 URL:

“`python

products/urls.py

from django.urls import path
from .views import ProductListCreateAPIView

urlpatterns = [
path(‘products/’, ProductListCreateAPIView.as_view(), name=’product-list-create’),
]
“`

在项目主 urls.py (drf_project/urls.py) 中包含应用的 URL:

“`python

drf_project/urls.py

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
path(‘admin/’, admin.site.urls),
path(‘api/’, include(‘products.urls’)), # 将产品相关的 API 路由到 products 应用下
]
“`

现在,运行 python manage.py runserver,访问 http://127.0.0.1:8000/api/products/,你将看到一个漂亮的 DRF 提供的可浏览 API 界面(如果你没有数据,它会显示一个空的列表和 POST 表单)。你可以尝试通过这个界面或使用 Postman/curl 进行 GET 和 POST 请求。

2. GenericAPIView 和 Mixins:

APIView 虽然灵活,但对于常见的操作(如列表、创建、检索、更新、删除)仍需要手动编写大量重复的代码。DRF 提供了 GenericAPIView,它继承自 APIView 并添加了一些常用属性(如 queryset, serializer_class, lookup_field)和方法(如 get_object, get_queryset),用于简化代码。

更进一步,DRF 提供了一系列 Mixins(混入类),它们提供了具体的行为实现,如:

  • ListModelMixin: 实现列表 (GET) 操作。
  • CreateModelMixin: 实现创建 (POST) 操作。
  • RetrieveModelMixin: 实现检索 (GET by ID) 操作。
  • UpdateModelMixin: 实现更新 (PUT/PATCH by ID) 操作。
  • DestroyModelMixin: 实现删除 (DELETE by ID) 操作。

通过继承 GenericAPIView 和一个或多个 Mixin,可以非常快速地构建常用视图。

修改 products/views.py 使用 Generic Views 和 Mixins:

“`python

products/views.py

… 导入不变

from rest_framework import generics

class ProductListCreateAPIView(generics.ListCreateAPIView):
“””
产品列表和创建视图 (使用 Generic Views)。
“””
queryset = Product.objects.all() # 指定查询集
serializer_class = ProductSerializer # 指定序列化器

class ProductRetrieveUpdateDestroyAPIView(generics.RetrieveUpdateDestroyAPIView):
“””
产品详情、更新和删除视图 (使用 Generic Views)。
“””
queryset = Product.objects.all() # 指定查询集
serializer_class = ProductSerializer # 指定序列化器
lookup_field = ‘pk’ # 指定用于查找对象的 URL 参数名称,默认为 ‘pk’ (主键)
“`

修改 products/urls.py 以包含详情视图的路由:

“`python

products/urls.py

from django.urls import path

from .views import ProductListCreateAPIView # 替换

from .views import ProductListCreateAPIView, ProductRetrieveUpdateDestroyAPIView

urlpatterns = [
path(‘products/’, ProductListCreateAPIView.as_view(), name=’product-list-create’),
path(‘products//’, ProductRetrieveUpdateDestroyAPIView.as_view(), name=’product-detail’), # 注意 URL 中需要
]
“`

现在,你有两个视图:一个处理 /api/products/ (GET for list, POST for create),另一个处理 /api/products/<id>/ (GET for retrieve, PUT/PATCH for update, DELETE for destroy)。代码量大大减少了,因为 Mixins 提供了大部分的实现。

3. ViewSets:

ViewSets 是 DRF 中更高级的概念,它将一组相关的视图逻辑(如列表、创建、检索、更新、删除)捆绑到一个类中,而不是像 Generic Views 那样分散到不同的类中。一个 ViewSet 不提供像 .get(), .post() 这样的方法,而是提供像 .list(), .create(), .retrieve(), .update(), .partial_update(), .destroy() 这样的方法。

ViewSets 的主要优势在于它们可以与 Routers(路由器)配合使用,自动生成 URL 配置,进一步简化了 URL 定义。

最常用的 ViewSet 是 ModelViewSet,它继承了 GenericViewSet 和所有 Model Mixins (List, Create, Retrieve, Update, Destroy),因此它提供了完整的 CRUD (创建、检索、更新、删除) 功能。

修改 products/views.py 使用 ViewSet:

“`python

products/views.py

… 导入不变

from rest_framework import generics # 替换

from rest_framework import viewsets

class ProductViewSet(viewsets.ModelViewSet):
“””
产品 ViewSet,提供 list, create, retrieve, update, destroy 操作。
“””
queryset = Product.objects.all()
serializer_class = ProductSerializer
# lookup_field = ‘pk’ # ModelViewSet 默认使用 ‘pk’
“`

修改 products/urls.py 使用 Router:

DRF 提供了 Router 来自动生成 URL 配置。

“`python

products/urls.py

from django.urls import path # 替换

from django.urls import path, include # 需要 include

from .views import ProductListCreateAPIView, ProductRetrieveUpdateDestroyAPIView # 替换

from .views import ProductViewSet
from rest_framework.routers import DefaultRouter # 导入路由器

创建一个路由器实例

router = DefaultRouter()

注册 ViewSet 到路由器

参数1: URL 前缀 (不需要开头和结尾斜杠)

参数2: ViewSet 类

参数3: 可选,用于命名 URL 模式的基础名称 (通常是模型名的小写)

router.register(r’products’, ProductViewSet)

router.urls 会自动生成 URL 列表

urlpatterns = [
# path(‘products/’, ProductListCreateAPIView.as_view(), name=’product-list-create’), # 替换
# path(‘products//’, ProductRetrieveUpdateDestroyAPIView.as_view(), name=’product-detail’), # 替换
path(”, include(router.urls)), # 包含路由器生成的 URL
]
“`

在项目主 urls.py (drf_project/urls.py) 中包含应用的 URL 的方式不变。

现在,访问 /api/ 路径(如果你的主 URL 配置是 /api/),DRF 的可浏览 API 会显示路由器自动生成的 URL 列表,包括 /api/products/ (list, create) 和 /api/products/<id>/ (retrieve, update, destroy)。

使用 ModelViewSetDefaultRouter 是构建典型 RESTful API 最快捷的方式,强烈推荐!

DRF 核心组件:请求 (Requests) 与响应 (Responses)

DRF 对 Django 原生的 HttpRequestHttpResponse 进行了封装和增强。

  • Request: DRF 的 Request 对象扩展了 Django 的 HttpRequest,最常用的属性是 request.datarequest.data 可以处理多种媒体类型的请求内容(如 JSON, XML, 表单数据),并根据请求的 Content-Type 自动解析。这意味着你不需要手动检查 request.methodrequest.body 并解析 JSON。
  • Response: DRF 的 Response 对象继承自 TemplateResponse,它接收 Python 原生的数据(如字典、列表)作为其第一个参数,并负责将其渲染成客户端期望的格式(如 JSON)。它根据请求的 Accept 头部信息选择合适的渲染器。这使得你可以直接返回 Python 数据,而无需手动将数据转换为 JSON 字符串。

这是 DRF 易用性的重要体现:在视图中处理的都是 Python 数据,DRF 负责底层的格式转换。

可浏览 API (Browsable API)

正如你在上面的例子中看到的,DRF 提供了一个非常实用的功能:可浏览 API。当你使用浏览器访问由 DRF View 或 ViewSet 支持的 URL 时,DRF 会渲染一个 HTML 页面,该页面展示了 API 的可用端点、允许的 HTTP 方法、序列化器的字段、以及一个用于发送 POST/PUT/PATCH 请求的表单。

这个功能对于开发、调试和测试 API 极其有用,它让你无需其他工具就能直观地与 API 交互。

DRF 核心组件:认证 (Authentication) 与权限 (Permissions)

构建实际的 API,安全性是必不可少的。你需要知道请求是谁发起的(认证),以及该用户是否有权执行请求的操作(权限)。

  • 认证 (Authentication): 验证请求的凭证(如用户名/密码、Token、Session ID),从而确定是哪个用户发起的请求。DRF 提供了多种认证类,如 SessionAuthentication (用于与 Django Session 配合,适合 Web 应用)、TokenAuthentication (基于 Token 的简单认证)、BasicAuthentication 等。你也可以实现自定义的认证类。
  • 权限 (Permissions): 验证通过认证的用户是否有执行特定操作的权限。DRF 提供了多种权限类,如 IsAuthenticated (要求用户必须认证)、IsAdminUser (要求用户必须是管理员)、IsAuthenticatedOrReadOnly (认证用户有读写权限,匿名用户只有读权限)。你也可以实现自定义的权限类,例如基于对象的权限。

你可以在视图或 ViewSet 中通过 authentication_classespermission_classes 属性来指定使用的认证和权限类。

“`python

products/views.py (添加认证和权限示例)

… 导入不变

from rest_framework.permissions import IsAuthenticatedOrReadOnly # 导入权限类
from rest_framework.authentication import TokenAuthentication # 导入认证类 (如果使用 Token 认证)

class ProductViewSet(viewsets.ModelViewSet):
“””
产品 ViewSet,添加认证和权限。
“””
queryset = Product.objects.all()
serializer_class = ProductSerializer
# lookup_field = ‘pk’ # ModelViewSet 默认使用 ‘pk’

# authentication_classes = [TokenAuthentication] # 如果使用 Token 认证,取消注释
permission_classes = [IsAuthenticatedOrReadOnly] # 设置权限类

“`

IsAuthenticatedOrReadOnly 应用到 ProductViewSet 意味着:未认证的用户只能通过 GET 请求查看产品列表和详情;认证用户可以执行所有操作 (GET, POST, PUT, PATCH, DELETE)。

注意: 使用 TokenAuthentication 需要在 settings.py 中配置并运行迁移,还需要生成 Token。这是另一个可以深入学习的话题,本文不再展开,但知道它们的存在和如何应用于视图是很重要的。

其他重要组件:分页 (Pagination) 与过滤 (Filtering)

对于包含大量数据的 API,一次性返回所有数据是不现实的。DRF 提供了分页功能,允许你限制返回结果的数量,并提供下一页/上一页的链接。

  • Pagination: 常见的类型有 PageNumberPagination (基于页码) 和 LimitOffsetPagination (基于偏移量和限制数量)。你可以在 settings.py 中设置全局默认分页类,也可以在视图中通过 pagination_class 属性覆盖。

“`python

drf_project/settings.py (全局设置分页)

REST_FRAMEWORK = {
‘DEFAULT_PAGINATION_CLASS’: ‘rest_framework.pagination.PageNumberPagination’,
‘PAGE_SIZE’: 10 # 每页项目数
}
“`

设置后,访问 /api/products/ 将自动分页,你可以通过 /api/products/?page=2/api/products/?limit=20&offset=20 (取决于分页类) 来访问不同页。

  • Filtering: 允许客户端通过 URL 参数对结果集进行过滤。DRF 提供了一个独立的包 django-filter 与其集成。安装并配置后,你可以通过 filter_backends 属性在视图中启用过滤。

bash
pip install django-filter

“`python

drf_project/settings.py (注册 django-filter)

INSTALLED_APPS = [
# … 其他应用
‘django_filters’, # 注册 django-filter
‘rest_framework’,
# …
]

REST_FRAMEWORK = {
# … 分页设置
‘DEFAULT_FILTER_BACKENDS’: [‘django_filters.rest_framework.DjangoFilterBackend’] # 默认过滤后端
}
“`

“`python

products/views.py (在 ViewSet 中使用过滤)

… 导入不变

from django_filters.rest_framework import DjangoFilterBackend # 导入过滤后端

class ProductViewSet(viewsets.ModelViewSet):
# … queryset, serializer_class, permission_classes

filter_backends = [DjangoFilterBackend] # 启用过滤后端
filterset_fields = ['name', 'price', 'stock'] # 指定允许过滤的字段

“`

现在,你可以通过 /api/products/?name=Example&price=10.00 来过滤产品。

总结与下一步

恭喜你!通过上面的步骤,你已经从零开始,理解了 DRF 的核心组件,并通过一个产品 API 的例子,实践了序列化器、各种视图类型(特别是 ViewSet)、请求/响应处理、URL 路由(特别是 Router),并了解了认证、权限、分页和过滤的基本概念。

你已经掌握了构建 RESTful API 的基本骨架。然而,DRF 的功能远不止于此。为了更深入地掌握 DRF,你可以进一步学习以下内容:

  1. 深入理解 Serializers: 学习如何处理嵌套序列化、自定义字段、验证器 (Validators)。
  2. 高级视图技术: 探索 GenericViewSet 的用法,如何使用自定义 Mixins。
  3. 认证与权限实战: 学习如何实现 TokenAuthentication、JWT 认证,以及如何编写自定义的权限类。
  4. 测试 API: 学习如何使用 Django 的 TestCase 或 DRF 提供的 APITestCase 来编写 API 测试用例。
  5. 版本控制 (Versioning): 当 API 发生变化时,如何优雅地处理不同版本的 API。
  6. 限流 (Throttling): 如何限制用户或客户端的请求频率。
  7. 自定义组件: 如何编写自定义的解析器 (Parsers)、渲染器 (Renderers)、字段 (Fields)、序列化器 (Serializers) 或 ViewSets。
  8. 文档生成: 使用工具如 Swagger/OpenAPI (drf-yasg, drf-spectacular) 为你的 API 生成交互式文档。

DRF 官方文档是最好的学习资源。它非常详细且更新及时。通过不断实践和查阅文档,你将能够充分发挥 DRF 的强大能力,构建出高效、健壮且易于维护的 Web API。

记住,最好的学习方法是动手实践。尝试在你自己的 Django 项目中使用 DRF,构建不同类型的 API,解决遇到的问题,这将是你掌握 DRF 最快的方式。

祝你在 DRF 的学习旅程中一切顺利!


发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注

滚动至顶部