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)),
]

 

 

 

认证组件:

模型层:models.py

class User(BaseModel):
   username = models.CharField(verbose_name='用户名', max_length=32)
   password = models.CharField(verbose_name='密码', max_length=64)


class Car(BaseModel):
   name = models.CharField(verbose_name='汽车品牌', max_length=32)
   price = models.DecimalField(verbose_name='价格', max_digits=11, decimal_places=2, default=1.00)

序列化层:serializer.py

from rest_framework import serializers
from . import models
class UsersModelSerializer(serializers.ModelSerializer):
   class Meta:
       model = models.User
       fields = ('username', 'password')
       extra_kwargs = {}

class CarsModelSerializer(serializers.ModelSerializer):
   class Meta:
       model = models.Car
       fields = ('name', 'price')
       extra_kwargs = {}

视图层:views.py

from rest_framework import generics, viewsets, mixins
from . import models, serializers


# 局部禁用:视图类中 authentication_classes 字段可以完成局部控制
class UsersRetrieveAPIView(generics.RetrieveAPIView):
   # 局部解除认证
   authentication_classes = ()
   queryset = models.User.objects.filter(is_delete=False)
   serializer_class = serializers.UsersModelSerializer


from . import authentication
class CarsGenericViewSet(mixins.RetrieveModelMixin, mixins.ListModelMixin, viewsets.GenericViewSet):
   # 局部完成禁用
   authentication_classes = (authentication.TokenAuthentication, )
   queryset = models.Car.objects.filter(is_delete=False)
   serializer_class = serializers.CarsModelSerializer

路由层:urls.py

from django.conf.urls import url, include
from . import views
urlpatterns = [
   url(r'^users/(?P<pk>\d+)/', views.UsersRetrieveAPIView.as_view()),

   url(r'^cars/$', views.CarsGenericViewSet.as_view({'get': 'list'})),
   url(r'^cars/(?P<pk>\d+)/', views.CarsGenericViewSet.as_view({'get': 'retrieve'})),
]
posted on 2019-08-19 17:28  郝俊连城  阅读(276)  评论(0)    收藏  举报