Django REST framework 框架是一个用于构建Web API 的强大而又灵活的工具。
通常简称为DRF框架 或 REST framework。
特点
提供了定义序列化器Serializer的方法,可以快速根据 Django ORM 或者其它库自动序列化/反序列化;
”序列化(Serialization)是一种将数据结构或对象的状态转换成一种可以存储或传输的形式的过程。通过序列化,可以将复杂的数据结构(如对象、数组、字典等)转化为字符串或二进制格式,以便将其保存到文件、数据库中,或者通过网络在不同的系统之间传递。序列化的逆过程称为反序列化(Deserialization),即将序列化后的数据还原为原始的数据结构或对象。“
提供了丰富的类视图、Mixin扩展类,简化视图的编写;
丰富的定制层级:函数视图、类视图、视图集合到自动生成 API,满足各种需要;
多种身份认证和权限认证方式的支持;
内置了限流系统;
直观的 API web 界面;
可扩展性,插件丰富
环境安装与配置
导包
pip install djangorestframework
添加rest_framework应用
INSTALLED_APPS = [
...
'rest_framework',
]
DRF基础操作流程:
1. 创建序列化器
在 booktest
应用中创建 serializers.py
文件,用来保存该应用的序列化器。
我们可以创建一个 BookInfoSerializer
序列化器来处理图书数据的序列化与反序列化。
from rest_framework import serializers
from .models import BookInfo
class BookInfoSerializer(serializers.ModelSerializer):
"""图书数据序列化器"""
class Meta:
model = BookInfo # 指定该序列化器对应的模型
fields = '__all__' # 序列化该模型的所有字段
model
指定了序列化器操作的数据来源,即模型类BookInfo
。fields
用来指定哪些字段需要被序列化,'__all__'
表示将模型的所有字段都包含在内。
2. 编写视图
在 booktest
应用的 views.py
文件中,我们可以创建一个视图 BookInfoViewSet
,这是一个视图集(ViewSet)。
from rest_framework.viewsets import ModelViewSet
from .serializers import BookInfoSerializer
from .models import BookInfo
class BookInfoViewSet(ModelViewSet):
queryset = BookInfo.objects.all() # 指定视图集使用的查询集
serializer_class = BookInfoSerializer # 指定该视图集使用的序列化器
queryset
指定该视图集使用的查询集,这里返回BookInfo
模型的所有数据。serializer_class
指定该视图集使用的序列化器,负责将数据格式化为JSON格式,或者将接收到的JSON数据反序列化为模型对象。
3. 定义路由
在 booktest
应用的 urls.py
中定义路由。
from . import views
from rest_framework.routers import DefaultRouter
urlpatterns = [
# 其他路由
]
router = DefaultRouter() # 创建一个默认路由器,用于自动处理视图集的路由
router.register(r'books', views.BookInfoViewSet) # 注册视图集到路由器
urlpatterns += router.urls # 将路由器中的路由信息添加到Django的路由列表中
路由器 DefaultRouter
会自动根据视图集生成路由,例如访问 /books/
会返回图书数据。
Serializer 序列化器的基本使用
1. 创建序列化器对象
定义好序列化器类之后,可以通过以下方式创建序列化器对象:
serializer = BookInfoSerializer(instance=book) # 用于序列化对象
Serializer
类的构造方法是:
Serializer(instance=None, data=empty, **kwargs)
instance
用于传入需要序列化的模型实例。data
用于传入需要反序列化的JSON数据。context
参数用于传递额外的数据(如请求对象),可以在序列化器内部使用。
例如:
serializer = BookInfoSerializer(book, context={'request': request})
2. 基本操作
例如,查询一个图书对象并进行序列化:
from booktest.models import BookInfo
book = BookInfo.objects.get(id=2) # 获取一个图书对象
接下来,创建序列化器并获取序列化后的数据:
from booktest.serializers import BookInfoSerializer
serializer = BookInfoSerializer(book) # 创建序列化器对象
print(serializer.data) # 输出序列化后的数据
输出结果类似:
{
"id": 2,
"btitle": "天龙八部",
"bpub_date": "1986-07-24",
"bread": 36,
"bcomment": 40,
"image": null
}
如果需要序列化多个对象(如查询集),可以通过设置 many=True
来进行:
book_qs = BookInfo.objects.all() # 获取所有图书
serializer = BookInfoSerializer(book_qs, many=True) # 序列化多个对象
print(serializer.data)
输出结果类似:
[
{
"id": 2,
"btitle": "天龙八部",
"bpub_date": "1986-07-24",
"bread": 36,
"bcomment": 40,
"image": null
},
{
"id": 3,
"btitle": "笑傲江湖",
"bpub_date": "1990-05-01",
"bread": 25,
"bcomment": 35,
"image": null
}
]
3. 关联对象嵌套序列化
如果模型中包含关联字段(如外键),我们可以使用以下方式对关联对象进行序列化。
(1) PrimaryKeyRelatedField
该字段将关联对象序列化为主键值。
hbook = serializers.PrimaryKeyRelatedField(label='图书', read_only=True)
或者,如果需要反序列化时进行验证,可以使用 queryset
参数:
hbook = serializers.PrimaryKeyRelatedField(label='图书', queryset=BookInfo.objects.all())
(2) StringRelatedField
将关联对象序列化为其 __str__
方法的返回值(通常为一个人类可读的名称)。
hbook = serializers.StringRelatedField(label='图书')
(3) HyperlinkedRelatedField
该字段将关联对象序列化为一个超链接(URL),指向该对象的详细页面。
hbook = serializers.HyperlinkedRelatedField(label='图书', read_only=True, view_name='books-detail')
view_name
必须指定为视图的名称,以便 DRF 可以找到对应的路由并生成URL。
(4) SlugRelatedField
该字段将关联对象序列化为指定字段的数据。
hbook = serializers.SlugRelatedField(label='图书', read_only=True, slug_field='bpub_date')
(5) 使用自定义序列化器
我们还可以通过自定义序列化器来序列化关联对象。
hbook = BookInfoSerializer()
(6) 重写 to_representation
方法
通过重写 to_representation
方法,我们可以自定义如何序列化字段数据。比如,我们可以自定义一个关联字段来输出不同格式的数据:
class BookRelateField(serializers.RelatedField):
"""自定义图书字段的序列化"""
def to_representation(self, value):
return 'Book: %d %s' % (value.id, value.btitle)
hbook = BookRelateField(read_only=True)
4. 使用 many=True
参数
如果某个字段关联多个对象(例如,一本书有多个作者),我们只需要在声明关联字段时加上 many=True
参数:
hbooks = serializers.PrimaryKeyRelatedField(queryset=BookInfo.objects.all(), many=True)
这种方式适用于任何需要表示多个关联对象的场景。
——————————————2.13———————————————
反序列化使用
1.验证
使用序列化器进行反序列化时,需要对数据进行验证后,才能获取验证成功的数据或保存成模型类对象。
在获取反序列化的数据前,必须调用is_valid()方法进行验证,验证成功返回True,否则返回False。
验证失败,可以通过序列化器对象的errors属性获取错误信息,返回字典,包含了字段和字段的错误。如果是非字段错误,可以通过修改REST framework配置中的NON_FIELD_ERRORS_KEY来控制错误字典中的键名。
验证成功,可以通过序列化器对象的validated_data属性获取数据。
在定义序列化器时,指明每个字段的序列化类型和选项参数,本身就是一种验证行为。
is_valid()方法还可以在验证失败时抛出异常serializers.ValidationError,可以通过传递raise_exception=True参数开启,REST framework接收到此异常,会向前端返回HTTP 400 Bad Request响应。
验证失败并获取错误信息的示例
当验证失败时,可以通过 serializer.errors
获取错误信息。错误信息以字典形式返回,包含了字段和字段的错误。
from rest_framework import serializers
# 定义序列化器
class UserSerializer(serializers.Serializer):
username = serializers.CharField(max_length=10)
age = serializers.IntegerField(min_value=18)
# 模拟传入的数据
data = {
"username": "this_is_too_long_for_the_field", # 超过最大长度
"age": 15 # 未达到最小年龄
}
# 序列化器实例
serializer = UserSerializer(data=data)
# 验证数据
if not serializer.is_valid():
print("验证失败,错误信息:")
print(serializer.errors)
# 输出错误信息:
# 验证失败,错误信息:
# {
# "username": ["Ensure this field has no more than 10 characters."],
# "age": ["Ensure this value is greater than or equal to 18."]
# }
验证成功并获取验证后的数据
当验证成功时,可以通过 serializer.validated_data
获取验证后的数据。
data = {
"username": "validuser",
"age": 25
}
serializer = UserSerializer(data=data)
if serializer.is_valid():
print("验证成功!")
print("验证后的数据:", serializer.validated_data)
# 输出:
# 验证成功!
# 验证后的数据: {'username': 'validuser', 'age': 25}
使用 raise_exception=True
抛出异常
当调用 is_valid()
时,传递 raise_exception=True
参数,会在验证失败时抛出 serializers.ValidationError
异常。对于 REST framework,这种异常会自动返回 HTTP 400 Bad Request 响应。
from rest_framework.exceptions import ValidationError
data = {
"username": "invalid_user_name_because_it_is_too_long",
"age": 15
}
serializer = UserSerializer(data=data)
try:
serializer.is_valid(raise_exception=True)
except serializers.ValidationError as e:
print("捕获到 ValidationError 异常!")
print(e)
# 输出:
# 捕获到 ValidationError 异常!
# {'username': ['Ensure this field has no more than 10 characters.'], 'age': ['Ensure this value is greater than or equal to 18.']}
修改 NON_FIELD_ERRORS_KEY
如果需要自定义非字段错误的键名,可以在 REST framework 的全局配置中设置 NON_FIELD_ERRORS_KEY
。
修改配置:
在 settings.py
中:
REST_FRAMEWORK = {
'NON_FIELD_ERRORS_KEY': 'non_field_errors'
}
示例:
class CustomSerializer(serializers.Serializer):
name = serializers.CharField()
password = serializers.CharField()
def validate(self, data):
if data['name'] == data['password']:
raise serializers.ValidationError("用户名和密码不能相同") # 这是一个非字段错误
return data
data = {
"name": "admin",
"password": "admin"
}
serializer = CustomSerializer(data=data)
if not serializer.is_valid():
print(serializer.errors)
# 输出:
# {'non_field_errors': ['用户名和密码不能相同']
2.保存
如果在验证成功后,想要基于validated_data完成数据对象的创建,可以通过实现create()和update()两个方法来实现。
create()
方法:当调用save()
时,如果序列化器在初始化时没有传递instance
,则会调用create()
方法,用于创建新的对象。update()
方法:当调用save()
时,如果序列化器在初始化时传递了instance
,则会调用update()
方法,用于更新现有对象。
示例代码:
from rest_framework import serializers
# 定义一个简单的模型类
class User:
def __init__(self, username, age):
self.username = username
self.age = age
# 定义序列化器
class UserSerializer(serializers.Serializer):
username = serializers.CharField(max_length=10)
age = serializers.IntegerField(min_value=18)
# create 方法
def create(self, validated_data):
return User(**validated_data) # 创建新的对象
# update 方法
def update(self, instance, validated_data):
instance.username = validated_data.get('username', instance.username)
instance.age = validated_data.get('age', instance.age)
return instance
# 使用 create() 创建对象
data = {"username": "testuser", "age": 25}
serializer = UserSerializer(data=data)
if serializer.is_valid():
user = serializer.save() # 调用 create() 方法
print("创建的用户对象:", user.__dict__)
# 使用 update() 更新对象
existing_user = User(username="olduser", age=30)
update_data = {"username": "updateduser"}
serializer = UserSerializer(instance=existing_user, data=update_data, partial=True)
if serializer.is_valid():
updated_user = serializer.save() # 调用 update() 方法
print("更新后的用户对象:", updated_user.__dict__)
2. 在 save()
时传递额外数据
可以在调用 save()
方法时传递额外的数据,这些数据会被传递到 create()
或 update()
方法的 validated_data
参数中。
示例代码:
class UserSerializer(serializers.Serializer):
username = serializers.CharField(max_length=10)
age = serializers.IntegerField(min_value=18)
def create(self, validated_data):
# 获取额外传递的数据
extra_info = validated_data.pop('extra_info', None)
print("额外信息:", extra_info)
return User(**validated_data)
data = {"username": "newuser", "age": 20}
serializer = UserSerializer(data=data)
if serializer.is_valid():
user = serializer.save(extra_info="This is extra data") # 传递额外的数据
print("创建的用户对象:", user.__dict__)
3. 使用 partial=True
进行部分字段更新
默认情况下,序列化器会对所有 required=True
的字段进行验证。如果只想更新部分字段,可以在创建序列化器时传递 partial=True
,允许跳过未提供的字段的验证。
示例代码:
# 使用 partial=True 进行部分字段更新
existing_user = User(username="partialuser", age=40)
update_data = {"age": 45} # 仅更新部分字段
serializer = UserSerializer(instance=existing_user, data=update_data, partial=True)
if serializer.is_valid():
updated_user = serializer.save()
print("部分更新后的用户对象:", updated_user.__dict__)
模型类序列化器ModelSerializer
ModelSerializer
是 Django REST Framework (DRF) 提供的一个基于 Django 模型的序列化器。它可以让你快速创建一个与模型类相关联的序列化器,而无需手动为每个字段定义逻辑。
定义一个 ModelSerializer
很简单,继承自 serializers.ModelSerializer
并定义 Meta
类即可。
from rest_framework import serializers
from myapp.models import MyModel
class MyModelSerializer(serializers.ModelSerializer):
class Meta:
model = MyModel # 指定对应的模型类
fields = '__all__' # 或指定具体字段列表
2. 指定字段
1) 使用 fields
明确字段
使用 fields
属性可以指定序列化器要包含的字段,可以使用 __all__
表示包含模型的所有字段,也可以指定具体字段。
class MyModelSerializer(serializers.ModelSerializer):
class Meta:
model = MyModel
fields = ['id', 'name', 'description'] # 指定具体字段
2) 使用 exclude
排除字段
使用 exclude
属性可以指定要排除的字段,fields
和 exclude
不能同时使用。
class MyModelSerializer(serializers.ModelSerializer):
class Meta:
model = MyModel
exclude = ['created_at', 'updated_at'] # 排除某些字段
3) 使用 depth
生成嵌套表示
默认情况下,ModelSerializer
使用主键(id
)作为关联字段。如果需要嵌套表示,可以使用 depth
属性。depth
是一个整数,用来指明嵌套的层级数量。
示例:
假设有两个模型:
class Category(models.Model):
name = models.CharField(max_length=255)
class Product(models.Model):
name = models.CharField(max_length=255)
category = models.ForeignKey(Category, on_delete=models.CASCADE)
序列化器如下:
class ProductSerializer(serializers.ModelSerializer):
class Meta:
model = Product
fields = '__all__'
depth = 1 # 嵌套层级为1
序列化后的数据可能是:
{
"id": 1,
"name": "Product A",
"category": {
"id": 2,
"name": "Category B"
}
}
4) 显式指定字段
如果需要对某个字段进行特殊处理,可以在序列化器中显式定义字段。例如:
class MyModelSerializer(serializers.ModelSerializer):
custom_field = serializers.CharField(source='get_custom_field_display')
class Meta:
model = MyModel
fields = ['id', 'name', 'custom_field']
5) 指定只读字段
可以使用 read_only_fields
属性指定只读字段,这些字段仅用于序列化输出,不能用于反序列化输入。
class MyModelSerializer(serializers.ModelSerializer):
class Meta:
model = MyModel
fields = '__all__'
read_only_fields = ['id', 'created_at'] # 指定只读字段
3. 添加额外参数
在某些情况下,我们可能需要为序列化器的字段添加额外的选项或修改原有的字段行为,可以通过 extra_kwargs
实现。
class MyModelSerializer(serializers.ModelSerializer):
class Meta:
model = MyModel
fields = '__all__'
extra_kwargs = {
'name': {'required': True, 'validators': []}, # 设置 name 字段为必填,并取消其验证器
'description': {'max_length': 200}, # 设置 description 字段的最大长度
}
整合示例
from rest_framework import serializers
from myapp.models import Category, Product
class ProductSerializer(serializers.ModelSerializer):
category_name = serializers.CharField(source='category.name', read_only=True)
class Meta:
model = Product
fields = ['id', 'name', 'price', 'category', 'category_name']
read_only_fields = ['id']
extra_kwargs = {
'price': {'required': True, 'min_value': 0}, # 价格字段必须非负
'category': {'write_only': True}, # 分类字段仅用于写入(反序列化)
}
通过 ModelSerializer
,可以快速为模型类创建功能齐全的序列化器,同时保留灵活性以满足自定义需求。
视图
1.Request
在Django REST框架中,request
对象已经不再是Django默认的HttpRequest
对象,而是由REST框架提供的扩展版本,即Request
对象。这个Request
对象继承了HttpRequest
,并加入了更多功能来处理API请求的数据。
当前端发起请求时,REST框架会根据请求的Content-Type
(比如JSON、表单等)自动解析请求体中的数据。解析后,这些数据会以类字典对象的形式存储在Request
对象中。这样,无论前端发送的数据格式是什么,我们都能通过统一的方式访问这些数据。
常用的属性:
request.data
这是请求体的数据。它的作用类似于Django中的request.POST
和request.FILES
,但是它有以下特点:
- 包含解析后的文件和非文件数据。
- 支持多种请求方式,如
POST
、PUT
、PATCH
等。 - 通过REST框架的解析器(
parsers
)解析,不仅支持表单数据,还支持JSON数据。
request.query_params
这个属性类似于Django中的request.GET
,用于获取请求URL中的查询参数(即?key=value
部分)。request.query_params
只是REST框架对request.GET
的改进,名字更准确一些。
简而言之,request.data
用于访问请求体的数据(比如表单数据或JSON),而request.query_params
用于获取URL中的查询参数。这样,不论前端发送何种格式的数据,都可以统一通过这些属性来访问和处理请求数据。
2.Response
在 Django REST framework 中,Response
是一个用来构造 HTTP 响应的类。它会根据前端的实际需求自动将 Python 数据转换为适合的格式(比如 JSON、HTML 等)。这个转换过程是通过 渲染器(Renderer) 来完成的。
响应的渲染机制
通过前端请求中的 Accept
请求头,REST framework 会选择最佳的渲染器将数据转换为对应格式。如果前端未指定 Accept
,系统会使用默认的渲染器来处理响应数据。默认渲染器可以在项目的配置中修改:
REST_FRAMEWORK = {
'DEFAULT_RENDERER_CLASSES': (
'rest_framework.renderers.JSONRenderer', # JSON 渲染器(默认返回 JSON 格式数据)
'rest_framework.renderers.BrowsableAPIRenderer', # 可浏览的 API 页面渲染器
)
}
构造响应
Response
类的构造方法如下:
Response(data, status=None, template_name=None, headers=None, content_type=None)
这里的 data
参数,只需要传入 Python 内置类型的数据(例如字典、列表、字符串等),而不需要是已经处理好的(渲染后的)数据。REST framework 会根据请求头和配置自动进行渲染。如果传入的是复杂结构(例如 Django 的模型对象),需要先通过 序列化器(Serializer) 转换为适合的格式(通常为字典)后再传递给 data
。
参数说明:
- data: 要返回的响应数据,必须是序列化后的 Python 内置类型(如字典、列表等)。
- status: HTTP 状态码,默认为
200
(成功)。 - template_name: 如果渲染器是
HTMLRenderer
,可指定使用的模板名称。 - headers: 一个字典,指定响应头信息。
- content_type: 响应的
Content-Type
,通常无需指定,REST framework 会自动根据渲染数据类型生成。
常用属性
.data
这个属性是传给Response
的原始数据,还没有经过渲染器处理(也就是“尚未转换为最终响应格式”的数据)。例如,传入一个字典,它就是你未加工的字典。.status_code
响应的 HTTP 状态码,例如200
表示成功,404
表示资源未找到。.content
这是最终处理完成的响应数据。它会经过渲染器的转换(例如转换为 JSON 格式字符串),最终成为 HTTP 响应体中返回的内容。
示例代码:简单演示
from rest_framework.response import Response
from rest_framework.views import APIView
class MyApiView(APIView):
def get(self, request):
# 原始数据
data = {
'message': 'Hello, World!',
'status': 'success'
}
# 返回响应
return Response(data, status=200)
在上面的例子中:
.data
是{'message': 'Hello, World!', 'status': 'success'}
,即传入的原始数据。.status_code
是200
,表示成功。.content
是{"message":"Hello, World!","status":"success"}
,即渲染器将数据转换为 JSON 格式的字符串。
只需要传入 Python 的原始数据,框架会根据前端的需求和配置自动完成数据格式的转换和响应构造,大大简化了开发流程。
3.状态码
为了更方便地设置 HTTP 状态码,框架在 rest_framework.status
模块中定义了一系列常用的状态码常量。这些常量是标准的 HTTP 状态码表示,使用这些常量可以让代码更加清晰易读,也有助于减少拼写错误。
HTTP 状态码根据用途分为 5 大类:
信息响应 – 1xx
这些状态码表示请求已接收,服务器需要进一步操作。
HTTP_100_CONTINUE
:客户端可以继续发送请求。HTTP_101_SWITCHING_PROTOCOLS
:服务器同意切换协议。
成功 – 2xx
这些状态码表示操作成功完成,服务器返回所需的结果。
HTTP_200_OK
:请求成功,返回结果。HTTP_201_CREATED
:资源已成功创建。HTTP_202_ACCEPTED
:请求已接受,但尚未处理完成。HTTP_204_NO_CONTENT
:请求成功,但无返回内容。- 其他状态码如
HTTP_205_RESET_CONTENT
和HTTP_206_PARTIAL_CONTENT
更加少用。
示例:
from rest_framework.response import Response
from rest_framework.status import HTTP_200_OK, HTTP_201_CREATED
def my_view(request):
data = {"message": "Resource created successfully"}
return Response(data, status=HTTP_201_CREATED)
重定向 – 3xx
这些状态码告诉客户端,资源已被移动,需要使用新的 URI 访问。
HTTP_301_MOVED_PERMANENTLY
:资源永久移动到新位置。HTTP_302_FOUND
:资源临时移动到新位置。HTTP_303_SEE_OTHER
:重定向到其他 URI。HTTP_304_NOT_MODIFIED
:资源未修改,客户端可使用缓存版本。
示例:
from rest_framework.response import Response
from rest_framework.status import HTTP_302_FOUND
def my_redirect_view(request):
return Response({"location": "https://example.com"}, status=HTTP_302_FOUND)
客户端错误 – 4xx
这些状态码表示客户端的请求存在问题,服务器无法处理。
- 常见错误:
HTTP_400_BAD_REQUEST
:请求参数错误。HTTP_401_UNAUTHORIZED
:未授权,需登录后才能访问。HTTP_403_FORBIDDEN
:权限不足,禁止访问。HTTP_404_NOT_FOUND
:资源未找到。HTTP_405_METHOD_NOT_ALLOWED
:请求方法不被允许(如 GET 请求调用了需要 POST 的接口)。- 其他错误:
HTTP_429_TOO_MANY_REQUESTS
:请求过多(例如 API 限流)。HTTP_422_UNPROCESSABLE_ENTITY
:请求格式正确,但语义错误(通常与数据校验相关)。
示例:
from rest_framework.response import Response
from rest_framework.status import HTTP_400_BAD_REQUEST, HTTP_404_NOT_FOUND
def my_error_view(request):
return Response({"error": "Bad Request"}, status=HTTP_400_BAD_REQUEST)
def not_found_view(request):
return Response({"error": "Resource not found"}, status=HTTP_404_NOT_FOUND)
服务器错误 – 5xx
这些状态码表示服务器在处理请求时发生了错误。
HTTP_500_INTERNAL_SERVER_ERROR
:服务器内部错误,无法完成请求。HTTP_501_NOT_IMPLEMENTED
:所请求的功能尚未实现。HTTP_503_SERVICE_UNAVAILABLE
:服务器当前无法处理请求(例如维护中)。HTTP_504_GATEWAY_TIMEOUT
:服务器未能及时响应请求。
示例:
from rest_framework.response import Response
from rest_framework.status import HTTP_500_INTERNAL_SERVER_ERROR
def server_error_view(request):
return Response({"error": "Internal Server Error"}, status=HTTP_500_INTERNAL_SERVER_ERROR)
总结
将状态码分为 5 类后,开发者可以根据业务场景快速选择合适的状态码。使用 rest_framework.status
提供的常量可以让代码更清晰,减少硬编码状态码带来的混乱。
完整状态码常量的分类和用途如下:
1xx 信息响应
HTTP_100_CONTINUE
HTTP_101_SWITCHING_PROTOCOLS
2xx 成功
HTTP_200_OK
HTTP_201_CREATED
HTTP_204_NO_CONTENT
3xx 重定向
HTTP_301_MOVED_PERMANENTLY
HTTP_302_FOUND
HTTP_304_NOT_MODIFIED
4xx 客户端错误
HTTP_400_BAD_REQUEST
HTTP_401_UNAUTHORIZED
HTTP_403_FORBIDDEN
HTTP_404_NOT_FOUND
HTTP_429_TOO_MANY_REQUESTS
5xx 服务器错误
HTTP_500_INTERNAL_SERVER_ERROR
HTTP_503_SERVICE_UNAVAILABLE
视图
在 Django REST framework 中,视图是处理 HTTP 请求并返回响应的核心组件。REST framework 提供了很多类和方法来简化视图的编写,下面将详细介绍几种常见的视图基类和扩展类,并配上通俗易懂的代码示例。
1. 两个基类视图
1)APIView
APIView
是 Django REST framework 提供的所有视图的基类,继承自 Django 的 View
类。
与 Django 的普通 View
的区别:
- 在
APIView
中,传入视图方法的请求对象是 REST framework 的Request
对象,而不是 Django 的HttpRequest
对象。 - 视图方法可以返回
Response
对象,响应的数据会自动根据前端的需求进行格式化(例如 JSON 格式)。 - 如果发生
APIException
异常,它会被自动捕获并转换为合适的响应信息。 - 在调用
dispatch()
方法前,框架会自动进行身份认证、权限检查和流量控制等操作。
常用属性:
authentication_classes
:指定身份认证类。permission_classes
:指定权限控制类。throttle_classes
:指定流量控制类。
示例:
from rest_framework.views import APIView
from rest_framework.response import Response
from .models import BookInfo
from .serializers import BookInfoSerializer
class BookListView(APIView):
def get(self, request):
# 获取所有书籍数据
books = BookInfo.objects.all()
serializer = BookInfoSerializer(books, many=True)
return Response(serializer.data)
在这个例子中,BookListView
继承自 APIView
,并通过 get()
方法返回书籍列表。
2)GenericAPIView
GenericAPIView
继承自 APIView
,增加了对列表视图和详情视图常用方法的支持,通常与 Mixin
类一起使用。
常用属性:
queryset
:列表视图查询的数据集。serializer_class
:使用的序列化器类。
常用方法:
get_queryset()
:获取查询集的方法。get_serializer_class()
:获取序列化器类的方法。
示例:
from rest_framework.generics import GenericAPIView
from rest_framework.response import Response
from .models import BookInfo
from .serializers import BookInfoSerializer
class BookDetailView(GenericAPIView):
queryset = BookInfo.objects.all()
serializer_class = BookInfoSerializer
def get(self, request, pk):
# 获取单本书籍数据
book = self.get_object() # 获取单一数据对象
serializer = self.get_serializer(book) # 序列化数据
return Response(serializer.data)
这里的 BookDetailView
继承自 GenericAPIView
,通过 get()
方法返回某本书籍的详细信息。
2. 五个常用扩展类
扩展类(Mixin)是为了简化常见的操作(如创建、更新、删除等),它们可以与 GenericAPIView
一起使用,提供快速实现常见视图功能的方法。
1)ListModelMixin
用于快速实现列表视图的功能。提供 list()
方法,返回符合过滤和分页条件的列表。
示例:
from rest_framework import mixins
from rest_framework import generics
from .models import BookInfo
from .serializers import BookInfoSerializer
class BookListView(mixins.ListModelMixin, generics.GenericAPIView):
queryset = BookInfo.objects.all()
serializer_class = BookInfoSerializer
def get(self, request):
return self.list(request) # 使用 ListModelMixin 中的 list 方法
2)CreateModelMixin
用于创建资源的视图。提供 create()
方法,成功时返回 201 状态码。
示例:
from rest_framework import mixins
from rest_framework import generics
from .models import BookInfo
from .serializers import BookInfoSerializer
class BookCreateView(mixins.CreateModelMixin, generics.GenericAPIView):
queryset = BookInfo.objects.all()
serializer_class = BookInfoSerializer
def post(self, request):
return self.create(request) # 使用 CreateModelMixin 中的 create 方法
3)RetrieveModelMixin
用于返回单个对象的详情视图。提供 retrieve()
方法。
示例:
from rest_framework import mixins
from rest_framework import generics
from .models import BookInfo
from .serializers import BookInfoSerializer
class BookDetailView(mixins.RetrieveModelMixin, generics.GenericAPIView):
queryset = BookInfo.objects.all()
serializer_class = BookInfoSerializer
def get(self, request, pk):
return self.retrieve(request, pk) # 使用 RetrieveModelMixin 中的 retrieve 方法
4)UpdateModelMixin
用于更新资源的视图。提供 update()
和 partial_update()
方法。
示例:
from rest_framework import mixins
from rest_framework import generics
from .models import BookInfo
from .serializers import BookInfoSerializer
class BookUpdateView(mixins.UpdateModelMixin, generics.GenericAPIView):
queryset = BookInfo.objects.all()
serializer_class = BookInfoSerializer
def put(self, request, pk):
return self.update(request, pk) # 使用 UpdateModelMixin 中的 update 方法
5)DestroyModelMixin
用于删除资源的视图。提供 destroy()
方法,成功时返回 204 状态码。
示例:
from rest_framework import mixins
from rest_framework import generics
from .models import BookInfo
from .serializers import BookInfoSerializer
class BookDeleteView(mixins.DestroyModelMixin, generics.GenericAPIView):
queryset = BookInfo.objects.all()
serializer_class = BookInfoSerializer
def delete(self, request, pk):
return self.destroy(request, pk) # 使用 DestroyModelMixin 中的 destroy 方法
3. 几个常用的子类视图
这些子类视图已经将常见的视图功能封装好了,开发者只需要继承并配置即可实现相应的功能。
1)CreateAPIView
提供 post()
方法,快速实现资源创建功能。
2)ListAPIView
提供 get()
方法,快速实现列表视图功能。
3)RetrieveAPIView
提供 get()
方法,快速实现单个对象的详情视图功能。
4)DestroyAPIView
提供 delete()
方法,快速实现资源删除功能。
5)UpdateAPIView
提供 put()
和 patch()
方法,快速实现资源更新功能。
6)RetrieveUpdateAPIView
提供 get()
、put()
和 patch()
方法,实现获取和更新资源的功能。
7)RetrieveUpdateDestroyAPIView
提供 get()
、put()
、patch()
和 delete()
方法,实现资源的获取、更新和删除功能。
视图集 (ViewSet)
视图集(ViewSet) 是一个用来处理一组相关动作(如列出数据、创建数据、更新数据等)的大类。通过视图集,你可以将这些逻辑放在一个类里,而不需要分别为每个动作编写单独的视图函数。
常见的 ViewSet 动作:
list()
:提供一组数据(如获取所有书籍)。retrieve()
:提供单个数据(如获取某本书的详细信息)。create()
:创建新数据(如添加一本新书)。update()
:更新数据(如修改一本书的信息)。destroy()
:删除数据(如删除一本书)。
在 ViewSet
中,不需要显式地定义 get()
、post()
等方法,而是定义这些动作的方法(list()
、create()
等)。当你调用 as_view()
时,框架会自动将请求与具体的动作方法(action)对应起来。
示例:
from rest_framework import viewsets
from rest_framework.response import Response
class BookInfoViewSet(viewsets.ViewSet):
def list(self, request):
# 返回所有书籍
books = BookInfo.objects.all()
return Response({'books': books})
def retrieve(self, request, pk=None):
# 返回单本书籍详情
book = BookInfo.objects.get(pk=pk)
return Response({'book': book})
当我们定义了这样的 BookInfoViewSet
类后,路由的配置会将 HTTP 请求与相应的动作方法(如 list()
、retrieve()
)关联起来:
设置路由:
from django.urls import path
from .views import BookInfoViewSet
urlpatterns = [
path('books/', BookInfoViewSet.as_view({'get': 'list'})), # 获取书籍列表
path('books/<int:pk>/', BookInfoViewSet.as_view({'get': 'retrieve'})), # 获取单本书籍
]
action 属性
在视图集中,action
属性可以帮助你判断当前请求执行的是哪个动作方法。例如,你可以根据 action
来决定使用哪个序列化器:
def get_serializer_class(self):
if self.action == 'create':
return BookCreateSerializer
else:
return BookListSerializer
在这个例子中,如果 action
是 create
,则使用 BookCreateSerializer
,否则使用 BookListSerializer
。
常用视图集父类
1)ViewSet
ViewSet
是最基本的视图集类,它继承自 APIView
。使用时需要自己定义具体的动作方法(如 list()
、create()
等)。
2)GenericViewSet
GenericViewSet
继承自 GenericAPIView
,提供了常用的功能方法(如 get_queryset()
和 get_serializer_class()
),简化了视图集的开发,特别适合用于列表视图和详情视图。
3)ModelViewSet
ModelViewSet
继承自 GenericViewSet
,并且包含了 ListModelMixin
、RetrieveModelMixin
、CreateModelMixin
、UpdateModelMixin
、DestroyModelMixin
,因此它提供了对模型的增删改查(CRUD)操作,简化了视图集的实现。
4)ReadOnlyModelViewSet
ReadOnlyModelViewSet
继承自 GenericViewSet
,并包含了 ListModelMixin
和 RetrieveModelMixin
,适用于只需要读取数据的视图集。
定义附加自定义动作
除了框架默认的动作(如 list()
、retrieve()
),你还可以在视图集中定义自定义的动作(action)。这些自定义动作通过 @action
装饰器来实现。
自定义动作
methods
:指定此动作支持的 HTTP 请求方法(如GET
、POST
)。detail
:指定动作是否是针对某个单独的对象(True
表示针对某个对象,False
表示不针对对象)。
示例:
from rest_framework.decorators import action
from rest_framework import viewsets
from rest_framework.response import Response
class BookInfoViewSet(viewsets.GenericViewSet, mixins.ListModelMixin, mixins.RetrieveModelMixin):
queryset = BookInfo.objects.all()
serializer_class = BookInfoSerializer
@action(methods=['get'], detail=False)
def latest(self, request):
# 返回最新添加的书籍
latest_books = BookInfo.objects.order_by('-created_at')[:5]
return Response({'latest_books': latest_books})
@action(methods=['put'], detail=True)
def read(self, request, pk=None):
# 标记某本书为已读
book = self.get_object()
book.read = True
book.save()
return Response({'book': BookInfoSerializer(book).data})
这个视图集类将会有两个自定义的动作:
latest
:返回最新的 5 本书。read
:更新某本书的状态为“已读”。
形成的路由:
^books/latest/$ name: book-latest
^books/{pk}/read/$ name: book-read
路由 (Routers)
对于视图集(ViewSet),Django REST framework 提供了 Router
来自动生成视图集的路由配置,减少了手动设置路由的工作。
两种常用的 Router:
- SimpleRouter:适用于大多数常见的视图集需求。
- DefaultRouter:与
SimpleRouter
类似,唯一的区别是它会自动为我们添加一个根路由(API 根路径)。
使用 SimpleRouter 注册视图集:
from rest_framework import routers
from .views import BookInfoViewSet
router = routers.SimpleRouter()
router.register(r'books', BookInfoViewSet, basename='book')
urlpatterns = [
path('', include(router.urls)),
]
这段代码会生成两个路由:
^books/$ name: book-list
^books/{pk}/$ name: book-detail
包含自定义动作的路由:
class BookInfoViewSet(viewsets.GenericViewSet, mixins.ListModelMixin, mixins.RetrieveModelMixin):
queryset = BookInfo.objects.all()
serializer_class = BookInfoSerializer
@action(methods=['get'], detail=False)
def latest(self, request):
latest_books = BookInfo.objects.order_by('-created_at')[:5]
return Response({'latest_books': latest_books})
@action(methods=['put'], detail=True)
def read(self, request, pk=None):
book = self.get_object()
book.read = True
book.save()
return Response({'book': BookInfoSerializer(book).data})
生成的路由:
^books/latest/$ name: book-latest
^books/{pk}/read/$ name: book-read
其他功能
1. 认证 Authentication
认证用于验证用户身份。可以通过全局设置或视图级别设置来启用不同的认证方式。
全局配置
在配置文件 settings.py
中,通过 DEFAULT_AUTHENTICATION_CLASSES
设置全局默认的认证方案:
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.BasicAuthentication', # 基本认证
'rest_framework.authentication.SessionAuthentication', # 会话认证
)
}
视图级别配置
可以为某个视图单独指定认证方式,覆盖全局配置:
from rest_framework.authentication import SessionAuthentication, BasicAuthentication
from rest_framework.views import APIView
class ExampleView(APIView):
authentication_classes = (SessionAuthentication, BasicAuthentication) # 指定认证
...
认证失败的返回值
- 401 Unauthorized: 用户未认证。
- 403 Permission Denied: 用户已认证,但无权限访问。
2. 权限 Permissions
权限用于控制用户能否访问视图或具体数据对象。
全局配置
可以通过 DEFAULT_PERMISSION_CLASSES
设置全局权限:
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticated', # 仅允许已认证用户访问
)
}
默认权限
如果未设置,默认权限为允许所有访问:
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.AllowAny', # 允许所有用户访问
)
视图级别配置
在视图中可以通过 permission_classes
指定权限:
from rest_framework.permissions import IsAuthenticated
from rest_framework.views import APIView
class ExampleView(APIView):
permission_classes = (IsAuthenticated,) # 仅允许已认证用户访问
...
内置权限
AllowAny
: 允许所有用户访问。IsAuthenticated
: 仅允许已认证用户访问。IsAdminUser
: 仅允许管理员用户访问。IsAuthenticatedOrReadOnly
: 已认证用户可进行写操作,未认证用户只能读(GET请求)。
自定义权限
可以通过继承 BasePermission
类创建自定义权限:
from rest_framework.permissions import BasePermission
class MyPermission(BasePermission):
def has_object_permission(self, request, view, obj):
"""自定义对象级权限:禁止访问所有对象"""
return False
# 应用于视图:
class BookInfoViewSet(ModelViewSet):
queryset = BookInfo.objects.all()
serializer_class = BookInfoSerializer
permission_classes = [IsAuthenticated, MyPermission] # 同时使用多个权限
3. 限流 Throttling
限流限制接口的访问频次,保护服务器免受过高流量影响。
全局配置
在 settings.py
中配置全局限流策略:
REST_FRAMEWORK = {
'DEFAULT_THROTTLE_CLASSES': (
'rest_framework.throttling.AnonRateThrottle', # 匿名用户限流
'rest_framework.throttling.UserRateThrottle' # 认证用户限流
),
'DEFAULT_THROTTLE_RATES': {
'anon': '100/day', # 匿名用户每天限制 100 次
'user': '1000/day' # 认证用户每天限制 1000 次
}
}
支持的时间周期:second
, minute
, hour
, day
。
视图级别配置
可以为某个视图单独设置限流策略:
from rest_framework.throttling import UserRateThrottle
from rest_framework.views import APIView
class ExampleView(APIView):
throttle_classes = (UserRateThrottle,) # 限制认证用户的请求频次
...
内置限流类
AnonRateThrottle
限制匿名用户访问频次,使用 IP 地址区分用户。
- 配置:
DEFAULT_THROTTLE_RATES['anon']
UserRateThrottle
限制已认证用户访问频次,使用用户 ID 区分。
- 配置:
DEFAULT_THROTTLE_RATES['user']
ScopedRateThrottle
针对每个视图的频次限制,适用于复杂场景。 示例:
class ContactListView(APIView):
throttle_scope = 'contacts' # 限流范围
...
class UploadView(APIView):
throttle_scope = 'uploads'
...
REST_FRAMEWORK = {
'DEFAULT_THROTTLE_CLASSES': (
'rest_framework.throttling.ScopedRateThrottle',
),
'DEFAULT_THROTTLE_RATES': {
'contacts': '1000/day', # 联系人接口每天限制 1000 次
'uploads': '20/day' # 上传接口每天限制 20 次
}
}
4. 过滤 Filtering
通过字段过滤列表数据。
安装依赖
pip install django-filter
配置
注册 django_filters
应用并启用过滤后端:
INSTALLED_APPS = [
...
'django_filters',
]
REST_FRAMEWORK = {
'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',)
}
视图中设置过滤字段
指定可过滤的字段:
class BookListView(ListAPIView):
queryset = BookInfo.objects.all()
serializer_class = BookInfoSerializer
filter_fields = ('btitle', 'bread') # 指定可过滤的字段
# 示例请求:127.0.0.1:8000/books/?btitle=西游记
5. 排序 Ordering
通过指定字段排序列表数据。
使用方法
在视图中使用 OrderingFilter
:
from rest_framework.filters import OrderingFilter
class BookListView(ListAPIView):
queryset = BookInfo.objects.all()
serializer_class = BookInfoSerializer
filter_backends = [OrderingFilter]
ordering_fields = ('id', 'bread', 'bpub_date') # 可选排序字段
# 示例请求:127.0.0.1:8000/books/?ordering=-bread (按浏览量降序)
6. 分页 Pagination
分页将数据分块返回以提高性能。
全局配置
在 settings.py
中设置默认的分页器:
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 100 # 每页返回数据量
}
自定义分页类
可以通过继承分页类自定义分页逻辑:
from rest_framework.pagination import PageNumberPagination
class LargeResultsSetPagination(PageNumberPagination):
page_size = 1000 # 每页默认数量
page_size_query_param = 'page_size' # 前端可动态指定每页数量
max_page_size = 10000 # 每页最大限制
class BookListView(ListAPIView):
queryset = BookInfo.objects.all()
serializer_class = BookInfoSerializer
pagination_class = LargeResultsSetPagination
关闭分页
如果某个视图不需要分页:
pagination_class = None
分页方式
PageNumberPagination
- 使用页码分页,默认参数:
page_query_param
: 页码参数(默认page
)。page_size_query_param
: 每页数据量参数(默认None
)。
- 示例请求:
127.0.0.1:8000/books/?page=1&page_size=2
LimitOffsetPagination
- 使用限制和偏移量分页,参数:
limit
: 每页数据量。offset
: 起始偏移量。
- 示例请求:
127.0.0.1:8000/books/?offset=3&limit=2
from rest_framework.pagination import LimitOffsetPagination
class BookListView(ListAPIView):
queryset = BookInfo.objects.all()
serializer_class = BookInfoSerializer
pagination_class = LimitOffsetPagination
版本管理 Versioning
版本管理允许我们为 API 设置版本号,方便维护和升级。
如何启用版本管理
要启用版本管理,在配置文件 settings.py
中设置:
REST_FRAMEWORK = {
'DEFAULT_VERSIONING_CLASS': 'rest_framework.versioning.NamespaceVersioning'
}
可选配置项
DEFAULT_VERSION
: 默认版本号(如未指定版本)。默认值为None
。ALLOWED_VERSIONS
: 允许的版本号列表,防止非法版本请求。VERSION_PARAM
: 客户端传递版本号的参数名称,默认是"version"
。
获取版本号
在代码中,可以通过 request.version
获取客户端请求的版本号:
def get(self, request, *args, **kwargs):
version = request.version # 获取请求的版本号
return Response({"version": version})
支持的版本管理方式
1. AcceptHeaderVersioning
:通过请求头传递版本号
客户端在 Accept
请求头中指定版本号:
GET /bookings/ HTTP/1.1
Host: example.com
Accept: application/json; version=1.0
在配置文件中启用:
REST_FRAMEWORK = {
'DEFAULT_VERSIONING_CLASS': 'rest_framework.versioning.AcceptHeaderVersioning'
}
2. URLPathVersioning
:通过 URL 路径指定版本号
客户端通过 URL 中的路径携带版本号:
urlpatterns = [
url(r'^(?P<version>(v1|v2))/bookings/$', bookings_list, name='bookings-list'),
url(r'^(?P<version>(v1|v2))/bookings/(?P<pk>[0-9]+)/$', bookings_detail, name='bookings-detail'),
]
示例请求:
GET /v1/bookings/ HTTP/1.1
Host: example.com
3. NamespaceVersioning
:通过命名空间指定版本号
使用命名空间为每个版本的 URL 定义路由:
# bookings/urls.py
urlpatterns = [
url(r'^$', bookings_list, name='bookings-list'),
url(r'^(?P<pk>[0-9]+)/$', bookings_detail, name='bookings-detail'),
]
# urls.py
urlpatterns = [
url(r'^v1/bookings/', include('bookings.urls', namespace='v1')),
url(r'^v2/bookings/', include('bookings.urls', namespace='v2')),
]
示例请求:
GET /v1/bookings/ HTTP/1.1
4. HostNameVersioning
:通过主机域名区分版本
使用不同的域名来区分版本号:
示例请求:
GET /bookings/ HTTP/1.1
Host: v1.example.com
在配置文件中启用:
REST_FRAMEWORK = {
'DEFAULT_VERSIONING_CLASS': 'rest_framework.versioning.HostNameVersioning'
}
5. QueryParameterVersioning
:通过查询字符串传递版本号
客户端通过查询参数表示版本号:
示例请求:
GET /something/?version=1.0 HTTP/1.1
在配置文件中启用:
REST_FRAMEWORK = {
'DEFAULT_VERSIONING_CLASS': 'rest_framework.versioning.QueryParameterVersioning',
'VERSION_PARAM': 'version', # 参数名可自定义
}
异常处理 Exceptions
Django REST framework 提供了异常处理机制,支持自定义处理。
自定义异常处理
通过自定义函数覆盖默认异常处理逻辑:
from rest_framework.views import exception_handler
def custom_exception_handler(exc, context):
# 调用 DRF 默认的异常处理方法,生成标准响应
response = exception_handler(exc, context)
# 添加自定义的处理逻辑
if response is not None:
response.data['status_code'] = response.status_code # 返回状态码给前端
return response
在配置文件中指定自定义异常处理函数:
REST_FRAMEWORK = {
'EXCEPTION_HANDLER': 'my_project.my_app.utils.custom_exception_handler'
}
默认异常处理
如果未指定自定义处理,则使用 REST framework 的默认异常处理:
REST_FRAMEWORK = {
'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler'
}
常见异常
以下是 REST framework 提供的常见异常:
APIException
: 所有异常的基类。ParseError
: 数据解析错误。AuthenticationFailed
: 认证失败。NotAuthenticated
: 用户未认证。PermissionDenied
: 权限不足。NotFound
: 数据未找到。MethodNotAllowed
: 请求方法不支持。NotAcceptable
: 响应数据格式不被客户端接受。Throttled
: 超过访问频率限制。ValidationError
: 数据校验失败。
自动生成接口文档
REST framework 支持自动生成以网页形式展示的接口文档,方便开发者和前端查看。
步骤 1:安装依赖
接口文档依赖 coreapi
库,安装方法:
pip install coreapi
步骤 2:设置接口文档的路由
在主路由文件中为接口文档设置访问路径:
from rest_framework.documentation import include_docs_urls
urlpatterns = [
...
url(r'^docs/', include_docs_urls(title='My API Documentation')), # 自定义文档标题
]
步骤 3:定义视图中的文档说明
1)单一方法视图
为单一方法的视图定义文档说明:
class BookListView(generics.ListAPIView):
"""
返回所有图书信息.
"""
2)多方法视图
对于包含多个方法的视图,可以分开定义文档说明:
class BookListCreateView(generics.ListCreateAPIView):
"""
get:
返回所有图书信息.
post:
新建图书.
"""
3)视图集(ViewSet)
对于 ViewSet
类,同样可以为每个操作定义文档说明:
class BookInfoViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, GenericViewSet):
"""
list:
返回图书列表数据.
retrieve:
返回图书详情数据.
latest:
返回最新的图书数据.
read:
修改图书的阅读量.
"""
步骤 4:访问生成的接口文档
在浏览器中访问文档路径,例如 127.0.0.1:8000/docs/
,即可看到自动生成的接口文档。