news 2026/10/8 9:43:08

Django Rest Framework构建API的实现示例

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Django Rest Framework构建API的实现示例

前言


Django REST framework(通常简称 DRF)是 Django 生态里最主流的 REST API 框架。它不是 Django 自带的,而是一个独立的第三方包,要单独安装。这一点常被误解——很多人以为 Django 生来就能写 REST 接口,实际上不加 DRF 也完全可以手写接口,只是要自己处理序列化、内容协商、状态码、分页,很啰嗦。


另一个常见误解是「DRF 只有一种写法」。实际上它提供了三种粒度不同的视图:APIView(最原始)、泛型视图(针对单个模型的常用操作)、ViewSet+ 路由器(把一组相关操作打包)。新手常见的两种极端是:要么全部手写APIView,把 DRF 当普通 Django 用;要么一上来就ModelViewSet,却不清楚它到底暴露了哪几个端点、哪些该关掉。


本文用一个博客文章(Post)的例子,从序列化器到路由完整走一遍。示例代码以 Django 5.x / 6.x 搭配当前稳定版 DRF 为背景,DRF 的具体 API 以官方文档为准;Python 版本要求取决于你选的 Django 版本(如 Django 6.x 需要 Python 3.12 及以上)。


一、安装与最小配置


pip install djangorestframework

然后在settings.py里注册,并给一组全局默认值:


# settings.py
INSTALLED_APPS = [
# ... Django 自带应用
"rest_framework",
"blog", # 你自己的应用
]

REST_FRAMEWORK = {
"DEFAULT_AUTHENTICATION_CLASSES": [
"rest_framework.authentication.TokenAuthentication",
],
"DEFAULT_PERMISSION_CLASSES": [
"rest_framework.permissions.IsAuthenticatedOrReadOnly",
],
"DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.PageNumberPagination",
"PAGE_SIZE": 10,
}

两个要点:REST_FRAMEWORK是一个字典,键名全大写;分页要同时设置DEFAULT_PAGINATION_CLASS和PAGE_SIZE,因为两者的默认值都是None,只设一个不会生效。


二、被拆解的数据模型


# blog/models.py
from django.db import models


class Post(models.Model):
title = models.CharField(max_length=200)
body = models.TextField()
created = models.DateTimeField(auto_now_add=True)

def __str__(self):
return self.title

改完模型照例要python manage.py makemigrations blog再python manage.py migrate。


三、序列化器:模型与 JSON 之间的翻译层


序列化器(serializer)负责两件事:把模型实例变成可以返回的 JSON(序列化),把请求里的 JSON 变成经过校验的 Python 数据(反序列化)。


# blog/serializers.py
from rest_framework import serializers

from .models import Post


class PostSerializer(serializers.ModelSerializer):
class Meta:
model = Post
fields = ["id", "title", "body", "created"]
read_only_fields = ["created"] # 只读,不接受客户端传入

def validate_title(self, value):
# 针对单个字段的校验钩子:名字必须是 validate_字段名
if len(value.strip()) < 3:
raise serializers.ValidationError("标题至少 3 个字符")
return value

def validate(self, attrs):
# 跨字段校验:attrs 是已校验的字段字典
if attrs.get("title") == attrs.get("body"):
raise serializers.ValidationError("标题和正文不能一模一样")
return attrs

用ModelSerializer时,fields列表决定了哪些字段会被暴露。这里有个重要的安全习惯:永远显式列出fields,不要图省事写fields = "__all__"——数据库里的敏感字段(密码哈希、内部标记)会随着模型演进而自动泄露出去。


手动使用序列化器的流程:


# 适用于 DRF 当前稳定版
from blog.serializers import PostSerializer

# 反序列化:校验请求数据
ser = PostSerializer(data={"title": "第一篇", "body": "正文内容"})
ser.is_valid(raise_exception=True) # 校验失败直接抛 400
post = ser.save() # 调用 create()

# 序列化:把对象转成可返回的数据
print(PostSerializer(post).data)

is_valid()返回布尔值;加了raise_exception=True后,校验失败会直接抛出 DRF 的异常,由框架转成 HTTP 400,省去手写判断。校验通过的数据在ser.validated_data,错误信息在ser.errors。


四、视图的三种粒度




写法抽象程度适合



APIView最低非 CRUD 的特殊逻辑,完全自定义

泛型视图(ListCreateAPIView等)中针对单模型的常见操作

ViewSet(ModelViewSet)最高标准 CRUD,配合路由器自动生成 URL



最省事的是ModelViewSet。官方文档写明它提供.list()、.retrieve()、.create()、.update()、.partial_update()、.destroy()六个动作,也就是标准的「增删改查」全套。


# blog/views.py
from rest_framework import permissions, viewsets
from rest_framework.decorators import action
from rest_framework.response import Response

from .models import Post
from .serializers import PostSerializer


class PostViewSet(viewsets.ModelViewSet):
queryset = Post.objects.all().order_by("-created")
serializer_class = PostSerializer
permission_classes = [permissions.IsAuthenticatedOrReadOnly]

@action(detail=False, methods=["get"])
def recent(self, request):
"""额外动作:GET /posts/recent/,只返回最新 5 篇。"""
qs = self.filter_queryset(self.get_queryset())[:5]
serializer = self.get_serializer(qs, many=True)
return Response(serializer.data)

@action用来给 ViewSet 加「不标准」的端点。两个关键参数:detail=True表示针对单个对象(URL 里带主键),detail=False表示针对整个集合;methods指定允许的 HTTP 方法。注册后,recent会挂到/posts/recent/上。


官方文档有一条提醒值得记住:不要对@action方法用.as_view()——那会绕过路由器的设置,导致permission_classes之类的动作配置被忽略。


五、路由:交给路由器自动生成


# blog/urls.py
from django.urls import include, path
from rest_framework.routers import DefaultRouter

from .views import PostViewSet

router = DefaultRouter()
router.register(r"posts", PostViewSet, basename="post")

urlpatterns = [
path("", include(router.urls)),
]

# 根 urls.py
from django.contrib import admin
from django.urls import include, path
from rest_framework.authtoken import views as token_views

urlpatterns = [
path("admin/", admin.site.urls),
path("api/", include("blog.urls")),
path("api-token-auth/", token_views.obtain_auth_token),
]

DefaultRouter自动生成的端点大致是:




HTTP 方法URL动作



GET/api/posts/列表

POST/api/posts/新建

GET/api/posts/{id}/详情

PUT/api/posts/{id}/整体更新

PATCH/api/posts/{id}/局部更新

DELETE/api/posts/{id}/删除

GET/api/posts/recent/自定义动作



register方法支持可选的basename参数。当 ViewSet 没有定义queryset属性时,必须显式给basename,否则路由器无法推断 URL 名称。


六、认证与权限


DRF 把「认证」(你是谁)和「权限」(你能不能做)分成两层,可以分别配置。


REST_FRAMEWORK = {
"DEFAULT_AUTHENTICATION_CLASSES": [
"rest_framework.authentication.TokenAuthentication",
],
"DEFAULT_PERMISSION_CLASSES": [
"rest_framework.permissions.IsAuthenticated",
],
}

用TokenAuthentication需要额外做两件事:把rest_framework.authtoken加进INSTALLED_APPS,并执行python manage.py migrate(该应用自带数据库迁移)。之后客户端用请求头发送令牌:


Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b

默认权限类很关键。DEFAULT_PERMISSION_CLASSES不设置时,DRF 默认是AllowAny——任何人都能读写你的接口。新项目上线前务必确认这一项已改成IsAuthenticated或IsAuthenticatedOrReadOnly。


官方文档还有一条硬性要求:在传输层使用TokenAuthentication时,必须保证 API 只通过 HTTPS 暴露,否则令牌等于明文裸奔。


获得令牌可以用内置视图(把用户名密码 POST 上去):


from rest_framework.authtoken import views as token_views

urlpatterns += [
path("api-token-auth/", token_views.obtain_auth_token),
]

常见坑点


1. 忘了把rest_framework加进INSTALLED_APPS


❌ 直接from rest_framework import serializers后页面报配置错误。 ✅ 先pip install djangorestframework,再加进INSTALLED_APPS。


2.fields = "__all__"埋下泄露隐患


❌class Meta: model = User; fields = "__all__",密码哈希也被暴露。 ✅ 显式列出fields = ["id", "username", "email"]。


3. 以为 DRF 默认要求登录


❌ 不配DEFAULT_PERMISSION_CLASSES,接口对全网开放还不自知。 ✅ 显式设置权限类;默认是AllowAny。


4. ViewSet 没有queryset也没给basename


❌router.register(r"posts", PostViewSet)抛路由命名错误。 ✅ 补上basename="post",或给 ViewSet 定义queryset。


5. 只设了PAGE_SIZE却没设分页类


❌ 以为配个PAGE_SIZE就自动分页,结果返回全量数据。 ✅DEFAULT_PAGINATION_CLASS和PAGE_SIZE两个都要设。


6. 用HttpResponse返回 DRF 的数据


❌ 在 DRF 视图里写return HttpResponse(serializer.data),收到一个str的字典。 ✅ 用rest_framework.response.Response。


7. 忘记raise_exception=True


❌if ser.is_valid(): ...校验失败时静默跳过,客户端收到 200。 ✅ser.is_valid(raise_exception=True),失败自动返回 400。


8. 用 TokenAuthentication 却跑在 HTTP 上


❌ 明文 HTTP 传Authorization: Token ...,令牌可被截获。 ✅ 生产必须走 HTTPS;或用更适合浏览器的会话认证。


总结




组件作用关键设置



ModelSerializer模型与 JSON 互转显式列fields,用validate_*校验

ModelViewSet一套 CRUD 动作提供 list/retrieve/create/update/destroy

@action加自定义端点detail决定是否带主键

DefaultRouter自动生成 URL无queryset时必须给basename

认证 / 权限分层控制访问默认AllowAny,上线要改

分页控制返回数量分页类与PAGE_SIZE同时设



DRF 的核心价值是把「序列化 + 校验 + 标准 CRUD + 路由」这套重复劳动模板化。上手时按Serializer → ViewSet → Router的顺序理解,再回头记牢两件事:fields要显式列,权限默认是开放。做到这两点,你已经能写出既简洁又不至于把数据泄露出去的 API 了。





版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/8 9:39:51

kqueue与epoll对比:Coursebook附录IO多路复用完整指南

kqueue与epoll对比&#xff1a;Coursebook附录IO多路复用完整指南 【免费下载链接】coursebook Open Source Introductory Systems Programming Textbook for the University of Illinois 项目地址: https://gitcode.com/GitHub_Trending/co/coursebook &#x1f4da; 想…

作者头像 李华
网站建设 2026/10/8 9:39:35

OpenClaw升级实战:skill机制重构与rosclaw ROS 2集成指南

周红伟&#xff1a;【OpenClaw】升级指南老周这篇文章我反复读了两遍&#xff0c;又在自己两台机器上各滚了一遍升级流程&#xff0c;才敢坐下来写这份实操记录。OpenClaw 这项目我从第一个公开版本就在跟进&#xff0c;中间换过部署方式、踩过不少坑&#xff0c;这次升级到新版…

作者头像 李华
网站建设 2026/10/8 9:39:02

Vera Rubin与Groq 3:AI算力基础设施的两条技术路线解析

这轮 AI 浪潮最容易被低估的&#xff0c;其实是"计算基础设施"这几个字。模型架构的进步大家看得见&#xff0c;GPU 的性能数字也经常冲上热搜&#xff0c;但你真把一个万卡集群从设计到交付跑起来&#xff0c;就会明白&#xff1a;算力不是买来插上电就能用的&#…

作者头像 李华
网站建设 2026/10/8 9:38:05

企业大模型网关搭建与自动化编程落地实践解析

企业大模型网关怎么搭、自动化编程怎么落地&#xff0c;我把这套实践逻辑拆开讲 这两年"企业大模型落地"这个词被讲得太多了&#xff0c;但实际去做的团队都知道&#xff0c;真正的难点从来不是"把模型部署起来&#xff0c;能对话"&#xff0c;而是怎么让业…

作者头像 李华
网站建设 2026/10/8 9:38:04

OpenClaw定时任务配置实战:从cron到systemd的自动化指南

只要你把 OpenClaw 从“问一句答一句”的聊天窗口里解放出来&#xff0c;第一件事大概率就是给它安排定时任务。OpenClaw 这类开源 AI 代理框架&#xff0c;最实用的能力之一就是把重复性、周期性、必须准点完成的事情交给配置去跑&#xff0c;让我能用一份指令加一个时间点&am…

作者头像 李华