Resquests(请求)
属性
.data
request.data 返回请求正文的解析内容。它包括所有解析的内容, 包括 文件或非文件 输入。
它支持解析除POST之外的HTTP方法的内容,这意味着你可以访问PUT和PATCH请求的内容。
它支持REST framework灵活的请求解析,而不仅仅支持表单数据。 例如,你可以以与处理传入表单数据相同的方式处理传入的JSON数据。
.query_params
request.query_params是request.GET的一个更准确的同义词。
为了让你的代码清晰明了, 我们建议使用 request.query_params 而不是Django标准的request.GET。这样做有助于保持代码库更加正确和明了——因为任何HTTP方法类型可能包括查询参数,而不仅仅是GET请求。
Response(响应)
Response 类使用的渲染器无法自行处理像 Django model 实例这样的复杂数据类型,因此你需要在创建 Response 对象之前将数据序列化为基本数据类型。(你可以使用 REST framework的== Serializer 类==来执行此类数据的序列化,或者使用你自定义的来序列化)
签名:
Response(data, status=None, template_name=None, headers=None, content_type=None)
参数:
data: response的数列化数据.
status: response的状态码。默认是200. 另行参阅 status codes.
template_name: HTMLRenderer 选择要使用的模板名称。
headers: A dictionary of HTTP headers to use in the response.
content_type: response的内容类型。通常由渲染器自行设置,由content negotiation确定,但是在某些情况下,你需要明确指定内容类型。
属性
.data
Request 对象的未渲染内容。
.status_code
HTTP 响应的数字状态吗。
.content
response的呈现内容。 .render() 方法必须先调用才能访问 .content 。
类视图
APIView:
APIView是DRF中的基本视图类,它继承自Django的View类,并添加了一些针对API设计的功能,例如请求解析、内容协商、认证和权限控制等。
它可以返回REST framework的Response,而不是Django的HttpRequest。视图会管理内容协议,给响应设置正确的渲染器。
当你使用APIView时,需要为每个HTTP方法(如GET、POST、PUT、DELETE等)定义一个单独的处理方法(如get()、post()、put()、delete()等)。APIView适用于处理较为复杂的业务逻辑,或者需要自定义处理方法的场景。
ViewSet:
ViewSet是DRF中的一个更高级别的视图抽象,它继承自APIView。
ViewSet将视图的操作方法(如list、create、retrieve、update、destroy等)与HTTP方法解耦,这意味着你可以在一个ViewSet中定义多个操作方法,并通过路由器(Routers)自动将这些操作方法映射到对应的HTTP方法和URL。ViewSet适用于处理标准的CRUD操作,可以简化视图和路由的定义。此外,ViewSet还支持动作(Actions),允许你为ViewSet添加自定义操作方法。
ViewSet 只是一种基于类的视图,它不提供任何方法处理程序(如 .get()或.post()),而是提供诸如 .list() 和 .create() 之类的操作。
ViewSet 的方法处理程序仅使用 .as_view() 方法绑定到完成视图的相应操作。
自带视图
def list(self, request):passdef create(self, request):passdef retrieve(self, request, pk=None):pass其中,retrieve是ViewSet中预定义的一个方法,它用于处理获取单个资源的请求。当你发送一个GET请求到一个具体的资源URL时
(例如:/api/items/1/),ViewSet会调用retrieve方法来处理这个请求。retrieve方法通常会接收两个参数:self和pk(主键)。它会根据pk从数据库中获取对应的资源实例,然后返回这个实例。
如果找不到对应的资源,retrieve方法会返回一个404错误。def update(self, request, pk=None):passdef partial_update(self, request, pk=None):passdef destroy(self, request, pk=None):pass
指定序列化器和查询集
在ViewSet中,需要指定序列化器和查询集。
# 定义了视图集将操作的基础查询集
queryset = User.objects.all()
# 序列化器,它定义了如何将User模型的实例转换为JSON格式,以及如何将JSON数据转换回User模型的实例。
serializer = UserSerializer(queryset, many=True)
路由注册
我们会用一个router来注册我们的viewset,让urlconf自动生成。
from myapp.views import UserViewSet
from rest_framework.routers import DefaultRouterrouter = DefaultRouter()
router.register(r'users', UserViewSet)
urlpatterns = router.urls
案例
from django.contrib.auth.models import User
from rest_framework import status
from rest_framework import viewsets
from rest_framework.decorators import detail_route, list_route
from rest_framework.response import Response
from myapp.serializers import UserSerializer, PasswordSerializerclass UserViewSet(viewsets.ModelViewSet):"""一个提供标准动作的 viewset"""queryset = User.objects.all()serializer_class = UserSerializer@detail_route(methods=['post'])def set_password(self, request, pk=None):user = self.get_object()serializer = PasswordSerializer(data=request.data)if serializer.is_valid():user.set_password(serializer.data['password'])user.save()return Response({'status': 'password set'})else:return Response(serializer.errors,status=status.HTTP_400_BAD_REQUEST)@list_route()def recent_users(self, request):recent_users = User.objects.all().order('-last_login')page = self.paginate_queryset(recent_users)if page is not None:serializer = self.get_serializer(page, many=True)return self.get_paginated_response(serializer.data)serializer = self.get_serializer(recent_users, many=True)return Response(serializer.data)
拓展:format
在ViewSet中,每个操作方法(如list、create、retrieve等)都可以包含一个format=None的关键字参数。这个参数的默认值是None,表示视图将根据客户端请求的Accept头部自动选择合适的数据格式。如果你的API需要支持格式后缀,那么务必在每个操作方法中包含这个参数。
例如,以下请求将返回JSON格式的数据:
GET /api/items/1.json
而以下请求将返回XML格式的数据:
GET /api/items/1.xml
当你在ViewSet中定义操作方法时,可以根据需要处理format参数。但通常情况下,Django REST framework会自动处理内容协商和序列化,你不需要在操作方法中显式处理这个参数。
拓展:固定视图
如果我们需要,我们可以将这个viewset绑定到两个单独的视图,像这样:
user_list = UserViewSet.as_view({'get': 'list'})
user_detail = UserViewSet.as_view({'get': 'retrieve'})
自定义视图
如果你有需要被路由到的特别方法,你可以使用 @detail_route 或 @list_route 装饰器将它们标记为需要路由。
@detail_route 装饰器在其URL模式中包含 pk 用于需要单个实例的方法。The @list_route 装饰器用于对对象列表进行操作的方法。
装饰器可以另外获取为路由视图设置的额外参数。例如…
@detail_route(methods=['post'], permission_classes=[IsAdminOrIsSelf])
def set_password(self, request, pk=None):...
这些装饰器将默认路由 GET 请求,但也可以通过使用 methods 参数接受其他 HTTP 方法。例如:
@detail_route(methods=['post', 'delete'])
def unset_password(self, request, pk=None):...
这两个新动作将在 urls ^users/{pk}/set_password/$
和^users/{pk}/unset_password/$
上可用。
DRF中的返回的Response、HttpResponse和JsonResponse有什么区别?
Response:这是DRF特有的响应对象,主要用于返回API请求的结果。Response对象可以自动处理多种内容类型(如JSON、XML等),并根据客户端请求的Accept头部选择合适的内容类型。Response对象还可以与DRF的序列化器(Serializers)一起使用,以自动序列化和反序列化数据。此外,Response对象还支持更丰富的状态码和错误处理。
HttpResponse:这是Django中的一个基本响应对象,用于返回HTTP响应。HttpResponse对象默认的内容类型是"text/html",适用于返回HTML内容。如果需要返回其他内容类型,需要手动设置。HttpResponse对象通常用于处理非API的请求,如网页渲染等。
JsonResponse:这是Django中的一个特殊的HttpResponse对象,专门用于返回JSON数据。JsonResponse对象的内容类型默认为"application/json"。当你需要返回JSON格式的数据时,可以使用JsonResponse,它会自动将Python字典或列表序列化为JSON字符串。需要注意的是,JsonResponse不支持序列化Django模型实例或查询集,这时需要手动序列化数据。
Router(路由器)
SimpleRouter
SimpleRouter是一个基础的路由器,它为视图集自动生成标准的CRUD操作的URL路由。这些路由包括:
列表视图(list):GET //
详情视图(detail):GET //{pk}/
创建视图(create):POST //
更新视图(update):PUT //{pk}/
部分更新视图(partial_update):PATCH //{pk}/
删除视图(destroy):DELETE //{pk}/
这里的是在注册视图集时指定的URL前缀,{pk}是对象的主键。
DefaultRouter(更推荐)
DefaultRouter继承自SimpleRouter,因此它提供了SimpleRouter的所有路由,同时还添加了一个默认的API根视图。这个根视图返回一个包含所有列表视图的超链接的响应,通常用于API的入口点。
Renderer(渲染器)
渲染器(Renderer)是Django REST framework中用于将数据转换为特定格式的组件。渲染器的作用是将服务器返回的原始数据(如Python字典、列表等)序列化为客户端可以接收的格式(如JSON、XML等)。渲染器会根据客户端请求的Accept头部或URL中的格式后缀自动选择合适的内容类型。
Django REST framework内置了多种渲染器,如JSONRenderer、XMLRenderer、HTMLRenderer等。你可以在项目设置中通过REST_FRAMEWORK设置来配置默认的渲染器,也可以在视图中通过renderer_classes属性来为特定视图指定渲染器。例如:
python
复制代码
REST_FRAMEWORK = {
‘DEFAULT_RENDERER_CLASSES’: [
‘rest_framework.renderers.JSONRenderer’,
‘rest_framework.renderers.XMLRenderer’,
],
}
在Response对象中,渲染器的作用是将传入的data参数序列化为合适的格式。需要注意的是,渲染器无法处理复杂的数据类型,如Django模型实例。在这种情况下,你需要使用序列化器(Serializer)先将数据序列化为基本数据类型(如字典、列表等),然后再创建Response对象。
例如,你可以使用Django REST framework的序列化器将模型实例序列化为字典:
python
复制代码
from rest_framework import serializers
from rest_framework.response import Response
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ‘all’
user = User.objects.get(pk=1)
serialized_user = UserSerializer(user).data
return Response(serialized_user)
总之,渲染器是Django REST framework中用于将数据转换为特定格式的组件,它负责将视图返回的数据序列化为客户端可以接收的格式。在使用Response对象时,需要确保传入的数据已经序列化为基本数据类型。
Serializers(序列化器)
序列化器的主要功能包括:
- 序列化:将模型实例或其他数据转换为Python字典,然后可以被渲染成JSON或其他格式。
- 反序列化:将传入的数据(如JSON)解析为Python数据类型,进行验证,并创建或更新模型实例。
- 验证:提供数据验证逻辑,确保传入的数据符合预期格式和规则。
假设你有一个Django模型User,你想要创建一个序列化器来处理用户数据的序列化和反序列化。
首先,定义你的模型(如果还没有定义):
from django.db import modelsclass User(models.Model):username = models.CharField(max_length=100)email = models.EmailField()is_active = models.BooleanField(default=True)
然后,创建一个序列化器:
from rest_framework import serializers
from .models import Userclass UserSerializer(serializers.ModelSerializer):class Meta:model = Userfields = ['id', 'username', 'email', 'is_active']
在这个UserSerializer中,我们继承了serializers.ModelSerializer,这是一个快捷的序列化器,它自动根据模型字段生成序列化器字段。在Meta类中,我们指定了要包含在序列化中的模型和字段。
序列化对象
现在,你可以在视图中使用这个序列化器来序列化用户数据:
from django.http import JsonResponse
from .models import User
from .serializers import UserSerializerdef user_list(request):users = User.objects.all()serializer = UserSerializer(users, many=True)return JsonResponse(serializer.data, safe=False)
在这个视图中,我们查询了所有的用户,然后使用UserSerializer来序列化这些用户数据。many=True参数告诉序列化器我们正在序列化一个对象列表而不是单个对象。最后,我们将序列化后的数据返回为JSON响应。
反序列化对象
同样,如果你想要反序列化传入的数据并创建一个新的用户实例,你可以这样做:
from django.views.decorators.csrf import csrf_exempt
from django.http import JsonResponse
from rest_framework.parsers import JSONParser
from .models import User
from .serializers import UserSerializer@csrf_exempt
def user_create(request):if request.method == 'POST':data = JSONParser().parse(request)serializer = UserSerializer(data=data)if serializer.is_valid():serializer.save()return JsonResponse(serializer.data, status=201)return JsonResponse(serializer.errors, status=400)
在这个视图中,我们首先解析了传入的JSON数据,然后使用UserSerializer来反序列化数据。我们检查数据是否有效,如果有效,我们保存新的用户实例,并返回新创建的用户数据。如果数据无效,我们返回一个包含错误信息的JSON响应。
注意,反序列化多个对象默认支持多个对象的创建,但是不支持多个对象的更新。
利用序列化器创建相应对象
如果我们希望能够返回基于验证数据的完整对象实例,我们需要实现其中一个或全部实现.create()和update()方法。例如:
class CommentSerializer(serializers.Serializer):email = serializers.EmailField()content = serializers.CharField(max_length=200)created = serializers.DateTimeField()def create(self, validated_data):return Comment(**validated_data)def update(self, instance, validated_data):instance.email = validated_data.get('email', instance.email)instance.content = validated_data.get('content', instance.content)instance.created = validated_data.get('created', instance.created)return instance
然后再调用.save()方法,即可创建一个数据验证过的对象实例。
comment = serializer.save()
注意,如果只实现了create方法,那么每次创建一个对象都是不同的地址。
如果只实现了update()方法,那么在调用serializer.save()方法时,将会更新现有的Comment对象而不是创建新的对象。所以在调用serializer.save()方法时,如果没有传递实例参数(instance),将会引发一个TypeError异常。因为在没有实例参数的情况下,无法确定要更新哪个对象。
保存到数据库里
我们如果想要的话,可以在外部将用.save创建的对象保存到数据库,这称为手动保存。
serializer = CommentSerializer(data=request.data)
if serializer.is_valid():comment = serializer.save()Comment.objects.create(comment)
但是我们也可以在create和update方法里,就确保这些对象会保存到数据库里。这称为自动保存。
def create(self, validated_data):return Comment.objects.create(**validated_data)def update(self, instance, validated_data):instance.email = validated_data.get('email', instance.email)instance.content = validated_data.get('content', instance.content)instance.created = validated_data.get('created', instance.created)instance.save()return instance
创建实例时注入其他属性数据
直接在.save()时添加其他关键字参数就可
serializer.save(owner=request.user)
验证
is_valid()
反序列化数据的时候,你始终需要先调用is_valid()方法,然后再尝试去访问经过验证的数据或保存对象实例。.is_valid()方法使用可选的raise_exception标志,如果存在验证错误将会抛出一个serializers.ValidationError异常。这些异常由REST framework提供的默认异常处理程序自动处理,默认情况下将返回HTTP 400 Bad Request响应。
意思就是
- serializer.is_valid():默认情况下,当调用serializer.is_valid()方法时,如果数据验证失败,它将返回一个布尔值False,并将错误信息存储在serializer.errors属性中。您可以通过检查serializer.errors来获取验证错误的详细信息。
- serializer.is_valid(raise_exception=True):当您将raise_exception参数设置为True时,如果数据验证失败,它将引发一个ValidationError异常。这意味着您可以使用异常处理机制来处理验证错误,而不需要手动检查serializer.errors。
is_valid()方法底层会依次执行以下步骤:
- 调用run_validation()方法,该方法会对输入数据进行验证,并返回验证后的数据。
- 调用validate()方法,该方法会在验证通过后执行自定义的验证逻辑。
- 如果验证通过,is_valid()方法返回True,否则返回False。
run_validation()
run_validation()方法会尝试在以下情况下进行类型转换:
-
字符串类型转换为其他类型:当字段声明为IntegerField、FloatField、DecimalField、BooleanField等数值类型时,如果输入数据是字符串类型,run_validation()方法会尝试将其转换为相应的数值类型。
-
数值类型转换为字符串类型:当字段声明为CharField、EmailField、URLField等字符串类型时,如果输入数据是数值类型,run_validation()方法会尝试将其转换为字符串类型。
-
字符串类型转换为日期/时间类型:当字段声明为DateField、DateTimeField等日期/时间类型时,如果输入数据是字符串类型,run_validation()方法会尝试将其转换为相应的日期/时间类型。
validate(),重写以达到自定义验证方法
示例:
from rest_framework import serializersclass EventSerializer(serializers.Serializer):description = serializers.CharField(max_length=100)start = serializers.DateTimeField()finish = serializers.DateTimeField()def validate(self, data):"""Check that the start is before the stop."""if data['start'] > data['finish']:raise serializers.ValidationError("finish must occur after start")return data
自定义某个字段的验证方法
自定义的validate_<field_name>方法应该返回一个验证过的数据或者抛出一个serializers.ValidationError异常。
当然,如果在序列化器中声明<field_name>的时候带有required=False参数,字段不被包含的时候这个验证步骤就不会执行。
from rest_framework import serializersclass BlogPostSerializer(serializers.Serializer):title = serializers.CharField(max_length=100)content = serializers.CharField()def validate_title(self, value):"""Check that the blog post is about Django."""if 'django' not in value.lower():raise serializers.ValidationError("Blog post is not about Django")return value
在多个序列化器中重复使用相同的验证器
共享验证器实例
在这个例子中,我们定义了一个UniqueRoomBookingValidator类,它接受一个查询集、日期字段和房间字段作为参数。在它的__call__方法中,它检查是否存在与给定日期和房间号冲突的预订。如果存在冲突,它将引发一个ValidationError。
然后,我们创建了一个common_room_booking_validator实例,并在三个不同的序列化器中重用它:EventSerializer、AppointmentSerializer和ReservationSerializer。这样,无论是处理事件、预约还是预订,都会应用相同的房间预订冲突验证逻辑。
这个例子展示了如何创建一个复杂的自定义验证器,并在多个序列化器中重用它,以确保在不同模型和上下文中应用相同的业务规则。这种方法提高了代码的可维护性,并确保了验证逻辑的一致性。
from rest_framework import serializers
from rest_framework.exceptions import ValidationError
from myapp.models import Event, Appointment, Reservationclass UniqueRoomBookingValidator:def __init__(self, queryset, date_field, room_field):self.queryset = querysetself.date_field = date_fieldself.room_field = room_fielddef __call__(self, attrs):date = attrs[self.date_field]room_number = attrs[self.room_field]# 检查是否存在冲突的预订conflicting_bookings = self.queryset.filter(**{self.date_field: date,self.room_field: room_number})if conflicting_bookings.exists():raise ValidationError('The room is already booked for this date.')# 创建一个通用的UniqueRoomBookingValidator实例
common_room_booking_validator = UniqueRoomBookingValidator(queryset=Event.objects.all(),date_field='date',room_field='room_number'
)class EventSerializer(serializers.Serializer):name = serializers.CharField()room_number = serializers.IntegerField()date = serializers.DateField()class Meta:validators = [common_room_booking_validator]class AppointmentSerializer(serializers.Serializer):client_name = serializers.CharField()room_number = serializers.IntegerField()date = serializers.DateField()class Meta:validators = [common_room_booking_validator]class ReservationSerializer(serializers.Serializer):guest_name = serializers.CharField()room_number = serializers.IntegerField()date = serializers.DateField()class Meta:validators = [common_room_booking_validator]# 使用EventSerializer、AppointmentSerializer和ReservationSerializer时,
# 它们都会应用相同的UniqueRoomBookingValidator验证逻辑
继承一个公共序列化器类(更普遍,推荐)
from rest_framework import serializers
from rest_framework.validators import UniqueTogetherValidator
from myapp.models import Event, Appointment, Reservation# 创建一个基础序列化器类,包含共享的字段和验证逻辑
class BaseRoomBookingSerializer(serializers.Serializer):room_number = serializers.IntegerField()date = serializers.DateField()class Meta:validators = [UniqueTogetherValidator(queryset=Event.objects.all(),fields=['room_number', 'date'])]# EventSerializer继承自BaseRoomBookingSerializer,并添加特定的字段
class EventSerializer(BaseRoomBookingSerializer):name = serializers.CharField()# AppointmentSerializer继承自BaseRoomBookingSerializer,并添加特定的字段
class AppointmentSerializer(BaseRoomBookingSerializer):client_name = serializers.CharField()# ReservationSerializer继承自BaseRoomBookingSerializer,并添加特定的字段
class ReservationSerializer(BaseRoomBookingSerializer):guest_name = serializers.CharField()# 使用EventSerializer、AppointmentSerializer和ReservationSerializer时,
# 它们都会应用相同的UniqueTogetherValidator验证逻辑
处理嵌套对象(默认不可写)
class UserSerializer(serializers.Serializer):email = serializers.EmailField()username = serializers.CharField()class CommentSerializer(serializers.Serializer):user = UserSerializer()content = serializers.CharField()created = serializers.DateTimeField(required=True)
错误表示
当我们尝试使用以下数据来创建一个CommentSerializer实例时:
{'user': {'email': 'foobar', 'username': 'doe'},'content': 'baz'
}
实现.create()实现可写的嵌套表示
在Django REST framework(DRF)中,“可写”(writable)通常指的是能够处理数据写入操作的能力,例如创建(POST)或更新(PUT/PATCH)数据。当官方文档提到"可写的嵌套表示"时,它指的是序列化器不仅能够处理数据的序列化(将模型实例转换为JSON等格式),还能处理反序列化(将JSON等格式转换为模型实例)并执行数据的保存操作。
在处理嵌套对象时,DRF默认只提供了序列化的能力,即它可以将嵌套的模型实例转换为嵌套的JSON表示。但是,如果你想要在接收到嵌套的JSON数据时创建或更新数据库中的相关记录,你需要自己实现.create()和.update()方法来处理这些嵌套的数据。
因为嵌套关系的创建和更新行为可能不明确,并且可能需要关联模型间的复杂依赖关系,REST framework 3 要求你始终明确的定义这些方法。默认的ModelSerializer .create()和.update()方法不包括对可写嵌套关联的支持。
官方文档中的示例展示了如何在序列化器中实现.create()方法,以便能够创建具有嵌套关系的对象。在这个例子中,我们有一个User模型和一个关联的Profile模型。UserSerializer包含一个嵌套的ProfileSerializer,用于处理profile字段。
我们可以看到user字段中的email值不是一个有效的电子邮件地址(因为它没有@符号),所以UserSerializer验证失败。同时,CommentSerializer中的created字段是必填的,但在提供的数据中缺失,所以也验证失败。
调用serializer.is_valid()方法后,我们得到False,表示数据验证不通过。然后我们可以通过serializer.errors来查看具体的错误信息。错误信息会按照字段组织在一个字典中,嵌套的user字段错误也会被嵌套在’user’键下:
{'user': {'email': ['Enter a valid e-mail address.']},'created': ['This field is required.']
}
只验证部分传入的字段(部分更新)
默认情况下,序列化器必须传递所有必填字段的值,否则就会引发验证错误。你可以使用 partial参数来允许部分更新。
serializer = CommentSerializer(comment, data={'content': u'foo bar'}, partial=True)
访问未处理的数据和实例
- .initial_data 属性
- .initial_data 属性用于访问传递给序列化器的原始输入数据,通常是来自客户端的请求数据。
- 这些数据通常是未经验证的,并且是序列化器进行验证和保存操作之前的原始状态。
- .initial_data 仅在序列化器被实例化时传递了 data 参数时存在。
- .instance 属性
- .instance 属性用于访问序列化器关联的模型实例,通常是从数据库中检索的对象。
- 这个属性通常在序列化器用于更新或检索操作时使用,以便访问和操作现有的数据库记录。
- .instance 在序列化器被实例化时传递了 instance 参数时存在,如果没有传递,则为 None。
举例说明
class EventDetailView(generics.RetrieveUpdateAPIView):queryset = Event.objects.all()serializer_class = EventSerializerdef perform_update(self, serializer):# 在这里,你可以通过serializer.instance来访问原始的Event实例# 这是因为在这个上下文中,你可能没有直接的引用到event_instanceoriginal_event = serializer.instance# ...执行一些额外的逻辑...serializer.save()
class EventCreateView(APIView):def post(self, request, *args, **kwargs):# 在这里,我们直接使用request.data,而不是一个单独的submitted_data变量serializer = EventSerializer(data=request.data)if serializer.is_valid():serializer.save()return Response(serializer.data, status=201)return Response(serializer.errors, status=400)def perform_create(self, serializer):# 假设我们需要在创建对象之前做一些额外的检查# 我们可以在这里使用.initial_data来访问原始提交的数据if 'some_condition' in serializer.initial_data:# 执行一些额外的逻辑passserializer.save()
ModelSerializer
通常你会想要与Django模型相对应的序列化类。
ModelSerializer类能够让你自动创建一个具有模型中相应字段的Serializer类。
这个ModelSerializer类和常规的Serializer类一样,不同的是:
它根据模型自动生成一组字段。
它自动生成序列化器的验证器,比如unique_together验证器。
它默认简单实现了.create()方法和.update()方法。
声明一个ModelSerializer如下:
class AccountSerializer(serializers.ModelSerializer):class Meta:model = Accountfields = ('id', 'account_name', 'users', 'created')# 你还可以将fields属性设置成'__all__'来表明使用模型中的所有字段。
你可以将exclude属性设置成一个从序列化器中排除的字段列表。例如
class AccountSerializer(serializers.ModelSerializer):class Meta:model = Accountexclude = ('users',)
拓展:检查ModelSerializer
序列化类生成有用的详细表示字符串,允许你全面检查其字段的状态。 这在使用ModelSerializers时特别有用,因为你想确定自动创建了哪些字段和验证器。
要检查的话,打开Django shell,执行 python manage.py shell,然后导入序列化器类,实例化它,并打印对象的表示:
>>> from myapp.serializers import AccountSerializer
>>> serializer = AccountSerializer()
>>> print(repr(serializer))
AccountSerializer():id = IntegerField(label='ID', read_only=True)name = CharField(allow_blank=True, max_length=100, required=False)owner = PrimaryKeyRelatedField(queryset=User.objects.all())
指定只读字段
你可能希望将多个字段指定为只读,而不是显式的为每个字段添加read_only=True属性,这种情况你可以使用Meta的read_only_fields选项。
该选项应该是字段名称的列表或元祖,并像下面这样声明:
class AccountSerializer(serializers.ModelSerializer):
class Meta:
model = Account
fields = (‘id’, ‘account_name’, ‘users’, ‘created’)
read_only_fields = (‘account_name’,)
模型中已经设置editable=False的字段和默认就被设置为只读的AutoField字段都不需要添加到read_only_fields选项中。
Serializer fields(序列化字段)
属性
required
如果在反序列化时候没有提供这个字段,通常会抛出一个错误。如果在反序列化操作中不需要这个字段,将其设置为False。
将其设置为False同样允许在序列化实例时忽略对象属性或者字段的键。如果这个键不存在,则该键根本不会出现在输出中。
默认是True
无论是allow_blank与allow_null上有效的选项ChoiceField,但我们强烈建议您只使用一个,而不是两个。allow_blank应该首选用于文本选择,并且allow_null应该首选用于数字或其他非文本选择。
Pagination(分页)
分页API可以支持以下两者之一:
- 作为响应内容的一部分提供的分页链接。
- 包含在响应标头中的分页链接,例如 Content-Range 或 Link。
当前内置样式都使用作为响应内容一部分的链接。当使用可浏览的API时,这种样式更容易访问。
只有在使用常规视图或视图集时才自动执行分页。==如果使用的是常规的 APIView ,则需要自行调用分页API以确保返回分页的响应。==请参见 mixins.ListModelMixin 以及 generics.GenericAPIView 类作为示例。
设置分页样式
可以使用 DEFAULT_PAGINATION_CLASS 和 PAGE_SIZE 设置键全局设置分页样式。例如
REST_FRAMEWORK = {'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination','PAGE_SIZE': 100
}
注意,您需要同时设置分页类和应该使用的页面大小。默认情况下, DEFAULT_PAGINATION_CLASS 和 PAGE_SIZE 均为 None 。
也可以使用 pagination_class 属性在单个视图上设置分页类。
如果同时设置了全局和单个视图,后者优先级更高。
PageNumberPagination(DRF自带分页样式之一)
PageNumberPagination 类包含许多属性,通过重写其中的一些属性可以修改分页属性
为了设置这些属性,应当重写 PageNumberPagination 类,然后如上所述启用自定义分页类。
django_paginator_class —— 要使用的django paginator类。默认为 django.core.paginator.Paginator ,适用于大多数情况。
page_size —— 表示页面大小的数值。如果设置,则覆盖 PAGE_SIZE 设置。其默认值与 PAGE_SIZE 设置键相同。
page_query_param —— 一个字符串值,指示用于分页控件的查询参数的名称。
page_size_query_param —— 如果设置,这是一个字符串值,指示允许客户端根据每个请求设置页面大小的查询参数的名称。默认值为 None,表示客户端可能无法控制请求的页面大小。
max_page_size —— 如果设置,这是一个数字值,指示允许的最大请求页面大小。此属性仅在设置了 page_size_query_param 时有效。
Exceptions(异常)
DRF自带异常处理
REST framework的视图能处理各种各样的异常,能处理并返回合适的错误响应。
以下异常会被处理:
- 在REST framework内部产生的APIException 的子类异常。
- 原生Django的Http404 异常.
- 原生Django的PermissionDenied 异常.
在上述各类情况中,REST framework会返回一个带有合适状态码与content-type的响应。响应正文(Response body)会包含有关报错的任何额外信息。
大多数报错响应都会在响应正文里包含一个detail。
例如,下面的请求:
DELETE http://api.example.com/foo/bar HTTP/1.1
Accept: application/json
就可能会收到一个报错响应,表示DELETE方法在该资源上不可使用。HTTP/1.1 405 Method Not Allowed
Content-Type: application/json
Content-Length: 42{"detail": "Method 'DELETE' not allowed."}
验证类的报错在处理上略有不同,他们会把字段名作为keys包含在响应正文中。验证类的报错如果并不是针对特定的字段,则会使用"non_field_error"或者是setting中NON_FIELD_ERRORS_KEY的值作为keys返回。
一个验证类错误大概是这个样子:
HTTP/1.1 400 Bad Request
Content-Type: application/json
Content-Length: 94{"amount": ["A valid integer is required."], "description": ["This field may not be blank."]}
自定义异常处理
自定义异常处理函数,处理DRF框架相关异常
当然你也可以自己实现自定义异常处理,只需要创建一个异常处理函数即可,它要能够将你API views里引发的异常转换成响应对象。这样你就可以自己控制你API的报错响应的样式了。
这个函数必须接受一对参数,第一个是需要处理的异常,第二个则是一个字典类型,这个字典需要包含一切额外相关信息,比如当前正在处理的view等。异常处理函数要么返回一个Response对象要么就直接返回None(比如异常无法正常处理的情况下)。如果处理函数返回了None,那么这个异常会继续向上报错,并由Django返回一个标准的HTTP 500的’server error’响应。
举个例子,你可能想确保你所有的响应正文里都会包含该次请求的HTTP状态码,就像这样:
HTTP/1.1 405 Method Not Allowed
Content-Type: application/json
Content-Length: 62{"status_code": 405, "detail": "Method 'DELETE' not allowed.", "view": "your_project.views.YourAPIView"}
想要变成这样的响应,你可以写一个像下面这样的异常处理函数:
from rest_framework.views import exception_handlerdef custom_exception_handler(exc, context):# 首先调用REST framework默认的异常处理,# 以获得标准的错误响应。response = exception_handler(exc, context)# 接下来将HTTP状态码加到响应中。if response is not None:response.data['status_code'] = response.status_code# 获取当前处理异常的view的信息view = context['view']# 在响应中添加view的信息response.data['view'] = str(view)return response
异常处理函数还必须通过settings来配置,来替换DRF默认的异常处理,如下:
REST_FRAMEWORK = {'EXCEPTION_HANDLER': 'my_project.my_app.utils.custom_exception_handler'
}
如果没有特别指出,'EXCEPTION_HANDLER’设置默认使用REST framework提供的标准异常处理:
REST_FRAMEWORK = {'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler'
}
要注意的是异常处理只会由DRF框架产生异常的响应调用。如:验证错误、权限错误、序列化错误,具体点就是,使用DRF自己的序列化器进行数据验证时,如果数据验证失败,DRF会自动将验证错误转换为一个异常,并生成一个HTTP 400 Bad。
它无法处理view直接返回的响应,即写在代码里的return Response(serializer.errors, status=HTTP_400_BAD_REQUEST)啥的。
自定义异常类,处理视图相关异常
APIException
如果你的API依赖某个时不时会掉线的第三方服务,你可能想要自己实现一个异常"503 Service Unavailable"的HTTP响应码,你可以这么干:
from rest_framework.exceptions import APIExceptionclass ServiceUnavailable(APIException):status_code = 503default_detail = 'Service temporarily unavailable, try again later.'default_code = 'service_unavailable'
检查 API 异常
有很多属性可以用来检查一个API异常的状态,你可以用这些属性来构建专属你项目的自定义异常。
可用的属性和方法有:
.detail - 以文字形式返回报错的细节描述。
.get_codes() - 返回报错的标识码。
.get_full_details() - 返回报错的细节描述以及报错的标识码。
大多数情况下,报错的细节的返回结果很简单:
>>> print(exc.detail)
You do not have permission to perform this action.
>>> print(exc.get_codes())
permission_denied
>>> print(exc.get_full_details())
{'message':'You do not have permission to perform this action.','code':'permission_denied'}
如果是验证类报错,那报错细节就会是一个列表或者字典:
>>> print(exc.detail)
{"name":"This field is required.","age":"A valid integer is required."}
>>> print(exc.get_codes())Zh
{"name":"required","age":"invalid"}
>>> print(exc.get_full_details())
{"name":{"message":"This field is required.","code":"required"},"age":{"message":"A valid integer is required.","code":"invalid"}}
ParseError
签名: ParseError(detail=None, code=None)
在访问request.data时,如果请求中包含格式不正确的数据,则该异常会被抛出。
默认情况下该异常会返回HTTP状态码为"400 Bad Request"的响应。