本文共 11734 字,大约阅读时间需要 39 分钟。
文章目录
一、serializer进行put、delete及获取单条数据的接口设计
1.1. 使用serializer进行put接口设计
urls.py
re_path(r'books/(\d+)/$', views.BookFilterView.as_view())
views.py
from rest_framework.views import APIViewfrom app_serializer import BookSerializerclass BookFilterView(APIView): def put(self, request, nid): book_obj = Book.objects.get(pk=nid) serialized_data = BookSerializer(data=request.data, instance=book_obj) if serialized_data.is_valid(): serialized_data.save() else: return Response(serialized_data.errors)
serializer.py
class BookSerializer(serializers.ModelSerializer): class Meta: model = Book fields = ('title', 'price', 'publish', 'authors', 'author_list', 'publish_name', 'publish_city' ) extra_kwargs = { 'publish': { 'write_only': True}, 'authors': { 'write_only': True} } publish_name = serializers.CharField(max_length=32, read_only=True, source='publish.name') publish_city = serializers.CharField(max_length=32, read_only=True, source='publish.city') author_list = serializers.SerializerMethodField() def get_author_list(self, book_obj): # 拿到queryset开始循环 [{ }, { }, { }, { }] authors = list() for author in book_obj.authors.all(): authors.append(author.name) return authors
除了传入data参数外,还需告诉序列化组件,我们需要更新哪条数据,也就是instance,另外,我们使用的序列化类还是之前那个
class BookSerializer(serializers.ModelSerializer): class Meta: model = Book fields = ('title', 'price', 'publish', 'authors', 'author_list', 'publish_name', 'publish_city' ) extra_kwargs = { 'publish': { 'write_only': True}, 'authors': { 'write_only': True} } publish_name = serializers.CharField(max_length=32, read_only=True, source='publish.name') publish_city = serializers.CharField(max_length=32, read_only=True, source='publish.city') author_list = serializers.SerializerMethodField() def get_author_list(self, book_obj): # 拿到queryset开始循环 [{ }, { }, { }, { }] authors = list() for author in book_obj.authors.all(): authors.append(author.name) return authors
1.2. 使用serializer进行delete接口设计
urls.py
re_path(r'books/(\d+)/$', views.BookFilterView.as_view()),
views.py
class BookFilterView(APIView): def delete(self, request, nid): book_obj = Book.objects.get(pk=nid).delete() return Response("") def put(self, request, nid): book_obj = Book.objects.get(pk=nid) serialized_data = BookSerializer(data=request.data, instance=book_obj) if serialized_data.is_valid(): serialized_data.save() return Response(serialized_data.data) else: return Response(serialized_data.errors)
1.3 使用serializer进行单条数据的接口设计
urls.py不变,新增三个接口逻辑后的视图类如下
class BookFilterView(APIView): def get(self, request, nid): book_obj = Book.objects.get(pk=nid) serialized_data = BookSerializer(book_obj, many=False) return Response(serialized_data.data) def delete(self, request, nid): book_obj = Book.objects.get(pk=nid).delete() return Response("") def put(self, request, nid): book_obj = Book.objects.get(pk=nid) serialized_data = BookSerializer(data=request.data, instance=book_obj) if serialized_data.is_valid(): serialized_data.save() return Response(serialized_data.data) else: return Response(serialized_data.errors)
不传参数时
class BookView(APIView): def get(self, request): origin_books = Book.objects.all() serialized_books = BookSerializer(origin_books, many=True) return Response(serialized_books.data) def post(self, request): verified_data = BookSerializer(data=request.data) if verified_data.is_valid(): book = verified_data.save() return Response(verified_data.data) else: return Response(verified_data.errors)
二、优化接口逻辑
2.2 使用mixin优化接口逻辑
urls.py有些区别:
from django.urls import re_pathfrom mixiner import viewsurlpatterns = [ re_path(r'books/$', views.BookView.as_view()), re_path(r'books/(?P\d+)/$', views.BookFilterView.as_view()),]
views.py
from rest_framework.mixins import ( ListModelMixin, CreateModelMixin, UpdateModelMixin, DestroyModelMixin, RetrieveModelMixin)from rest_framework.generics import GenericAPIView# 当前app中的模块from .models import Bookfrom mixin_serializer import BookSerializer# Create your views here.class BookView(ListModelMixin, CreateModelMixin, GenericAPIView): queryset = Book.objects.all() serializer_class = BookSerializer def get(self, request, *args, **kwargs): return self.list(request, *args, **kwargs) def post(self, request, *args, **kwargs): return self.create(request, *args, **kwargs)class BookFilterView(DestroyModelMixin, UpdateModelMixin, RetrieveModelMixin, GenericAPIView): queryset = Book.objects.all() serializer_class = BookSerializer def get(self, request, *args, **kwargs): return self.retrieve(request, *args, **kwargs) def delete(self, request, *args, **kwargs): return self.destroy(request, *args, **kwargs) def put(self, request, *args, **kwargs): return self.update(request, *args, **kwargs)
mixin源码剖析
1. Django程序启动,开始初始化,读取urls.py, 读取settings, 读取视图类2. 执行as_views(), BookView没有,需要到父类中找3. 几个ModelMixin也没有,GenericAPIView中没有,继续到GenericAPIView(APIView)中找4. 找到了,并且与之前的逻辑是一样的,同时我们发现GenericAPIView中定义了查找queryset和serializer_class类的方法5. as_view()方法返回重新封装的视图函数,开始建立url和视图函数之间的映射关系6. 等待用户请求7. 接收到用户请求,根据url找到视图函数8. 执行视图函数的dispatch方法(因为视图函数的返回值是:return self.dispatch()9. dispatch分发请求,查找到视图类的五个方法中的某个10. 开始执行,比如post请求,返回:self.create(),视图类本身没有,则会到父类中查找11. 最后在CreateModelMixin中查找12. 执行create()方法,获取queryset和serializer_class13. 返回数据
2.2 使用view优化接口逻辑
# -*- coding: utf-8 -*-from rest_framework import generics# 当前app中的模块from .models import Bookfrom .serializer_classes import BookSerializer# Create your views here.class BookView(generics.ListCreateAPIView): queryset = Book.objects.all() serializer_class = BookSerializerclass BookFilterView(generics.RetrieveUpdateDestroyAPIView): queryset = Book.objects.all() serializer_class = BookSerializer
2.3 使用viewset优化接口逻辑
urls.py有变化:
from django.urls import re_pathfrom viewsetter import viewsurlpatterns = [ re_path(r'books/$', views.BookView.as_view({ 'get': 'list', 'post': 'create' })), re_path(r'books/(?P\d+)/$', views.BookView.as_view({ 'get': 'retrieve', 'put': 'update', 'delete': 'destroy' })),]
view.py
# -*- coding: utf-8 -*-# django rest framework组件from rest_framework.viewsets import ModelViewSet# 当前app中的模块from .models import Bookfrom .serializer_classes import BookSerializer# Create your views here.class BookView(ModelViewSet): queryset = Book.objects.all() serializer_class = BookSerializer
viewset源码剖析
1. Django程序启动,开始初始化,读取urls.py, 读取settings, 读取视图类2. 执行as_views(), BookView没有,需要到父类(ModelViewSet)中找3. ModelViewSet继承了mixins的几个ModelMixin和GenericViewSet,显然ModelMixin也没有,只有GenericViewSet中有4. GenericViewSet没有任何代码,只继承了ViewSetMixin和generics.GenericAPIView(这个我们已经认识了)5. 继续去ViewSetMixin中查找,找到了as_view类方法,在重新封装view函数的过程中,有一个self.action_map = actions6. 这个actions就是我们给as_view()传递的参数7. 绑定url和视图函数(actions)之间的映射关系8. 等待用户请求9. 接收到用户请求,根据url找到视图函数10. 执行视图函数的dispatch方法(因为视图函数的返回值是:return self.dispatch()11. dispatch分发请求,查找到视图类的五个方法中的某个12. 开始执行,比如post请求,返回:self.create(),视图类本身没有,则会到父类中查找13. 最后在CreateModelMixin中查找14. 执行create()方法,获取queryset和serializer_class15. 返回数据
三 viewset
几种view以及他们之间的关系。
mixins,主要也分为5类 1.首先,我们使用django自带的view,获取一个课程的列表# drf是通过json的格式进行数据交互的,所以这里也返回json数据import jsonfrom django.views.generic.base import Viewfrom django.core import serializersfrom django.http import HttpResponse,JsonResponsefrom .models import Courseclass CourseListView(View): def get(self, request): """ 通过django的view实现课程列表页 """ courses = Course.objects.all()[:10] json_data = serializers.serialize('json', Courses) json_data = json.loads(json_data) return JsonResponse(json_data, safe=False)
APIView
from rest_framework.views import APIViewfrom rest_framework.response import Response# 这个serializers是在其他文件自定义的from .serializers import CourseSerializerclass CourseListView(APIView): def get(self, request, format=None): """ 通过APIView实现课程列表页 """ courses = Course.objects.all() serializer = CourseSerializer(courses, many=True) return Response(serializer.data)
GenericAPIView
from rest_framework import mixinsfrom rest_framework import genericsclass CourseListView(mixins.ListModelMixin, generics.GenericAPIView): """ 课程列表页 """ queryset = Course.objects.all() serialize_class = CourseSerializer def get(self, request, *args, **kwargs): # list方法是存在于mixins中的,同理,create等等也是 # GenericAPIView没有这些方法! return self.list(request, *args, **kwargs)
ViewSet功能
GenericViewSet继承了GenericAPIView,依然有get_queryset,get_serialize_class相关属性与方法,GenericViewSet重写了as_view方法,可以获取到HTTP的请求方法
from rest_framework import viewsetsimport...class CourseViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet): queryset = Course.objects.all() def get_serializer_class(self): # 重写get_serializer_class方法 if self.action == 'list': return CourseSerializer return CourseDetailSerializer
http请求方法与mixins的方法进行绑定 GenericViewSet本身依然不存在list, create方法,需要我们与mixins一起混合使用 重写as_view的方法为我们提供了绑定的功能
# 进行绑定courses = CourseViewSet.as_view({ 'get': 'list', 'post': 'create'})urlpatterns = [ ... # 常规加入url匹配项 url(r'courses/', CourseViewSet.as_view(), name='courses')]
简洁的方法route方法注册与绑定
from rest_framework.routers import DefaultRouterrouter = DefaultRouter() # 只需要实现一次router.register(r'courses', CourseViewSet, base_name='courses')urlpatterns = [ ... # 只需要加入一次 url(r'^', include(router.urls)),]
四. 修改 ModelViewSet 的默认返回信息
drf API 接口默认返回的只是数据的JSON字符串。源码发现这些返回信息是写在create()、list()、retrieve()、update()、destroy()这些方法里的
ModelViewSet直接继承了6个父类:
class ModelViewSet(mixins.CreateModelMixin, mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin, mixins.ListModelMixin, GenericViewSet): """ A viewset that provides default `create()`, `retrieve()`, `update()`, `partial_update()`, `destroy()` and `list()` actions. """ pass
类里面的对应的方法的return Response就可以了。以update为例:
class MyModelViewSet(viewsets.ModelViewSet): def update(self, request, *args, **kwargs): partial = kwargs.pop('partial', False) instance = self.get_object() serializer = self.get_serializer(instance, data=request.data, partial=partial) is_valid = serializer.is_valid(raise_exception=False) ####### if not is_valid: return Response({ 'code': 0, 'msg': '失败', 'data': serializer.errors}) self.perform_update(serializer) ###### if getattr(instance, '_prefetched_objects_cache', None): # If 'prefetch_related' has been applied to a queryset, we need to # forcibly invalidate the prefetch cache on the instance. instance._prefetched_objects_cache = { } return Response({ 'code': 1, 'msg': '成功', 'data': serializer.data})
或直接修改源码 测试如下
转载地址:https://blog.csdn.net/qq_35911309/article/details/113534397 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!