下载工作台
Django Web 开发

Django REST Framework 入门

试读上半部分 · 解锁后可读全文

第 7 章 · Django REST Framework 入门

本章目标:安装并配置 Django REST Framework(DRF);掌握 Serializer 序列化与反序列化;使用 ViewSetRouter 快速暴露 REST API;配置分页;完成与前端 JSON 对接的完整链路;在虚构电商 shop-demo 上实现商品 API。

学时建议:4~5 小时(含 2 小时 API 联调)

前置:本模块 ch01 MTV 与项目结构;ch04 CBV;ch05 ORM 与 Product 模型;ch06 分页与 Admin。Python 基础见 python-dev ch11 requests 与 JSON。


7.1 为什么需要 DRF

传统 Django 视图返回 HTML 模板;前后端分离架构中,后端需提供 JSON API,供 Vue/React 或移动端消费。

浏览器 / SPA 前端
    → HTTP GET/POST/PUT/DELETE
    → DRF ViewSet
    → Serializer(校验 + 转换)
    → Model ↔ 数据库
    → JSON Response
对比项Django 视图 + JsonResponseDRF
序列化手写 dictSerializer 声明字段
校验手动 if 判断is_valid() 统一处理
路由每个 URL 单独写Router 自动生成 REST 路由
分页自己算 offsetPageNumberPagination 内置
Browsable API开发期可视化调试
说明:本章示例均基于教学项目 shop-demo,API 基址使用 https://api.example.com 或本地 http://127.0.0.1:8000,不引用任何企业内部仓库。
模型演进提示:从本章起,Product 模型升级为企业常用字段——sku 更名为 slug(SEO 友好标识)、is_active 更名为 is_published,并补充 descriptionupdated_at。请先执行字段迁移再继续:

>

```bash
python manage.py makemigrations catalog --name evolve_product_fields
python manage.py migrate
```

>

字段对照表(ch01~ch06 练习 → ch07+ 正式模型):

>

| ch01~ch06 | ch07+ | 说明 |
|------------|-------|------|
| sku | slug | 商品 URL 标识 |
| is_active | is_published | 是否上架 |
| — | description | 详情大字段 |
| — | updated_at | 自动更新时间 |

>

本章及后续章节(ch07~ch19)均以新字段为准;ch01~ch06 的旧字段示例请按上表对照理解。

7.2 安装与全局配置

shop-demo 虚拟环境中:

cd ~/python-learn/shop-demo
pip install "djangorestframework>=3.14,<4" "django-filter>=24,<26"
pip freeze | grep -iE "rest|filter" >> requirements.txt

shopdemo/settings.py

INSTALLED_APPS = [
    # ...
    "rest_framework",
    "django_filters",   # 7.4 的过滤后端依赖
    "catalog",   # 商品应用,ch05 已建
]

REST_FRAMEWORK = {
    "DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.PageNumberPagination",
    "PAGE_SIZE": 10,
    "DEFAULT_RENDERER_CLASSES": [
        "rest_framework.renderers.JSONRenderer",
        "rest_framework.renderers.BrowsableAPIRenderer",  # 开发期保留
    ],
    "DEFAULT_PERMISSION_CLASSES": [
        "rest_framework.permissions.IsAuthenticatedOrReadOnly",
    ],
}
配置项作用
PAGE_SIZE默认每页条数
IsAuthenticatedOrReadOnly未登录可读,写操作需登录
Browsable API浏览器访问 /api/products/ 可点选调试

7.3 Serializer 基础

catalog/serializers.py

from rest_framework import serializers
from .models import Product, Category


class CategorySerializer(serializers.ModelSerializer):
    class Meta:
        model = Category
        fields = ["id", "name", "slug"]


class ProductListSerializer(serializers.ModelSerializer):
    category_name = serializers.CharField(source="category.name", read_only=True)

    class Meta:
        model = Product
        fields = [
            "id", "name", "slug", "price", "stock",
            "is_published", "category", "category_name",
            "created_at",
        ]
        read_only_fields = ["created_at"]


class ProductDetailSerializer(serializers.ModelSerializer):
    """详情接口:比列表多 description 等大字段,列表接口保持轻量"""
    category_name = serializers.CharField(source="category.name", read_only=True)

    class Meta:
        model = Product
        fields = [
            "id", "name", "slug", "description", "price", "stock",
            "is_published", "category", "category_name",
            "created_at", "updated_at",
        ]
        read_only_fields = ["created_at", "updated_at"]

要点

  • ModelSerializer 根据 Model 自动生成字段映射
  • source="category.name" 嵌套只读字段
  • 列表与详情可用不同 Serializer,减少列表接口 payload

手动校验示例

class ProductWriteSerializer(serializers.ModelSerializer):
    class Meta:
        model = Product
        fields = ["name", "slug", "price", "stock", "category", "description"]

    def validate_price(self, value):
        if value <= 0:
            raise serializers.ValidationError("价格必须大于 0")
        return value

    def validate_slug(self, value):
        if Product.objects.filter(slug=value).exists():
            raise serializers.ValidationError("slug 已存在")
        return value

7.4 ViewSet 与 Router

catalog/views.py

from rest_framework import viewsets, filters
from rest_framework.decorators import action
from rest_framework.response import Response
from django_filters.rest_framework import DjangoFilterBackend

from .models import Product
from .serializers import ProductListSerializer, ProductDetailSerializer, ProductWriteSerializer


class ProductViewSet(viewsets.ModelViewSet):
    queryset = Product.objects.select_related("category").all()
    filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]
    filterset_fields = ["category", "is_published"]
    search_fields = ["name", "slug"]
    ordering_fields = ["price", "created_at", "stock"]
    ordering = ["-created_at"]

    def get_serializer_class(self):
        if self.action == "list":
            return ProductListSerializer
        if self.action in ("create", "update", "partial_update"):
            return ProductWriteSerializer
        return ProductDetailSerializer

    @action(detail=False, methods=["get"], url_path="on-sale")

以下内容需解锁后阅读

试读已结束。解锁本章 ¥5.00,或开通年度会员畅读全部教程。
年度会员 ¥199.00/年; 小紫 AI 工作台有效会员 ¥99.00/年

正文仅在服务端鉴权后下发,未付费无法获取下半部分内容。