首页 > 其他分享 >drf-drf请求、响应、基于GenericAPIView+5个视图扩展类

drf-drf请求、响应、基于GenericAPIView+5个视图扩展类

时间:2023-02-03 22:55:38浏览次数:37  
标签:GenericAPIView return ser models self 视图 import drf name

1.反序列化类校验部分源码分析(了解)

1.当我们在视图类中生成一个序列化类对象ser,并且用ser.is_valid()是就会执行校验,校验通过返回True,不通过返回False。首先对象ser和序列化类中都没有方法is_valid()。
然后我们去其父类Serializer中找,也没找到,再去其父类BaseSerializer中找,找到了方法is_valid():

2.关键语句在于:self._validated_data = self.run_validation(self.initial_data)
self是序列化类BookSerializer的对象,从头开始找方法run_validation。此时我们不能按ctrl点run_validation方法,因为这样找到的是其父类fields中的run_validation。但是在BookSerializer对的父类Serializer中就可以找到名字run_validation。

3.可以发现在异常捕获中看到了我们之前见过的全局钩子名字:validate。所以当我们用ser点is_valid时会触发全局钩子进行校验。
    
4.value = self.to_internal_value(data)这一步是在进行局部钩子的校验。还是重头开始查找名字to_internal_value,最终在类Serializer中找到了名字to_internal_value:

    def to_internal_value(self, data):
	# fields是一个个字段名对象,field是字段名对象
        for field in fields:
	# 如果对象ser或其父类(BookSerializer)中有'validate_' + field.field_name的名字,例如validate_name,那么此时validate_method就是例如validate_name。
            validate_method = getattr(self, 'validate_' + field.field_name, None)        
            try:
                validated_value = field.run_validation(primitive_value)
                if validate_method is not None:
	# validate_method是validate_name,validated_value就是待校验的某个字段名,这也是为什么我们在局部钩子要上传字段名。
                    validated_value = validate_method(validated_value)
            except ValidationError as exc:
	# 如果有错误将每个字段名对应的错误添加到错误信息当中。
                errors[field.field_name] = exc.detail
            except DjangoValidationError as exc:
                errors[field.field_name] = get_error_detail(exc)
            except SkipField:
                pass
            else:
                set_value(ret, field.source_attrs, validated_value)

        if errors:
            raise ValidationError(errors)

        return ret
"""
面向对象中名字的查找顺序:每一次对象查找名字都要从自身的名称空间中查找,然后再到类名称空间,再到父类名称空间。
"""

2.断言

源码中大量使用try和断言:
	assert后面跟的语句如果成立,就会执行下面的语句;不成立则会马上抛出异常。但是异常信息无法编辑。
assert isinstance(111,int)
print('111是整形')  # 111是整形

assert isinstance(111,str)
print('111是整形')  # 报错:AssertionError

3.drf请求

1.Request能够解析的前端传入的编码格式
如果我们只想接收前端发送的json格式的数据,不接受其他形式发送的数据,我们需要做如下设置:
	方式一:局部配置:在继承自APIView及其子类的视图类中配置
from rest_framework.parsers import JSONParser,FormParser,MultiPartParser

class BookView(APIView):
    parser_classes = [JSONParser,]
    def post(self,request):
        print(request.data)
        ser = BookSerializer(data=request.data)
        if ser.is_valid():
            ser.save()
            return Response({'code':100,'msg':'新增成功'})
        else:
            return Response({'code':101,'msg':ser.errors})

	方式二:全局配置:在settings中设置,会影响全局,如果想禁用掉哪个提交方式,只需要注掉就可以。
REST_FRAMEWORK = {
    'DEFAULT_PARSER_CLASSES': [
        # 'rest_framework.parsers.JSONParser',
        'rest_framework.parsers.FormParser',
        # 'rest_framework.parsers.MultiPartParser',
    ],
}
"""
如果我们在全局配置了一种,部分视图函数需要三种,我们只需要在视图函数配置三种发送方式。因为配置查找顺序是:先从视图类自身查找,再到drf配置中找,再去drf默认配置中查找。
"""

2.Request类中的方法:
data,__getattr__,query_params

4.drf响应

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',
    ],
}
"""
优先使用视图类中的配置,其次使用项目匹配,最后使用那个内置的配置。
"""

5.Response源码属性或方法

当我们进到Response源码中发现有以下参数:
def __init__(self, data=None, status=None,
                 template_name=None, headers=None,
                 exception=False, content_type=None):
data:是我们返回给前端的数据,可以是字典、列表、字符串。我们之前写的ser.data就是data的内容。
status:响应状态码,默认是200,可以手动定义数字,也可以通过导模块来使用drf内部定义的响应状态码:

template_name:了解即可,修改响应模板的样子
content_type:响应编码格式,一般不动
headers:响应头

"""
在Http四件套中如何添加响应头?
def indexfunc(request):
    obj = HttpResponse('hhh')  先生成一个HttpResponse的对象
    obj['msg'] = 'success'	给对象添加键值对
    return obj
"""

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

1.APIView跟之前的View区别
	传入到视图方法中的是REST framework的Request对象,而不是Django的HttpRequeset对象;
	视图方法可以返回REST framework的Response对象-
	任何APIException异常都会被捕获到,并且处理成合适的响应信息;
	在进行dispatch()分发前,会对请求进行身份认证、权限检查、流量控制
    
 2.APIView类属性:
   renderer_classes # 响应格式
    parser_classes #能够解析的请求格式
    authentication_classes#认证类
    throttle_classes#频率类
    permission_classes#权限类
    
3.APIView+ModelSerializer+Resposne写5个接口:
serializer.py:
from rest_framework import serializers
from app01.models import Book
from rest_framework.exceptions import ValidationError


class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = ['name','price','publish','authors','publish_detail','author_list']
        extra_kwargs = {
            'name':{'max_length':8},
            'publish_detail':{'read_only':True},
            'author_list':{'read_only':True},
            'publish':{'write_only':True},
            'authors':{'write_only':True}
        }

    def validate_name(self,name):
        if name.startswith('s'):
            raise ValidationError('书名不能以s开头')
        else:
            return name
        
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')

    @property
    def publish_detail(self):
        return {'name':self.publish.name,'addr':self.publish.addr}

    @property
    def author_list(self):
        l = []
        for author_obj in self.authors.all():
            l.append({'name':author_obj.name,'phone':author_obj.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)

views.py:
from rest_framework.views import APIView
from rest_framework.response import Response
from app01.models import Book
from .serializer import BookSerializer

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


    def post(self,request):
        ser = BookSerializer(data=request.data)
        if ser.is_valid():
            ser.save()
            return Response({'code':100,'msg':'新增成功','result':ser.data})
        else:
            return Response({'code':101,'msg':ser.errors})


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

    def put(self,request,pk):
        book_obj = Book.objects.filter(pk=pk).first()
        ser = BookSerializer(instance=book_obj,data=request.data)
        if ser.is_valid():
            ser.save()
            return Response({'code':100,'msg':'修改成功','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':'删除成功'})
    
urls.py:
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())
]

7.基于GenericAPIView写接口

1.GenericAPIView两个重要的类属性:
queryset:序列化或反序列化指定的queryset,需要指定
serializer_class:序列化类需要指定
lookup_field:查询单条的路由通过转换器分出来的字段名
filter_backends:过滤器的配置
pagination_class:分页器的配置
    
2.方法:
get_queryset:获取序列化的对象
get_object:获取单个对象,查找时不需要在括号内上传参数pk
get_seriializer:获取序列化类(和它差不多的:get_serializer_class:一般重写它,不调用它)
filter_queryset:过滤器有关
    
3.代码:
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')

    @property
    def publish_detail(self):
        return {'name':self.publish.name,'addr':self.publish.addr}

    @property
    def author_list(self):
        l = []
        for author_obj in self.authors.all():
            l.append({'name':author_obj.name,'phone':author_obj.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)
    
serializer.py:(和之前没变)
from rest_framework import serializers
from app01.models import Book
from rest_framework.exceptions import ValidationError


class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = ['name','price','publish','authors','publish_detail','author_list']
        extra_kwargs = {
            'name':{'max_length':8},
            'publish_detail':{'read_only':True},
            'author_list':{'read_only':True},
            'publish':{'write_only':True},
            'authors':{'write_only':True}
        }

    def validate_name(self,name):
        if name.startswith('s'):
            raise ValidationError('书名不能以s开头')
        else:
            return name
        
views.py:
rom rest_framework.response import Response
from app01.models import Book
from .serializer import BookSerializer
from rest_framework.generics import GenericAPIView

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

    def get(self, request):
        # 在这里不能直接self.queryset,而是要用drf提供的get_queryset()方法,objs拿到的还是类中的queryset
        objs = self.get_queryset()
        # 序列化类也要用指定的方法
        ser = self.get_serializer(instance=objs, many=True)
        return Response(ser.data)

    def post(self, request):
        ser = self.get_queryset(data=request.data)
        if ser.is_valid():
            ser.save()
            return Response({'code':100,'msg':'新增成功','result':ser.data})
        else:
            return Response({'code':101,'msg':ser.errors})
from rest_framework.mixins import ListModelMixin

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

    def get(self,request,pk):
        obj = self.get_object()
        ser = self.get_serializer(instance=obj)
        return Response(ser.data)

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


    def delete(self,request,pk):
        self.get_object().delete()
        return Response({'code':100,'msg':'删除成功'})
"""
到这一步我们再写其他的表,只需要改变类中:
queryset = Book.objects.all()
serializer_class = BookSerializer
即可
"""

8.基于GenericAPIView+5个视图扩展类

针对接口中5个不同的功能,drf提供了5个不同的类:CreateModelMixin,UpdateModelMixin,DestroyModelMixin,RetrieveModelMixin,ListModelMixin。这些类封装了5个功能中重复的代码。
urls.py:
urlpatterns = [
    path('admin/', admin.site.urls),
    path('books/',views.BookView.as_view()),
    path('books/<int:pk>/',views.BookDetailView.as_view())
]

views.py:
    
from app01.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,UpdateModelMixin,DestroyModelMixin,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)
    
serializer.py:
from rest_framework import serializers
from app01.models import Book
from rest_framework.exceptions import ValidationError


class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = ['name','price','publish','authors','publish_detail','author_list']
        extra_kwargs = {
            'name':{'max_length':8},
            'publish_detail':{'read_only':True},
            'author_list':{'read_only':True},
            'publish':{'write_only':True},
            'authors':{'write_only':True}
        }

    def validate_name(self,name):
        if name.startswith('s'):
            raise ValidationError('书名不能以s开头')
        else:
            return name

标签:GenericAPIView,return,ser,models,self,视图,import,drf,name
From: https://www.cnblogs.com/zkz0206/p/17090649.html

相关文章

  • DRF视图组件
    DRF视图组件 文章目录DRF视图组件一、视图视图继承关系二、2个视图基类1.APIViewAPIView与View示例小结2.GenericAPIView(通用视图类)1.......
  • 视图组件介绍及两个视图基类
    1.反序列化类校验码部分源码解析(了解)#反序列化校验,什么时候,开始执行校验 -视图类中的ser.is_valid(),就会执行校验,校验通过返回True,不通过返回False#入口:ser.is_va......
  • 反序列化类校验部分源码解析,断言,drf之请求与响应
    反序列化类校验部分源码解析反序列化校验,什么时候开始执行校验(切入点)视图类中的ser.is_valid(),就会执行校验,校验通过返回True,不通过返回False入口:ser.is_valid()......
  • drf-请求/相应/视图组件/
    内容概要反序列化类校验部分源码解析断言drf-请求drf-响应视图组件介绍及两个视图基类基于GenericAPIView+5个视图扩展类反序列化类校验部分源码分析......
  • drf从入门到精通 05
    今日内容详细1.反序列化类校验部分源码解析#反序列化校验什么时候开始执行校验 -视图类中的ser.is_valid()就会开始执行校验校验通过返回True不通过返回False......
  • django框架之drf(部分讲解)
    一、反序列化类校验部分源码解析(了解即可)反序列化校验,什么时候,开始执行校验?视图类中的ser.is_valid(),就会执行校验,校验通过返回True,不通过返回False源码入口#......
  • drf-day5——反序列化类校验部分源码分析、断言、drf请求、drf响应、视图组件及两个视
    目录一、反序列化类校验部分源码解析(了解)二、断言三、drf之请求3.1Request能够解析的前端传入的编码格式3.2Request类有哪些属性和方法(学过)常用参数Response类的实例化......
  • drf之路由Routers
    #2.路由Routers对于视图集ViewSet,我们除了可以自己手动指明请求方式与动作action之间的对应关系外,还可以使用Routers来帮助我们快速实现路由信息。如果是非视图集,不需......
  • Django框架之drf:5、反序列化器校验部分源码分析、断言、drf之请求与响应、视图组件介
    Django框架之drf目录Django框架之drf一、反序列化类校验部分源码解析二、断言三、drf之请求1、Request能够解析的前端传入编码格式2、Request类中的属性和方法四、drf之......
  • drf之视图集ViewSet
    ##1.3视图集ViewSet使用视图集ViewSet,可以将一系列视图相关的代码逻辑和相关的http请求动作封装到一个类中:-list()提供一组数据-retrieve()提供单个数据-crea......