RESTful API 设计与实现:用 DRF 快速搭建后端接口的完整指南
【免费下载链接】Python-100-DaysPython - 100天从新手到大师项目地址: https://gitcode.com/GitHub_Trending/py/Python-100-Days
前后端分离的开发里,时间消耗最大的环节往往是接口反复返工,而问题根源九成出在 URI 设计上。结论先说:URI 只负责表示业务实体,操作意图全部交给 HTTP 动词表达,再把 DRF 的分页、过滤、认证这些机制用起来,接口就能做到"一次定义、长期稳定"。Python-100-Days 仓库里的 Day46-60/54.RESTful架构和DRF入门.md 到 Day46-60/55.RESTful架构和DRF进阶.md 正好覆盖了从架构原则到落地代码的全过程,本文按"先跑通、再拆原理、最后避坑"的路径带你过一遍。
接口返工的根源:先把资源想清楚
URI 该怎么设计,直接决定了接口会不会被前端反复吐槽。核心就一条:URI 指向资源本身,动作交给 HTTP 动词。以订单车间为例:
| 请求方法 | URI 路径 | 表达的动作 |
|---|---|---|
| GET | /orders/ | 拉取订单列表 |
| POST | /orders/ | 新建一笔订单 |
| GET | /orders/{id}/ | 查询单笔订单 |
| PUT | /orders/{id}/ | 全量覆盖订单 |
| PATCH | /orders/{id}/ | 只改订单里的部分字段 |
| DELETE | /orders/{id}/ | 取消订单 |
动词和 URI 的组合就能无歧义地表达意图,服务器无需记住任何客户端信息,这就是无状态。无状态不是抠细节,而是水平扩展的前提——流量涨了直接加节点,不用同步会话数据。
最快跑通路径:三步接入 DRF
要让一个 Django 项目提供 RESTful 接口,最少做三件事:装包、注册应用、给全局配置。
pip install djangorestframework在 settings.py 中把rest_framework加入INSTALLED_APPS,并追加全局配置:
REST_FRAMEWORK = { 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination', 'PAGE_SIZE': 10, }以书籍资源为例,一个序列化器加一个视图类再加一行路由就是最小闭环:
from rest_framework import serializers from rest_framework.viewsets import ModelViewSet from .models import Book class BookSerializer(serializers.ModelSerializer): class Meta: model = Book fields = ('id', 'title', 'author', 'price', 'stock') class BookViewSet(ModelViewSet): queryset = Book.objects.all() serializer_class = BookSerializer路由不用逐条手写,交给路由器批量生成:
from rest_framework.routers import DefaultRouter from .views import BookViewSet router = DefaultRouter() router.register('api/books', BookViewSet) urlpatterns = router.urls启动后直接访问接口地址,DRF 自带一个浏览器调试页,能直接发请求、看 JSON,前后端联调阶段非常省事。
机制拆解:DRF 替你省掉的三层代码
上一节几乎没写任何处理逻辑,原因藏在三层机制里。
Serializer:进出门都走它
序列化器看着是把模型实例变成 JSON 的出口,实际上它还是入口:POST 请求体先经过 Serializer 校验,类型不对、字段缺失、自定义规则不过关,一律拒收。
类视图:五个动作一次配齐
类视图(CBV)把 HTTP 动词的处理逻辑拆成了 Mixin,ModelViewSet一次性混入增、删、改、查五个能力。你只需声明两件事:数据从哪来(queryset)、数据怎么变(serializer_class)。代价是灵活性不如函数视图——需要复杂业务编排时,函数视图里想怎么写就怎么写,这是取舍不是缺陷。
JWT:把"登录态"搬进客户端
传统 session 把登录态存在服务端,多节点部署时状态同步很麻烦;token 方案恰好相反,身份标识交给浏览器本地存储,服务端对每次请求只做验签,天然无状态。JWT 是这套方案的事实标准,由头部、载荷、签名三段编码拼接而成:
- 头部:声明签名算法与令牌类型
- 载荷:存放用户 ID、过期时间等实际数据
- 签名:用服务端私钥对前两段做指纹,防止伪造
import jwt from datetime import datetime, timedelta from django.conf import settings payload = {'userid': user.id, 'exp': datetime.utcnow() + timedelta(hours=2)} token = jwt.encode(payload, settings.SECRET_KEY, algorithm='HS256').decode() data = jwt.decode(token, settings.SECRET_KEY, algorithms=['HS256'])前端拿到 token 后存入 localStorage,每次请求放进请求头;服务端验签不通过就统一回 401,前端据此跳回登录页。
常见坑与优化清单 ⚠️
跑通只是起点,下面这几件事能决定接口上线后稳不稳。
分页:别让列表接口裸奔
列表接口务必分页。页码分页之外,DRF 还内置游标分页(CursorPagination),客户端只能拿着上一页的游标往后翻,无法通过页码反推总数据量,对公开接口更友好。单个视图不想跟从全局配置时,给它单独指定一个pagination_class即可。
过滤与排序:把查询逻辑写进 URL
按状态、渠道筛选,按金额排序这类需求,交给django-filter配OrderingFilter,一行配置让前端直接用 URL 参数表达复杂查询:
class BookViewSet(ModelViewSet): filter_backends = [DjangoFilterBackend, OrderingFilter] filterset_fields = ['status', 'channel'] ordering_fields = ['amount', 'create_time']缓存:只给读操作开门
读多写少的列表接口挂上cache_page,数据库压力立降;但写操作千万别误伤进缓存,否则下单之后查到的还是旧数据。
JWT 的三件麻烦事
令牌一旦泄露就等同交出用户全部权限,有效期宁短勿长,敏感操作叠加短信二次验证;已签发的令牌在过期前无法主动作废,需要"踢人下线"就得引入黑名单存储;token 存浏览器,天然暴露在 XSS 面前,输出转义别偷懒。
文档:给前端一个稳定的合同
响应结构、状态码含义、参数位置在文档里定死再开发。仓库里的 Day91-100/94.网络API接口设计.md 有一份可直接套用的接口文档模板,错误码规划、参数表、示例响应一应俱全。
收束
RESTful 的骨架是"URI 表资源、动词表动作",DRF 的价值在于把序列化、校验、分页、路由这些重复劳动收敛成配置。想继续往前走的三个方向:接口版本控制策略、限流与熔断、Celery 异步任务处理——对应的延伸阅读都收在 Python-100-Days 仓库的 Day46-60 与 Day91-100 目录里。
【免费下载链接】Python-100-DaysPython - 100天从新手到大师项目地址: https://gitcode.com/GitHub_Trending/py/Python-100-Days
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考