python之路63 drf从入门到成神 4 反序列化类校验部分源码解析、断言、drf请求、响应格式配置、视图组件介绍及两个视图基类、基于GenericAPIView+5个视图扩展类

导读:本篇文章讲解 python之路63 drf从入门到成神 4 反序列化类校验部分源码解析、断言、drf请求、响应格式配置、视图组件介绍及两个视图基类、基于GenericAPIView+5个视图扩展类,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

反序列化类校验部分源码解析

# 反序列化校验、什么时候开始执行校验
    视图类中的  ser.is_valid(),就会执行校验,校验通过返回True,不通过返回False


# 入口:ser.is_valid() 是序列化类的对象,假设序列化类是BookSerializer--》is_valid()---》找不到, 找到父类BookSerializer中有:【raise_exception:先注意】
    def is_valid(self, *, raise_exception=False):

        if not hasattr(self, '_validated_data'):
            try:
                # self序列化类的对象,属性中没有_validated_data,一定会走这句【核心】
                self._validated_data = self.run_validation(self.initial_data)
            except ValidationError as exc:
                self._validated_data = {}
                self._errors = exc.detail
            else:
                self._errors = {}

        if self._errors and raise_exception:
            raise ValidationError(self.errors)

        return not bool(self._errors)
# self._validated_data = self.run_validation(self.initial_data)  核心---》self序列化类的对象
    切记一定不要按住ctrl键点击
    真正的执行顺序是,从上往下找,找不到,再往上
    最终从Serializer类中找到了run_validation而不是Field中的run_validation

    def run_validation(self, data=empty):
         # 字段自己的  validates方法
        (is_empty_value, data) = self.validate_empty_values(data)
        if is_empty_value:
            return data
        # 局部钩子 ----【局部钩子】
        value = self.to_internal_value(data)
        try:
            self.run_validators(value)
            # 全局钩子---》如果在BookSerializer中写了validate,优先走它 非常简单
            value = self.validate(value)

        except (ValidationError, DjangoValidationError) as exc:
            raise ValidationError(detail=as_serializer_error(exc))

        return value
# 局部钩子  self.to_internal_value(data) ---》self是BookSerializer的对象 从根上找
     def to_internal_value(self, data):

        ret = OrderedDict()
        errors = OrderedDict()
        fields = self._writable_fields
        # fields写在序列化类中一个个字段类的对象
        for field in fields:
            # self BookSerializer的对象,反射validate_name
            validate_method = getattr(self, 'validate_' + field.field_name, None)
            try:
               # 在执行BookSerializer类中的validate_name方法,传入了要校验的数据
                validated_value = validate_method(validated_value)
            except ValidationError as exc:
                errors[field.field_name] = exc.detail
            else:
                set_value(ret, field.source_attrs, validated_value)

        if errors:
            raise ValidationError(errors)

        return ret

断言assert

# 源码中大量使用try和断言

# 关键字assert,有什么作用,断定是xx   如果不是就抛异常

name = 'lqz'

# if name == 'lqz':
#     print('对了')
# else:
#     # print('错了')
#     raise Exception('名字不为lqz,不能继续走了')


assert name=='lqz'   # 断定是,如果不是,就抛异常

print('后续代码')

drf请求

Request能够解析的前端传入的编码格式

# 需求是该接口只能介绍json格式,不能接收其他格式

# 方式一 在继承自APIView及其子类的视图类中配置(局部配置)
# 总共有三个:from rest_framework.parsers import JSONParser,FormParser,MultiPartParser

class BookView(APIView):
    parser_classes = [JSONParser,]


# 方式二:在配置文件中配置(影响所有,全局配置)
     django有套默认配置,每个项目有个配置
     drf也有套默认,每个项目也有个配置----》就在django的配置文件中
     REST_FRAMEWORK = {
    'DEFAULT_PARSER_CLASSES': [
        'rest_framework.parsers.JSONParser',
        'rest_framework.parsers.FormParser',
        'rest_framework.parsers.MultiPartParser',
    ],
}

# 方式三:全局配了1个,某个视图类想要3个,怎么配?
     只需要在视图类,配置3个即可
     因为:先从视图类自身配置找,找不到,去项目的drf配置中找,再找不到,去drf默认的配置找

Request类有哪些属性和方法(前面写过了)

     1  新的request用起来,跟之前一模一样,因为新的取不到,会取老的__getattr__
     2 request.data  无论什么编码,什么请求方式,只要是body中的数据,就从这里取,字典
     3 request.query_params 就是原来的request._request.GET
     4 上传的文件从request.FILES里面取

drf之响应

Response能够响应的编码格式

drf  是django的一个app 所以需要注册
drf 的响应,如果使用浏览器和postman访问同一个接口,返回格式是不一样的

    drf做个判断 如果是浏览器 好看一些 如果是postman只要json数据

方式一 : 在视图类中写(局部配置)
    两个响应类---》找--》drf的配置文件中找---》两个类
    from rest_framework.renderers import JSONRenderer,BrowsableAPIRenderer
    class BookView(APIView):
        renderer_classes=[JSONRenderer,]

# 方式二:在项目配置文件中写(全局配置)
    REST_FRAMEWORK = {
      'DEFAULT_RENDERER_CLASSES': [
        'rest_framework.renderers.JSONRenderer', 'rest_framework.renderers.BrowsableAPIRenderer',
    ],
}

# 方式三:使用顺序(一般就用内置的即可)
     优先使用视图类中的配置,其次使用项目配置文件中的配置,最后使用内置的

Response的源码属性或方法

drf 的Response源码分析
    from rest_framework.response import Response
    视图类的方法返回时,return Response,走它的__init__,ini中可以传什么参数
    
# Response init可以传的参数
     def __init__(self,
              data=None,
              status=None,
              template_name=None,
              headers=None,
              exception=False,
              content_type=None)

      data:之前咱们写的ser.data 可以是字典或列表,字符串---》序列化后返回给前端---》前端在响应体中看到的就说这个

      status:http响应的状态码,默认是200 可以改
     
          drf在status包下,把所有http响应状态码都写一遍 常量

          from rest_framework.status import HTTP_200_OK
              def get(self, request):
                  return Response('ddd',                 status=status.HTTP_200_OK)
       template_name: 了解即可  修改响应模板的样子,BrowsableAPIRenderer定死的样子,后期公司可以自己定制
    
    headers:响应头 http响应的响应头
      原生django 如何向响应头中加东西
         # 四件套 render,redirect,HttpResponse,JsonResponse
        obj = HttpResponse('ddd')
        obj['xxxc'] = 'yyy'
        return obj

    content_type:响应编码格式,一般不动

重点:data,status,headers

视图组件介绍及两个视图基类

drf 视图,视图类,学过APIView,drf的基类drf提供最顶层的类

# APIView跟之前的View区别
   传入到视图方法中的是REST framework的Request对象,而不是Django的HttpRequest对象;
   视图方法可以返回REST framework的Response对象
   任何APIException异常都会被捕获到,并且处理成合适的响应信息
   在进行dipatch()分发前,会对请求进行身份认证、权限检查、流量控制
   

# 两个视图基类
   APIView
       类属性:
          renderer_classes  # 响应格式
          parser_classes    # 能够解析的请求格式   
          authentication_classes # 认证类
          throttle_classes   # 频率类
          permission_classes # 权限类

models.py里表模型代码 注释为其中一种定制方法
     from django.db import models

class Book(models.Model):
    name = models.CharField(max_length=32)
    price = models.CharField(max_length=32)

    publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE)  # 留住,还有很多
    authors = models.ManyToManyField(to='Author')

    # def publish_detail(self):
    #     return {'name': self.publish.name, 'addr': self.publish.addr}
    #
    # def author_list(self):
    #     l = []
    #     for author in self.authors.all():
    #         l.append({'name': author.name, 'phone': author.phone})
    #         return l


class Publish(models.Model):
    name = models.CharField(max_length=32)
    addr = models.CharField(max_length=32)


class Author(models.Model):
    name = models.CharField(max_length=32)
    phone = models.CharField(max_length=11)

基于APIView+ModelSerializer+Response写5个接口

视图类
from .models import Book
from .serializer import BookSerializer
from rest_framework.views import APIView
from rest_framework.response import Response



class BookView(APIView):
    def get(self, request):
        books = Book.objects.all()
        ser = BookSerializer(instance=books, many=True)
        return Response(ser.data)

    def post(self, request):
        ser = BookSerializer(data=request.data)
        if ser.is_valid():
            ser.save()
            # 咱们现在只要ser序列化类的对象,但是咱们想要,新增的对象--》序列化成字典 --》大前提 序列化类中的create方法一定要返回新增的对象
            return Response({'code': 100, 'mag': '新增成功', 'result': ser.data})
        else:
            return Response({'code': 101, 'msg': ser.errors})


class BookDetailView(APIView):
    def get(self, request, pk):
        books = Book.objects.filter(pk=pk).first()
        ser = BookSerializer(instance=books)
        return Response(ser.data)

    def put(self, request, pk):
        books = Book.objects.filter(pk=pk).first()
        ser = BookSerializer(instance=books, data=request.data)
        if ser.is_valid():
            ser.save()
            return Response({'code': 100, 'mag': '修改成功', 'result': ser.data})
        else:
            return Response({'code': 101, 'msg': ser.errors})

    def delete(self, request, pk):
        Book.objects.filter(pk=pk).delete()
        return Response({'code': 100, 'msg': '删除成功'})


序列化类
两种定制字段方式 注释部分和表模型中配合使用

from rest_framework import serializers
from .models import Book, Publish, Author
from rest_framework.exceptions import ValidationError


class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book

        # fields = '__all__'
        fields = ['name', 'price', 'publish_detail', 'author_list', 'publish', 'authors']

        extra_kwargs = {'name': {'max_length': 8},
                        # 'publish_detail': {'read_only': True},
                        # 'author_list': {'read_only': True},
                        'publish': {'write_only': True},
                        'authors': {'write_only': True}, }

    publish_detail = serializers.SerializerMethodField(read_only=True)

    def get_publish_detail(self, obj):
        return {'name': obj.publish.name, 'addr': obj.publish.addr}

    author_list = serializers.SerializerMethodField(read_only=True)

    def get_author_list(self, obj):
        l = []
        for author in obj.authors.all():
            l.append({'name': author.name, 'phone': author.phone})
        return l

    def validate_name(self, name):
        if name.startswith('sb'):
            raise ValidationError('不能以sb开头')

        else:
            return name

路由
from django.contrib import admin
from django.urls import path
from app01 import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('books/', views.BookView.as_view()),
    path('books/<int:pk>/', views.BookDetailView.as_view()),
 
]

基于GenericAPIView+ModelSerializer+Response写5个视图接口

视图类
from .models import Book
from .serializer import BookSerializer
from rest_framework.response import Response

from rest_framework.generics import GenericAPIView

class BookView(GenericAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

    def get(self, request):
        objs = self.get_queryset()
        ser = BookSerializer(instance=objs, many=True)
        return Response(ser.data)

    def post(self, request):

        ser = self.get_serializer(data=request.data)
        if ser.is_valid():
            ser.save()
            # 咱们现在只要ser序列化类的对象,但是咱们想要,新增的对象--》序列化成字典 --》大前提 序列化类中的create方法一定要返回新增的对象
            return Response({'code': 100, 'mag': '新增成功', 'result': ser.data})
        else:
            return Response({'code': 101, 'msg': ser.errors})


class BookDetailView(GenericAPIView):

    queryset = Book.objects.all()
    serializer_class = BookSerializer

    def get(self, request):

        obj = self.get_object()
        ser = self.get_serializer(instance=obj)
        return Response(ser.data)

    def put(self, request):
        obj = self.get_object()
        ser = self.get_serializer(instance=obj, data=request.data)
        if ser.is_valid():
            ser.save()
            return Response({'code': 100, 'mag': '修改成功', 'result': ser.data})
        else:
            return Response({'code': 101, 'msg': ser.errors})

    def delete(self, request):
        self.get_object().delete()
        return Response({'code': 100, 'msg': '删除成功'})

序列化类


from rest_framework import serializers
from .models import Book, Publish, Author
from rest_framework.exceptions import ValidationError


class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book

        # fields = '__all__'
        fields = ['name', 'price', 'publish_detail', 'author_list', 'publish', 'authors']

        extra_kwargs = {'name': {'max_length': 8},
                        # 'publish_detail': {'read_only': True},
                        # 'author_list': {'read_only': True},
                        'publish': {'write_only': True},
                        'authors': {'write_only': True}, }

    publish_detail = serializers.SerializerMethodField(read_only=True)

    def get_publish_detail(self, obj):
        return {'name': obj.publish.name, 'addr': obj.publish.addr}

    author_list = serializers.SerializerMethodField(read_only=True)

    def get_author_list(self, obj):
        l = []
        for author in obj.authors.all():
            l.append({'name': author.name, 'phone': author.phone})
        return l

    def validate_name(self, name):
        if name.startswith('sb'):
            raise ValidationError('不能以sb开头')

        else:
            return name

路由
from django.contrib import admin
from django.urls import path
from app01 import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('books/', views.BookView.as_view()),
    path('books/<int:pk>/', views.BookDetailView.as_view()),
 
]

基于GenericAPIView+Response写5个接口总结

### 咱们能不能想一种方式,通过继承,少些代码-----》GenericAPIView---》继承了APIView,有很多新的属性和方法
# 以后咱们可以基于这个类,来写5个接口
# 5个接口的效果一样,但是咱们代码 可用性变高了
# GenericAPIView 属性和方法
'''
# 属性
1 queryset:要序列化或反序列化的表模型数据
2 serializer_class:使用的序列化类
3 lookup_field :查询单条的路由分组分出来的字段名
4 filter_backends:过滤类的配置(了解)
5 pagination_class:分页类的配置(了解)

# 方法
1 get_queryset   :获取要序列化的对象
2 get_object  :获取单个对象
3 get_serializer :获取序列化类  ,跟它差不多的get_serializer_class,一般重写它,不调用它
4 filter_queryset  :过滤有关系(了解)
'''

基于GenericAPIView+5个视图扩展类

视图类

# CreateModelMixin 新增   create 方法
# UpdateModelMixin 更新   destroy方法
# DestroyModelMixin 删除   retrieve方法
# RetrieveModelMixin 查单条 list方法
# ListModelMixin   查多条   update方法

from .models import Book
from .serializer import BookSerializer
from rest_framework.generics import GenericAPIView

from rest_framework.mixins import CreateModelMixin, UpdateModelMixin, DestroyModelMixin, RetrieveModelMixin, \
    ListModelMixin


class BookView(GenericAPIView, ListModelMixin, CreateModelMixin):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

    def get(self, request):
        return self.list(request)

    def post(self, request):
        return self.create(request)


class BookDetailView(GenericAPIView, DestroyModelMixin, UpdateModelMixin, RetrieveModelMixin):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

    def get(self, request, *args, **kwargs):
        return self.retrieve(request, *args, **kwargs)

    def put(self, request, *args, **kwargs):
        return self.update(request, *args, **kwargs)

    def delete(self, request, *args, **kwargs):
        return self.destroy(request, *args, **kwargs)

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由半码博客整理,本文链接:https://www.bmabk.com/index.php/post/98736.html

(0)

相关推荐

半码博客——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!