(持续更新中)DRF相关

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):
       pass

def create(self, request):
    pass

def 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):
    pass

def partial_update(self, request, pk=None):
    pass

def 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 DefaultRouter

router = 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, PasswordSerializer

class 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 models

class 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 User

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ['id', 'username', 'email', 'is_active']

在这个UserSerializer中,我们继承了serializers.ModelSerializer,这是一个快捷的序列化器,它自动根据模型字段生成序列化器字段。在Meta类中,我们指定了要包含在序列化中的模型和字段。

序列化对象

现在,你可以在视图中使用这个序列化器来序列化用户数据:

from django.http import JsonResponse
from .models import User
from .serializers import UserSerializer

def 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 serializers

class 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 serializers

class 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, Reservation

class UniqueRoomBookingValidator:
    def __init__(self, queryset, date_field, room_field):
        self.queryset = queryset
        self.date_field = date_field
        self.room_field = room_field

    def __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 = EventSerializer

    def perform_update(self, serializer):
        # 在这里,你可以通过serializer.instance来访问原始的Event实例
        # 这是因为在这个上下文中,你可能没有直接的引用到event_instance
        original_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:
            # 执行一些额外的逻辑
            pass
        serializer.save()

ModelSerializer

通常你会想要与Django模型相对应的序列化类。

ModelSerializer类能够让你自动创建一个具有模型中相应字段的Serializer类。

这个ModelSerializer类和常规的Serializer类一样,不同的是:

它根据模型自动生成一组字段。
它自动生成序列化器的验证器,比如unique_together验证器。
它默认简单实现了.create()方法和.update()方法。
声明一个ModelSerializer如下:

class AccountSerializer(serializers.ModelSerializer):
    class Meta:
        model = Account
        fields = ('id', 'account_name', 'users', 'created')
        # 你还可以将fields属性设置成'__all__'来表明使用模型中的所有字段。

你可以将exclude属性设置成一个从序列化器中排除的字段列表。例如

class AccountSerializer(serializers.ModelSerializer):
    class Meta:
        model = Account
        exclude = ('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_handler

def 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 APIException

class ServiceUnavailable(APIException):
    status_code = 503
    default_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"的响应。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/473682.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

NCV7428D15R2G中文资料PDF数据手册参数引脚图图片价格概述参数芯片特性原理

产品概述&#xff1a; NCV7428 是一款系统基础芯片 (SBC)&#xff0c;集成了汽车电子控制单元 (ECU) 中常见的功能。NCV7428 为应用微控制器和其他负载提供低电压电源并对其进行监控&#xff0c;包括了一个 LIN 收发器。 产品特性&#xff1a; 控制逻辑3.3 V或5 V VOUT电源&…

(css)步骤条el-steps区分等待、进行中、完成三种状态的图片

(css)步骤条el-steps区分等待、进行中、完成三种状态的图片 效果&#xff1a; <el-steps :active"active" finish-status"success" class"steps"><el-step title"选择.."></el-step><el-step title"..规则&…

【Java】使用 Java 语言实现一个冒泡排序

大家好&#xff0c;我是全栈小5&#xff0c;欢迎阅读小5的系列文章。 这是《Java》系列文章&#xff0c;每篇文章将以博主理解的角度展开讲解&#xff0c; 特别是针对知识点的概念进行叙说&#xff0c;大部分文章将会对这些概念进行实际例子验证&#xff0c;以此达到加深对知识…

鸿蒙Harmony应用开发—ArkTS-高级组件:@ohos.arkui.advanced.ComposeTitleBar(头像和单双行文本标题栏)

一种普通标题栏&#xff0c;支持设置标题、头像&#xff08;可选&#xff09;和副标题&#xff08;可选&#xff09;&#xff0c;可用于一级页面、二级及其以上界面配置返回键。 说明&#xff1a; 该组件从API Version 10开始支持。后续版本如有新增内容&#xff0c;则采用上角…

Linux CentOS 7.6安装mysql5.7.26详细保姆级教程

一、通过wget下载mysql安装包 1、下载 //进入home目录 cd /home //下载mysql压缩包 wget https://dev.mysql.com/get/Downloads/MySQL-5.7/mysql-5.7.26-linux-glibc2.12-x86_64.tar.gz //解压 tar -xvf mysql-5.7.26-linux-glibc2.12-x86_64.tar.gz //重命名文件夹 mv mys…

【Springboot3+Mybatis】文件上传阿里云OSS 基础管理系统CRUD

文章目录 一、需求&开发流程二、环境搭建&数据库准备三、部门管理四、员工管理4.1 分页(条件)查询4.2 批量删除员工 五、文件上传5.1 介绍5.2 本地存储5.3 阿里云OSS1. 开通OSS2. 创建存储空间Bucket 5.4 OSS快速入门5.5 OSS上传显示文件 六、配置文件6.1 yml配置6.2 C…

【设计模式】Java 设计模式之模板命令模式(Command)

命令模式&#xff08;Command&#xff09;的深入分析与实战解读 一、概述 命令模式是一种将请求封装为对象从而使你可用不同的请求把客户端与接受请求的对象解耦的模式。在命令模式中&#xff0c;命令对象使得发送者与接收者之间解耦&#xff0c;发送者通过命令对象来执行请求…

【NLP】多头注意力(Multi-Head Attention)的概念解析

一. 多头注意力 多头注意力&#xff08;Multi-Head Attention&#xff09;是一种在Transformer模型中被广泛采用的注意力机制扩展形式&#xff0c;它通过并行地运行多个独立的注意力机制来获取输入序列的不同子空间的注意力分布&#xff0c;从而更全面地捕获序列中潜在的多种语…

Linux快速入门,上手开发 01.学习路线

少时曾许凌云志&#xff0c;当取世间第一流 再见少年拉满弓&#xff0c;不惧岁月不飓风 —— 24.3.20 1.Linux的发展历史 2.VM虚拟机的Linux初体验 3.图形化页面设置系统——快速上手 4.命令行操作——向专业前进 5.核心操作命令——必知必会&#xff08;管理企业级权限/定位b…

【LEMONSQUEEZY: 1【mysql写shell】】

前期环境准备 靶机下载地址 https://vulnhub.com/entry/lemonsqueezy-1%2C473/ 信息收集 ┌──(root㉿kali)-[/home/test/桌面/lemmon] └─# nmap -sP 192.168.47.1/24 --min-rate 3333 Starting Nmap 7.92 ( https://nmap.org ) at 2024-03-20 14:02 CST Stats: 0:00:06 e…

目标检测——YOLOR算法解读

论文&#xff1a;YOLOR-You Only Learn One Representation: Unifified Network for Multiple Tasks 作者&#xff1a;Chien-Yao Wang, I-Hau Yeh, Hong-Yuan Mark Liao 链接&#xff1a;https://arxiv.org/abs/2105.04206 代码&#xff1a;https://github.com/WongKinYiu/yolo…

使用ansible批量修改操作系统管理员账号密码

一、ansible server端配置 1、对于Linux主机配置免密登录ssh-copy-id -i ~/.ssh/id_rsa.pub rootremote_ip 2、在/etc/ansible/hosts文件中添加相应主机IP 3、对于Windows主机需要在/etc/ansible/hosts文件中进行以下配置 192.168.83.132 ansible_ssh_useradministrator an…

centos重启防火墙导致docker不可用

重启容器报错 错误原因 docker服务启动时定义的自定义链docker&#xff0c;由于centos7 firewall 被清掉 firewall的底层是使用iptables进行数据过滤&#xff0c;建立在iptables之上&#xff0c;这可能会与 Docker 产生冲突。 当 firewalld 启动或者重启的时候&#xff0c;将…

【大数据】Redis介绍和使用

【大数据】Redis介绍和使用 介绍服务器搭建redis支持的五种数据类型数据类型应用场景总结 介绍 Redis&#xff08;Remote Dictionary Server&#xff09;是一个开源的基于内存的数据结构存储系统&#xff0c;它提供了丰富的数据结构&#xff08;如字符串、哈希表、列表、集合、…

HTML静态网页成品作业(HTML+CSS)——动漫猫和老鼠网页(1个页面)

&#x1f389;不定期分享源码&#xff0c;关注不丢失哦 文章目录 一、作品介绍二、作品演示三、代码目录四、网站代码HTML部分代码 五、源码获取 一、作品介绍 &#x1f3f7;️本套采用HTMLCSS&#xff0c;未使用Javacsript代码&#xff0c;共有1个页面。 二、作品演示 三、代…

[C语言]——内存函数

目录 一.memcpy使用和模拟实现&#xff08;内存拷贝&#xff09; 二.memmove 使用和模拟实现 三.memset 函数的使用&#xff08;内存设置&#xff09; 四.memcmp 函数的使用 C语言中规定&#xff1a; memcpy拷贝的就是不重叠的内存memmove拷贝的就是重叠的内存但是在VS202…

Vue3组件的注册

组件是Vue.js中的一个重要概念&#xff0c;它是一种抽象&#xff0c;是一个可以复用的Vue.js实例。它拥有独一无二的组件名称&#xff0c;可以扩展HTML元素&#xff0c;以组件名称的方式作为自定义的HTML标签。 在大多数系统网页中&#xff0c;网页都包含header、body、footer…

流畅的 Python 第二版(GPT 重译)(十)

第十八章&#xff1a;with、match 和 else 块 上下文管理器可能几乎与子例程本身一样重要。我们只是初步了解了它们。[…] Basic 有一个 with 语句&#xff0c;在许多语言中都有 with 语句。但它们的功能不同&#xff0c;它们都只是做一些非常浅显的事情&#xff0c;它们可以避…

神经网络(深度学习,计算机视觉,得分函数,损失函数,前向传播,反向传播,激活函数)

目录 一、神经网络简介 二、深度学习要解决的问题 三、深度学习的应用 四、计算机视觉 五、计算机视觉面临的挑战 六、得分函数 七、损失函数 八、前向传播 九、反向传播 十、神经元的个数对结果的影响 十一、正则化与激活函数 一、神经网络简介 神经网络是一种有监督…

排水管网信息化平台:科技赋能,助力城市水环境管理升级

排水管网承担着城市污水、雨水的收集与排出的双重任务&#xff0c;是城市重要的基础设施。城市化率的不断提高&#xff0c;对城市基础设施的性能也提出了考验。 排水管网存在窨井监测设备不足、管段淤积、无序监管、污水超标排放等问题突出&#xff0c;导致部分污水直排受纳水…