Python API开发完整实战:用DRF从零搭建一套RESTful接口
【免费下载链接】Python-100-DaysPython - 100天从新手到大师项目地址: https://gitcode.com/GitHub_Trending/py/Python-100-Days
基于 Python-100-Days 课程,本文用一个"课程管理系统"的真实需求贯穿全程,走一遍 Python API 开发的完整动线:拆解需求、搭建 DRF RESTful 接口、设计认证、交付文档。读完你能带走一份可直接套用的接口开发模板,而不是零散的知识点。
需求拆解:把课程管理业务翻译成接口任务
当产品经理甩来一句"前端要展示课程列表,还要能增删改查"时,别急着敲代码,先把业务动作翻译成资源操作。REST 风格(Representational State Transfer,即"表现层状态转移")要求 URI 指向资源而不是动作——用GET /api/subjects/而不是GET /getSubjects,这样接口才见名知意、不随界面改版而失效。
| 业务需求 | 接口任务 | REST 风格定位 |
|---|---|---|
| 浏览课程列表 | 返回列表资源 | GET /api/subjects/ |
| 新建课程 | 创建资源 | POST /api/subjects/ |
| 修改课程 | 更新资源(全量/部分) | PUT或PATCH /api/subjects/{no}/ |
| 删除课程 | 移除资源 | DELETE /api/subjects/{no}/ |
| 查某课程的老师 | 子资源筛选 | GET /api/teachers/?sno=编号 |
拆解时建议同步确定三件事:哪些资源要暴露、每个资源支持哪几个 HTTP 动词、错误时返回什么状态码。这张清单就是后面所有工作的验收标准。
骨架搭建:DRF 安装与全局配置
当你新建好 Django 项目、模型也写完了,接下来要让它"会说 JSON"。直接用原生 Django 视图手搓 JSON 既繁琐又容易漏掉校验,而 djangorestframework(简称 DRF)把序列化、认证、权限、限流全部做成可配置项,这是选它而不是裸写视图的理由。
安装只需一条命令:
pip install djangorestframework注册应用并做全局配置。这里每个键都不是随意填的:SessionAuthentication服务于 Django 自带后台和浏览器调试页面,TokenAuthentication服务于移动端与跨域前端,两者并存才能覆盖全部调用方;默认权限设为IsAuthenticated,等于给自己上保险,避免某个新接口"裸奔"上线。
INSTALLED_APPS = [ # ... 'rest_framework', ] REST_FRAMEWORK = { 'PAGE_SIZE': 10, 'DEFAULT_AUTHENTICATION_CLASSES': [ 'rest_framework.authentication.SessionAuthentication', 'rest_framework.authentication.TokenAuthentication', ], 'DEFAULT_PERMISSION_CLASSES': [ 'rest_framework.permissions.IsAuthenticated', ], }数据流转:序列化与校验
当前端问"这条课程数据的 JSON 从哪来",答案是一条清晰的动线:数据库里的模型对象 → 序列化器转成字典 → 视图包成 JSON 响应;写操作的动线正好反过来:请求体 → 序列化器验证 → 落库。DRF 的序列化器(把 Python 对象和 JSON 互相翻译的类)是这条动线上的枢纽。
如果字段就是模型字段本身,继承ModelSerializer是性价比最高的选择,它会根据模型自动生成字段定义:
class SubjectSerializer(serializers.ModelSerializer): class Meta: model = Subject fields = '__all__'只有当你需要嵌套资源、只读计算字段或手动拼装结构时,才退回更底层的Serializer逐个声明字段——能少写一行是一行。
校验则是动线的"反向关卡"。以学员年龄为例,把规则写在validate_字段名方法里,非法数据会在入库前被拦下并统一返回 400:
def validate_age(self, value): if value < 18: raise serializers.ValidationError('年龄必须大于等于18岁') return value接口暴露:FBV 还是 CBV 的决策
当课程列表接口要上线,你会在两种写法之间犹豫:FBV(基于函数的视图)直白灵活,CBV(基于类的视图)复用性强。选择标准很简单——逻辑越标准,越该用 CBV;逻辑越特殊,越该用 FBV。
| 场景 | 推荐写法 | 理由 |
|---|---|---|
| 一次查询即返回、逻辑简单 | FBV | 函数即接口,断点调试方便 |
| 完整 CRUD 四件套 | ModelViewSet | 五个 mixin 已实现增删改查,几乎零代码 |
| 只读列表 + 筛选 | ListAPIView等泛型视图 | 比全量 ViewSet 少暴露写操作 |
先看 FBV 的最小形态,一个装饰器声明允许的动词,其余交给序列化器:
@api_view(['GET']) def subject_list(request): subjects = Subject.objects.order_by('no') serializer = SubjectSerializer(subjects, many=True) return Response(serializer.data)而课程管理这种标准 CRUD,ModelViewSet两行声明加一个路由器就完成全部五个接口的注册:
class SubjectViewSet(ModelViewSet): queryset = Subject.objects.all() serializer_class = SubjectSerializer # urls.py router = DefaultRouter() router.register('api/subjects', SubjectViewSet) urlpatterns += router.urlsDRF 还自带可浏览的接口页面,没写前端时也能直接发起请求、查看响应,联调前的自测全靠它。
安全加固:Session 与 JWT 的选型
当用户登录成功后发出下一次请求,无状态的 HTTP 协议让服务器认不出"这是谁",于是你需要在两种身份跟踪方案里做选择。
| 维度 | Session 方案 | JWT 方案 |
|---|---|---|
| 身份信息存放位置 | 服务器端 session 对象 | 客户端本地存储,请求头携带 |
| 服务器状态 | 有状态,扩容需同步 session | 无状态,加节点即可水平扩展 |
| 令牌撤销 | 删 session 即刻生效 | 过期前难以作废,需短有效期 + 黑名单 |
| 典型适用 | 同域 Web 站、Django admin | 移动端、跨域前后端分离 |
结论是:纯浏览器同域应用保留 Session 即可;一旦涉及移动端或多节点部署,选 JWT(JSON Web Token,由头部、载荷、签名三段编码拼接的令牌)。它的签名机制让伪造和篡改无处遁形,而无状态特性天然契合 REST 的水平扩展诉求。代价是令牌泄露风险,对策就是缩短有效期,敏感操作二次验证。
用 PyJWT(pip install pyjwt)生成与校验各只需几行:
token = jwt.encode( {'userid': user.id, 'exp': datetime.utcnow() + timedelta(days=1)}, settings.SECRET_KEY, algorithm='HS256', ) try: payload = jwt.decode(token, settings.SECRET_KEY, algorithms=['HS256']) except jwt.PyJWTError: raise AuthenticationFailed('无效的令牌或已过期')交付与协作:接口文档规范与测试要点
当前端拿到接口却找不到文档时,联调就会退化成"人肉传话"。一份合格的接口文档至少交代清楚:请求方法与 URL、每个参数的位置(路径/查询/请求头/消息体)、成功与失败的状态码约定。以"获取文章评论"为例:
GET/api/articles/{article-id}/comments/
| 参数 | 位置 | 必填 | 说明 |
|---|---|---|---|
| page | 查询参数 | 否 | 页码,默认 1 |
| key | 请求头 | 是 | 用户身份标识 |
{ "code": 10000, "message": "获取评论成功", "page": 1, "contents": [ {"userId": 1700095, "nickname": "王大锤", "content": "..."} ] }测试别只测"正常路径":401(未认证)、404(资源不存在)、400(参数非法)这三类异常状态码,才是线上事故的高发区。响应体里也建议杜绝裸null,从数据库字段设置默认值开始治理,前端强类型语言才不会踩坑。
踩坑与提速:分页、过滤、缓存问答
课程列表数据上万,前端加载卡顿怎么办?
全局配置默认分页器,让所有列表接口自动带上count、next、results:
REST_FRAMEWORK = { 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination', 'PAGE_SIZE': 10, }若不想暴露数据总量(页码分页会泄露这一点),换成CursorPagination游标分页即可。
前端要按条件筛选、排序,后端要写多少查询代码?
少量条件直接重写get_queryset从request.GET取值过滤;条件多了就上django-filter,声明式配置过滤字段:
class TeacherView(ListAPIView): serializer_class = TeacherSerializer filter_backends = [DjangoFilterBackend, OrderingFilter] filterset_fields = ['subject'] ordering_fields = ['no']热门课程接口被反复请求,数据库扛不住?
对读多写少的列表接口套一层缓存,15 分钟内的重复请求直接命中:
class SubjectViewSet(ModelViewSet): @method_decorator(cache_page(60 * 15)) def list(self, request, *args, **kwargs): return super().list(request, *args, **kwargs)一套 RESTful 接口从需求到交付,本质就是"资源定位 → 数据流转 → 身份验证 → 契约交付"这四步的循环。接下来可以深入的方向:API 版本控制与兼容策略、限流节流防刷、以及用 Celery 把耗时任务从请求线程里剥离出去。
【免费下载链接】Python-100-DaysPython - 100天从新手到大师项目地址: https://gitcode.com/GitHub_Trending/py/Python-100-Days
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考