自己总结
继承APIView流程
APIView类
as_view(): 就干了一件事:禁用了csrf中间件的安全认证
dispatch():
- 二次封装request对象,将原wsgi的request对象保留至 _request 中
- 将数据包中的数据解析到request.data,将url链接?后的数据解析到request.query_params
- drf的三大认证
- 二次处理响应对象response在返回
封装Response
from rest_framework.response import Response
class APIResponse(Response):
def __init__(self, data_status, msg, results=None, headers=None, status=None, **kwargs):
data = {
'status': data_status,
'msg': msg,
}
if results:
data['results'] = results
data.update(kwargs)
super().__init__(data=data, headers=headers, status=status)
使用:APIResponse(0, 'ok', {}, headers, status)
允许局部修改
partial=Ture
context可以完成视图类给序列化类传参,需要在视图里面写,在序列化类中通过钩子函数中的validate_名字中的self.context.get('名字来捕获')
局部钩子
全局钩子
设置群体资源校验类ListSerializer
1、在序列化中
class Meta:
# 设置群体资源校验类
list_serializer_class = BooksListSerializer
2、在群体资源类中
class BooksListSerializer(serializers.ListSerializer):
# ListSerializer已提供create的实现体,有特殊需求可以重写
def create(self, validated_data):
# print('>>>', validated_data)
return super().create(validated_data)
# ListSerializer未提供update的实现体,必须重写
def update(self, instance, validated_data):
# print('***', instance, validated_data)
for index, book_obj in enumerate(instance):
book_dic = validated_data[index] # type: dict
for k, v in book_dic.items():
if hasattr(book_obj, k):
setattr(book_obj, k, v)
# 同步到数据库
book_obj.save()
# print("+++", instance)
return instance
GenericeAPIView视图
from rest_framework.generics import GenericAPIView
继承:GenericAPIView
1、需要提供queryset和serializer类属性
queryset = models.Book.objects.filter(is_delete=False)
serializer_class = serializers.BooksModelSerializer
2、在请求方法中通过self.get_queryset和self.get_serializerl来获取
主要作用是简化了queryset和serializer_class,将这两个变量提取到了类属性中,但是get、post、put、等方法还是得自己写
mixins视图工具类
封装了增删改查5大接口
from rest_framework import mixins
继承:mixins.ListModelMixin, mixins.RetrieveModelMixin, GenericAPIView
CreateModelMixin单增 DestoryModelMixin单删,listModelMIxin群查,RetrieveModelMixin单查,UpdateModelMixin单更
1、需要提供queryset和serializer类属性
queryset = models.Book.objects.filter(is_delete=False)
serializer_class = serializers.BooksModelSerializer
2、方法都被封装好了,使用只需要调用和继承相应的方法即可,两行
整合mixins 到 generics 中(ListCreateAPIView)
不需要自己写功能,只需要提供queryset和serializer类属性即可,单需要继承相应的方法
viewsets:视图集(重要)
整合了mixins和viewsets.GenericViewSet
rom rest_framework import viewsets
继承:mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet
1、ViewSetMixin重写了as_view方法,路由层掉用as_view方法就是掉用此方法
2、能够实现5大接口并且自定义5大接口,即能够实现10大接口
3、路由层需要传参,传入不同的请求对应部同的方法,来实现分发
4、通过路由插拔式的方法来根据需求,需要自己写的自己来写方法,不需要的就用系统的方法
老师笔记
ListSerializer类:群增 群改
数据层:还是采用Book、Publish、Author、AuthorDetail四个Model类
序列化层:
from rest_framework import serializers
from . import models
# 利用 ListSerializer 类完成群增群改
class BooksListSerializer(serializers.ListSerializer):
# ListSerializer已提供create的实现体,有特殊需求可以重写
def create(self, validated_data):
# print('>>>', validated_data)
return super().create(validated_data)
# ListSerializer未提供update的实现体,必须重写
def update(self, instance, validated_data):
# print('***', instance, validated_data)
for index, book_obj in enumerate(instance):
book_dic = validated_data[index] # type: dict
for k, v in book_dic.items():
if hasattr(book_obj, k):
setattr(book_obj, k, v)
# 同步到数据库
book_obj.save()
# print("+++", instance)
return instance
class BooksModelSerializer(serializers.ModelSerializer):
class Meta:
# 设置群体资源校验类
list_serializer_class = BooksListSerializer
# 关联的Model类
model = models.Book
fields = ('name', 'price', 'publish', 'authors')
extra_kwargs = {
'publish': {
'write_only': True
},
'authors': {
'write_only': True
},
'price': {
# 数据库字段设置了默认值,也需要 反序列化 时必须提供该字段
'required': True,
'error_messages': {
'required': '价格不能为空',
}
},
'name': {
'min_length': 3,
'error_messages': {
'min_length': '太短',
}
},
}
def validate_name(self, value: str):
# 拿视图类传递过来的参数
# print(self.context.get('owner'))
if not value.isidentifier():
raise serializers.ValidationError('名字非法')
return value
def validate(self, attrs):
# 同一出版社书面相同,代表书是同一本,不存入数据库
name = attrs.get('name')
publish = attrs.get('publish')
# print(name, type(name))
# print(publish, type(publish))
if models.Book.objects.filter(name=name, publish=publish):
raise serializers.ValidationError({'%s' % name: '已存在'})
return attrs
视图层
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from . import models, serializers
from utils.response import APIResponse
class BooksAPIView(APIView):
# 获取所有 | 一个
def get(self, request, *args, **kwargs):
pk = kwargs.get('pk')
if pk:
books_query = models.Book.objects.filter(is_delete=False, pk=pk)
else:
books_query = models.Book.objects.filter(is_delete=False).order_by('id')
books_data = serializers.BooksModelSerializer(books_query, many=True).data
return APIResponse(0, 'ok', books_data)
# 新增多个 | 一个
def post(self, request, *args, **kwargs):
request_data = request.data
# if isinstance(request_data, list): # 群增
# many = True
# else: # 单增
# many = False
many = True if isinstance(request_data, list) else False
book_ser = serializers.BooksModelSerializer(data=request_data, many=many)
if book_ser.is_valid():
book_obj_list = book_ser.save()
return APIResponse(0, 'ok', serializers.BooksModelSerializer(book_obj_list, many=many).data)
else:
return APIResponse(1, 'failed', book_ser.errors)
# 修改一个
def put(self, request, *args, **kwargs):
pk = kwargs.get('pk', 1)
book_obj = models.Book.objects.filter(pk=pk, is_delete=False).first()
book_ser = serializers.BooksModelSerializer(instance=book_obj, data=request.data)
if book_ser.is_valid():
book_obj = book_ser.save()
return Response({
'status': 0,
'msg': 'ok',
'results': serializers.BooksModelSerializer(book_obj).data
})
else:
return Response({
'status': 1,
'msg': 'failed',
'results': book_ser.errors
})
# 局部修改多个 | 一个
"""
def patch(self, request, *args, **kwargs):
request_data = request.data
many = True if isinstance(request_data, list) else False
if many: # 群改
pks = [book_dic.pop('pk') for book_dic in request_data]
# print(pks, request_data)
book_query = models.Book.objects.filter(pk__in=pks, is_delete=False)
book_ser = serializers.BooksModelSerializer(partial=True, many=True, instance=book_query, data=request_data)
if book_ser.is_valid():
book_obj_list = book_ser.save()
return APIResponse(0, 'ok', serializers.BooksModelSerializer(book_obj_list, many=True).data)
else:
return APIResponse(1, 'failed', book_ser.errors)
else: # 单改
pk = kwargs.get('pk')
book_query = models.Book.objects.filter(pk=pk, is_delete=False)
# partial=True允许操作 局部的反序列化字段
book_ser = serializers.BooksModelSerializer(partial=True, many=True, instance=book_query, data=[request_data])
# context可以完成视图类给序列化类传递参数
# book_ser = serializers.BooksModelSerializer(partial=True,instance=book_obj, data=request.data,context={'owner': 'Owen'})
if book_ser.is_valid():
book_obj = book_ser.save()
return APIResponse(0, 'ok', serializers.BooksModelSerializer(book_obj, many=True).data)
else:
return APIResponse(1, 'failed', book_ser.errors)
"""
def patch(self, request, *args, **kwargs):
request_data = request.data
# 群改:往 /Books/ 发送 [{"pk":1,"name":"西游记"},{"pk":2,"price":"1.00"}] pk是必须字段
if isinstance(request_data, list):
pks = [book_dic.pop('pk') for book_dic in request_data]
else: # 单改:往 /Books/(pk)/ 发送 {"name":"西游记"}
pks = [kwargs.get('pk')]
request_data = [request_data]
book_query = models.Book.objects.filter(pk__in=pks, is_delete=False)
book_ser = serializers.BooksModelSerializer(partial=True, many=True, instance=book_query, data=request_data)
if book_ser.is_valid():
book_obj_list = book_ser.save()
return APIResponse(0, 'ok', serializers.BooksModelSerializer(book_obj_list, many=True).data)
else:
return APIResponse(1, 'failed', book_ser.errors)
# 删除一个 /books/1/ | 删除多个 /books/ 数据[1, 2]
def delete(self, request, *args, **kwargs):
pk = kwargs.get('pk')
if pk:
pks = [pk]
else:
pks = request.data
delete_rows = models.Book.objects.filter(pk__in=pks, is_delete=False).update(is_delete=True)
if delete_rows != 0:
return APIResponse(0, 'ok')
return APIResponse(1, '删除失败')
视图家族:
数据层、序列化层:不变
视图层:
"""
generics:视图类
重点:将 queryset对象 与 serializer对象 封装成类属性
mixins:视图工具集
重点:通过list、create、update、destroy、retrieve五大功能(依赖generics类)
viewsets:视图集
重点:通过ViewSetMixin完成请求方法的自定义映射(整合mixins、 generics、ViewSetMixin)
"""
from rest_framework.generics import GenericAPIView
from . import models, serializers
from utils.response import APIResponse
# generics:视图类
class BooksGenericAPIView(GenericAPIView):
queryset = models.Book.objects.filter(is_delete=False)
serializer_class = serializers.BooksModelSerializer
# lookup_field = 'pk' # 与urls中的有名分组,有名分组为pk可以省略
def get(self, request, *args, **kwargs):
pk = kwargs.get('pk')
if not pk:
book_query = self.get_queryset()
book_ser = self.get_serializer(book_query, many=True)
return APIResponse(0, 'ok', book_ser.data)
else:
book_obj = self.get_object()
book_ser = self.get_serializer(book_obj)
return APIResponse(0, 'ok', book_ser.data)
# mixins:视图工具集
from rest_framework import mixins
class BooksMixinsGenericAPIView(mixins.ListModelMixin, mixins.RetrieveModelMixin, GenericAPIView):
queryset = models.Book.objects.filter(is_delete=False)
serializer_class = serializers.BooksModelSerializer
def get(self, request, *args, **kwargs):
pk = kwargs.get('pk')
if not pk:
return self.list(request, *args, **kwargs)
else:
return self.retrieve(request, *args, **kwargs)
# 整合mixins 到 generics 中:不需要自己写功能
from rest_framework.generics import ListCreateAPIView, RetrieveAPIView
class BooksListAPIView(ListCreateAPIView):
queryset = models.Book.objects.filter(is_delete=False)
serializer_class = serializers.BooksModelSerializer
# 重点
# viewsets:视图集(整合mixins 到 generics)、
from rest_framework import viewsets
class BooksGenericViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet):
queryset = models.Book.objects.filter(is_delete=False)
serializer_class = serializers.BooksModelSerializer
def create_many_or_one(self, request, *args, **kwargs):
request_data = request.data
many = True if isinstance(request_data, list) else False
book_ser = serializers.BooksModelSerializer(data=request_data, many=many)
if book_ser.is_valid():
book_obj_list = book_ser.save()
return APIResponse(0, 'ok', serializers.BooksModelSerializer(book_obj_list, many=many).data)
else:
return APIResponse(1, 'failed', book_ser.errors)
路由层
from django.conf.urls import url, include
from . import views
urlpatterns = [
url(r'^v1/books/$', views.BooksGenericAPIView.as_view()),
url(r'^v1/books/(?P<pk>d+)/', views.BooksGenericAPIView.as_view()),
url(r'^v2/books/$', views.BooksMixinsGenericAPIView.as_view()),
url(r'^v2/books/(?P<pk>d+)/', views.BooksMixinsGenericAPIView.as_view()),
url(r'^v3/books/$', views.BooksListAPIView.as_view()),
url(r'^v3/books/(?P<pk>d+)/', views.BooksListAPIView.as_view()),
# 重点:
url(r'^v4/books/$', views.BooksGenericViewSet.as_view({'get': 'list', 'post': 'create_many_or_one'})),
url(r'^v4/books/(?P<pk>d+)/', views.BooksGenericViewSet.as_view({'get': 'retrieve'})),
]
路由组件:了解
from django.conf.urls import url, include
from . import views
from rest_framework.routers import SimpleRouter
router = SimpleRouter()
router.register('books', views.BooksGenericViewSet, base_name='book')
# url(r'^v1/books/$', views.BooksGenericAPIView.as_view()),
# url(r'^v1/books/(?P<pk>d+)/', views.BooksGenericAPIView.as_view()),
# 第一种方式
urlpatterns = []
urlpatterns.extend(router.urls)
# 第二种方式
urlpatterns = [
url(r'^', include(router.urls)),
]