今天重新看了一遍 drf 的文档,真的是豁然开朗,以前写的时候都是不求甚解,直接 cv,现在知道为什么这么写了

技巧

  1. data 直接模拟来自客户端数据, 不用 request.data
  2. 字典用 get,不要用[],容易报错
  3. request.POST 的类型是 QueryDict,和普通的 Dict 不同的是,如果使用 get,只能获得数组的最后一个数,必须使用 getlist 才能获取 list

反序列化

校验数据

字段选项,都是反序列化需要

max_length
min_length
allow_blank
trim_whitespace 截断空白符
max_value
min_value

validaters = [序列化器外部的验证函数]

required = False 反序列化时可以不提供,不会报错

read_only = True 前端提交的数据不应该有这个字段,有的话被忽略
wirte_only = True 对象转化成字典时,不需要这个字段
err_message = {'min_value': '小于最小值'} 自定义验证字段报错信息

反序列化基本步骤

1. 实例化serializer对象
xx = XXSerializer(data=xxxx)
2. 校验数据
xx.is_valid()
3. 获取验证数据
xx.validated_data
4. 获取验证报错
xx.errors # dict key为字段
2. 直接抛出异常,不需要4
xx.is_valid(raise_exception=True)
4. 保存
xx.save()
5. 返回
xx.validated_data

验证

1. 抛出异常
raise serializers.ValidationError(detail="xxxx", code="validate_name")
2. 验证来自客户端所有数据
def validate(self, attrs)
3. 验证单一字段xxx
def validate_xxx(self, data)

保存数据

def create(self, validated_data):
return xxx_model.objects.create(**validated_data)
def update(self, instance, validated_data):
# instance.xx = validated_data['xx']
setattr(instance, key, value)
instance.save() # django没有update方法
return instance
更新操作:
1. 实例化 partial=True允许只传入部分字段更新,不验证其它字段
serializer = XXSerializer(instance=instance, data=data, partial=True)
2. 校验
xx.is_valid(raise_exception=True)
3. 保存
serializer.save() # 可以传不需要校验的数据 如owner=request.user
4. 返回
serializer.validated_data

ModelSerializer 简化代码

class Meta:
model = User
fields = ['id', 'name']
exclude = [排除的字段] # 少用
read_only_fields = ['id'] # 只读 即只有序列化时候才用的字段
extra_kwargs = { # 字段的选项
'字段名': {
'选项': value,
},
如:
'name': {
'max_length': 10
}
}
重写create方法
def create(self, validated_data):
validated_data['password'] = make_password(validated_data['password'])
super().create(validated_data)

模型中没有声明的字段可以自己加,自己加的没有值不会返回,model 导入的一定会返回(null)

APIView

基本视图,继承自 View,升级了 request/response/as_view/异常处理方法

新增类属性:

1. authentication_classes 身份认证
2. permission_classes 权限检查
3. throttle_classes 流量控制

方法(需要自己写):

  1. get
  2. post
  3. patch
  4. put
  5. delete

request/response

request.data     # body/json/file 都可以解析
request.query_params
request._request # django原生request
response(headers={'flag': '123456'}) # 自定义响应头

GenericAPIView+Mixin

GenericAPIView 通用视图,继承自 APIView

新增类属性:

1. queryset
2. serializer_class
3. lookup_field 用于数据库查询字段名
4. lookup_url_kwarg 前端传过来的字段名

新增类方法:

1. get_queryset()
2. get_serializer() 多个serializer需要重写 一般不用_class
3. get_object() 使用lookup_field参数在queryset中查/重写以提供基于多个参数查
4. filter_object()

Mixin 类,提供了增删查改的几个方法

1. ListModelMixin     提供list方法
2. CreateModelMixin 提供create方法
3. RetrieveModelMixin 提供查询单个对象方法
4. UpdateModelMixin 更新/partial=True部分更新
5. DestroyModelMixin 删除

ListAPIView

继承自 GenericAPIView 和 ListModelMixin,提供了 get 方法,里面调用了 mixin 类里的 list 方法,下面都类似,一看名字就知道了,不一一介绍了

CreateAPIView

RetrieveAPIView

DestroyAPIView

UpdateAPIView

ListCreateAPIView

RetrieveUpdateAPIView

RetrieveDestroyAPIView

RetrieveUpdateDestroyAPIView

ViewSet

继承自 APIView,更加简化代码,可以把多个相关的视图放到一块儿,搭配独特路由器机制,as_view 中绑定请求 method 到视图的方法 list/create/retrieve/update/destroy,但不提供这些方法实现,需要自己写

XXXViewSet.as_view({'get': 'list/自己的方法名···'})

GenericViewSet

继承自 GenericAPIView,不是 ViewSet,也是不提供 crud 方法

ModelViewSet

继承自 GenericViewSet 和所有 mixin 类,提供完整 crud 方法

RealOnlyModelViewSet

继承自 GenericViewSet+RetrieveModelMixin+ListModelMixin

Router

路由,自动绑定 method 到视图集方法

router = routers.SimpleRouter()
router.register(r'users', UserViewSet)
router.register(r'accounts', AccountViewSet)
urlpatterns = router.urls

自定义方法绑定

@detail_route(methods=['post'], permission_classes=[IsAdminOrIsSelf], url_path='yyyyyy')
def xxxxxx(self, request, **kwargs)

router自动生成这样的url: aaa/{pk}/yyyyyy

或者直接action绑定,和上面的类似
@action(methods, detail=True/False, url_path, url_name)

异常处理

自定义异常处理

from rest_framework.views import exception_handler
def custom_exception_handler(exc, context):
response = exception_handler(exc, context) # 先调用drf生成一个标准的
if response is not None:
response.data['status_code'] = response.status_code # 向response里传数据
return response