python

DRF

2019-06-30  本文已影响0人  不咸的Yan

Django REST framework
在序列化与反序列化时,虽然操作的数据不尽相同,但是执行的过程却是相似的,也就是说这部分代码是可以复用简化编写的。
在开发REST API的视图中,虽然每个视图具体操作的数据不同,但增、删、改、查的实现流程基本套路化,所以这部分代码也是可以复用简化编写的:
增:校验请求数据 -> 执行反序列化过程 -> 保存数据库 -> 将保存的对象序列化并返回
删:判断要删除的数据是否存在 -> 执行数据库删除
改:判断要修改的数据是否存在 -> 校验请求的数据 -> 执行反序列化过程 -> 保存数据库 -> 将保存的对象序列化并返回
查:查询数据库 -> 将数据序列化并返回
Django REST framework 框架是一个用于构建Web API 的强大而又灵活的工具。
通常简称为DRF框架 或 REST framework。
DRF框架是建立在Django框架基础之上,由Tom Christie大牛二次开发的开源项目
特点
提供了定义序列化器Serializer的方法,可以快速根据 Django ORM 或者其它库自动序列化/反序列化;
提供了丰富的类视图、Mixin扩展类,简化视图的编写;
丰富的定制层级:函数视图、类视图、视图集合到自动生成 API,满足各种需要;
多种身份认证和权限认证方式的支持;
内置了限流系统;
直观的 API web 界面;
可扩展性,插件丰富

开发方式


特点


序列化器

序列化:
序列化(serialization)
在计算机科学的资料处理中,是指将数据结构或物件状态转换成可取用格式(例如存成档案,存于缓冲,或经由网络中传送),以留待后续在相同或另一台计算机环境中,能恢复原先状态的过程。
依照序列化格式重新获取字节的结果时,可以利用它来产生与原始物件相同语义的副本。对于许多物件,像是使用大量参照的复杂物件,这种序列化重建的过程并不容易。
面向对象中的物件序列化,并不概括之前原始物件所关联的函式。这种过程也称为物件编组(marshalling)。
从一系列字节提取数据结构的反向操作,是反序列化(也称为解编组, deserialization, unmarshalling)。

​ 在数据储存与传送的部分是指将一个对象)存储至一个储存媒介,例如档案或是记亿体缓冲等,或者透过网络传送资料时进行编码的过程,可以是字节或是XML等格式。而字节的或XML编码格式可以还原完全相等的对象)。这程序被应用在不同应用程序之间传送对象),以及服务器将对象)储存到档案或数据库。相反的过程又称为反序列化。



基本序列化器

from rest_framework.serializers import Serializer
作用: 进行数据的校验 对数据对象进行转换
使用:

1 为模型类提供序列化器,定义一个Serializer类


class BookInfoSerializer(serializers.Serializer):
"""图书数据序列化器"""
    id = serializers.IntegerField(label='ID', read_only=True)
    btitle = serializers.CharField(label='名称', max_length=20)
    bpub_date = serializers.DateField(label='发布日期', required=False)
    bread = serializers.IntegerField(label='阅读量', required=False)
    bcomment = serializers.IntegerField(label='评论量', required=False)
    image = serializers.ImageField(label='图片', required=False)

字段与选项

字段
字段构造方式
BooleanField
BooleanField()
ImageField
ImageField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL)
CharField
CharField(max_length=None, min_length=None, allow_blank=False, trim_whitespace=True)
EmailField
EmailField(max_length=None, min_length=None, allow_blank=False)
RegexField
RegexField(regex, max_length=None, min_length=None, allow_blank=False)
FileField
FileField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL)
IntegerField
IntegerField(max_value=None, min_value=None)
UUIDField
UUIDField(format='hex_verbose') 
format: 
1) 'hex_verbose' 如"5ce0e9a5-5ffa-654b-cee0-1238041fb31a" 
2) 'hex' 如 "5ce0e9a55ffa654bcee01238041fb31a" 
3)'int' - 如: "123456789012312313134124512351145145114" 
4)'urn' 如: "urn:uuid:5ce0e9a5-5ffa-654b-cee0-1238041fb31a"
FloatField
FloatField(max_value=None, min_value=None)
TimeField
TimeField(format=api_settings.TIME_FORMAT, input_formats=None)
DateField
DateField(format=api_settings.DATE_FORMAT, input_formats=None)
DecimalField
DecimalField(max_digits, decimal_places, coerce_to_string=None, max_value=None, min_value=None)
max_digits: 最多位数
decimal_palces: 小数点位置
DateTimeField
DateTimeField(format=api_settings.DATETIME_FORMAT, input_formats=None)


选项参数

参数名称
作用
max_length
最大长度
min_length
最小长度
allow_blank
是否允许为空
trim_whitespace
是否截断空白字符
max_value
最小值
min_value
最大值

通用参数

参数名称
说明
read_only
表明该字段仅用于序列化输出,默认False
write_only
表明该字段仅用于反序列化输入,默认False
required
表明该字段在反序列化时必须输入,默认True
default
反序列化时使用的默认值
allow_null
表明该字段是否允许传入None,默认False
validators
该字段使用的验证器
error_messages
包含错误编号与错误信息的字典
label
用于HTML展示API页面时,显示的字段名称
help_text
用于HTML展示API页面时,显示的字段帮助提示信息

备注:


2 创建Serializer对象
ser = Serializer(instance=None, data=empty, **kwarg)


输出ser 可以打印出ser的字段信息
3 根据传入的参数。进行序列化/反序列化操作

序列化过程


class BookInfoSerializer(serializers.Serializer):
"""图书数据序列化器"""
    id = serializers.IntegerField(label='ID', read_only=True)
    btitle = serializers.CharField(label='名称', max_length=20)
    bpub_date = serializers.DateField(label='发布日期', required=False)
    bread = serializers.IntegerField(label='阅读量', required=False)
    bcomment = serializers.IntegerField(label='评论量', required=False)
    image = serializers.ImageField(label='图片', required=False)
    heroinfo_set = serializers.PrimaryKeyRelatedField(read_only=True, many=True)  # 新增many=True

from booktest.serializers import BookInfoSerializer
from booktest.models import BookInfo
book = BookInfo.objects.get(id=2)
serializer = BookInfoSerializer(book)
serializer.data
# {'id': 2, 'btitle': '天龙八部', 'bpub_date': '1986-07-24', 'bread': 36, 'bcomment': 40, 'image': None, 'heroinfo_set': [6,8, 9]}

反序列化过程


流程
1 postman给data构造参数
注意 json数据最后不加逗号。 json数据中的True,False。都应该 小写
2 验证 is_valid()
ser.is_valid( raise_exception=true)
验证失败的话,REST framework接收到此异常,直接给前端返回一个HTTP 400 Bad Request响应,不再返回T/F

在序列化器外定义函数
def about_django(value):
  if 'django' not in value.lower():
  raise serializers.ValidationError("图书不是关于Django的")


字段中添加参数
class BookInfoSerializer(serializers.Serializer):
"""图书数据序列化器"""
    id = serializers.IntegerField(label='ID', read_only=True)

    btitle = serializers.CharField(label='名称', max_length=20, validators=[about_django])

    bpub_date = serializers.DateField(label='发布日期', required=False)
    bread = serializers.IntegerField(label='阅读量', required=False)
    bcomment = serializers.IntegerField(label='评论量', required=False)
    image = serializers.ImageField(label='图片', required=False)

3 保存 ser.save()


class BookInfoSerializer(serializers.Serializer):
"""图书数据序列化器"""
    ...
    def create(self, validated_data):
"""新建"""
        returnBookInfo.objects.create(**validated_data)

    def update(self, instance,validated_data):
"""更新,instance为要更新的对象实例"""
        instance.btitle = validated_data.get('btitle', instance.btitle)
        instance.bpub_date = validated_data.get('bpub_date', instance.bpub_date)
        instance.bread = validated_data.get('bread', instance.bread)
        instance.bcomment = validated_data.get('bcomment', instance.bcomment)
        instance.save()
        return instance

create 传入validated_data
    def create(self, validated_data):
         #保存数据
         # 方法1
        # book=BookInfo()
        # book.btitle = validated_data['btitle']
        # book.bpub_date = validated_data['bpub_date']
        # book.bread = validated_data['bread']
        # book.bcomment = validated_data['bcomment']
        # book.is_delete = validated_data['is_delete']
        # book.save()
         #方法2
        book=BookInfo.objects.create(btitle = validated_data['btitle'],bpub_date = validated_data['bpub_date'],bread = validated_data['bread'],bcomment = validated_data['bcomment'],is_delete = validated_data['is_delete'])
        return book

创建序列化器对象的时候,
from db.serializers import BookInfoSerializer
data = {'btitle': '封神演义'}
serializer = BookInfoSerializer(data=data)  没有实例的传入,得到的数据新增到数据库
serializer.is_valid()  # True
serializer.save()  # <BookInfo: 封神演义>



from db.models import BookInfo
book = BookInfo.objects.get(id=2)
data = {'btitle': '倚天剑'}
serializer = BookInfoSerializer(book, data=data)   传入实例,在实例的基础上进行数据修                            改,更新实例对象
serializer.is_valid()  # True
serializer.save()  # <BookInfo: 倚天剑>
book.btitle  # '倚天剑'
模型类序列化器 ModelSerializer

from rest_framework . serializers import ModelSerializer 继承基本的序列化器 serializers
继承serializers,更高一层的封装,在Meta中对模型、字段进行设置,与基本序列化器相比,字段不用自己写了


流程
1 创建序列化器 serializers.py
定义序列化器,指定对应的模型类、控制的字段,定义对字段校验的方法
from rest_framework import serializers
from book.models import BookInfo

class BookModelSerializer(serializers.ModelSerializer):
    image_code = serializers.CharField(max_length=4,min_length=4,allow_null=True)
    class Meta:
        model = BookInfo
        # 所有字段都选中
        # fields = "__all__"
        # fields = ['btitle','bread','bcomment','bpub_date']  
        exclude = ['is_delete']
        read_only_fields = ['bread','bcomment']
        extra_kwargs = {
            'btitle':{
                'min_length':'10',
            }
        }

2 编写视图 views.py
定义视图,指定序列化器的类、指定查询集

from rest_framework.viewsets import ModelViewSet
from DRF.serializer import BookSerializer   引入刚才所创建的序列化器
from book.models import BookInfo


class DRFBookViewSet(ModelViewSet):
queryset = BookInfo.objects.all()    指明该视图集在查询数据时使用的查询集
serializer_class = BookSerializer    指明该视图在进行序列化或反序列化时使用的序列化器

3 定义路由 urls.py
配置路由,应用了rest_framework可以自动生成url,

from . import views
from rest_framework.routers import DefaultRouter

urlpatterns = [
    ...
]

router = DefaultRouter()  # 可以处理视图的路由器
router.register(r'books', views.BookInfoViewSet)  # 向路由器中注册视图集

urlpatterns += router.urls  # 将路由器中的所有路由信息追到到django的路由列表中

判断使用哪种序列化类
根据操作的字段是否和模型类有关系来判断用那种序列化器
有关 模型类 ModelSerializer
无关 基本类Serializer

视图

在原先Django框架视图中的简化

import json
from DRF.serializer import BookSerializer,HeroSerializer
from book.models import BookInfo,HeroInfo
from django.views import View
from django.http import HttpResponse,JsonResponse

class DRFView(View):      #继承Django的View视图
    def get(self,request):
        books = BookInfo.objects.all()
        ser = BookSerializer(books,many=True)   
        #使用序列化器进行操作 注意  many=True
        return JsonResponse(ser.data,safe=False)      
        #在初始化json响应对象时,safe默认是True,非字典数据无法传输,设置为False,允许非字典数据传输
        #safe=False 非字典传输    将列表格式的数据(在前端叫做数组)也可转成json进行传输
        #为True,会提示(In order to allow non-dict objects to be serialized set the safe parameter to False.)

    def post(self,request):
        #获取数据
        json_byte = request.body
        json_str = json_byte.decode()
        json_dict = json.loads(json_str)

        #将数据传入序列化器
        ser = BookSerializer(data=json_dict)
        #校验
        ser.is_valid()#判断不通过直接报错,给前端返回400
        print(ser.is_valid())
        print(ser.errors)
        #保存是模型对象
        ser.save()
        return JsonResponse(ser.data,safe=False)

作用
控制序列化器的执行(校验,保存,转换数据)
控制数据库查询的执行

Request

常用属性:
对Django的request更高封装(GET,POST,body,meta)
request.data 返回解析之后的请求体数据。类似于Django中标准的request.POST和request.FILES属性

request.query_params

url(^(?P<mobile>\d+)/$),views.方法()
在后端中,
def get(self,request,mobile):
    正则匹配到的mobile可以直接作为参数传递使用


对于后面查询字符串的获取
def get(self,request):
    name = request.query_params.get('name')
Response

from rest_framework.response import Response
封装了Django的HTTPResponse,JsonResponse,render,使用该类构造响应对象时,响应的具体数据内容会被转换(render渲染)成符合前端需求的类型
Response(data, status=None, template_name=None, headers=None, content_type=None)


状态码
from rest_framework import status
status.HTTP....

信息告知 - 1xx
HTTP_100_CONTINUE
HTTP_101_SWITCHING_PROTOCOLS

成功 - 2xx
HTTP_200_OK
HTTP_201_CREATED  创建成功
HTTP_202_ACCEPTED
HTTP_203_NON_AUTHORITATIVE_INFORMATION
HTTP_204_NO_CONTENT
HTTP_205_RESET_CONTENT
HTTP_206_PARTIAL_CONTENT
HTTP_207_MULTI_STATUS

重定向 - 3xx
HTTP_300_MULTIPLE_CHOICES
HTTP_301_MOVED_PERMANENTLY
HTTP_302_FOUND
HTTP_303_SEE_OTHER
HTTP_304_NOT_MODIFIED
HTTP_305_USE_PROXY
HTTP_306_RESERVED
HTTP_307_TEMPORARY_REDIRECT

客户端错误 - 4xx
HTTP_400_BAD_REQUEST
HTTP_401_UNAUTHORIZED
HTTP_402_PAYMENT_REQUIRED
HTTP_403_FORBIDDEN
HTTP_404_NOT_FOUND
HTTP_405_METHOD_NOT_ALLOWED
HTTP_406_NOT_ACCEPTABLE
HTTP_407_PROXY_AUTHENTICATION_REQUIRED
HTTP_408_REQUEST_TIMEOUT
HTTP_409_CONFLICT
HTTP_410_GONE
HTTP_411_LENGTH_REQUIRED
HTTP_412_PRECONDITION_FAILED
HTTP_413_REQUEST_ENTITY_TOO_LARGE
HTTP_414_REQUEST_URI_TOO_LONG
HTTP_415_UNSUPPORTED_MEDIA_TYPE
HTTP_416_REQUESTED_RANGE_NOT_SATISFIABLE
HTTP_417_EXPECTATION_FAILED
HTTP_422_UNPROCESSABLE_ENTITY
HTTP_423_LOCKED
HTTP_424_FAILED_DEPENDENCY
HTTP_428_PRECONDITION_REQUIRED
HTTP_429_TOO_MANY_REQUESTS
HTTP_431_REQUEST_HEADER_FIELDS_TOO_LARGE
HTTP_451_UNAVAILABLE_FOR_LEGAL_REASONS

服务器错误 - 5xx
HTTP_500_INTERNAL_SERVER_ERROR
HTTP_501_NOT_IMPLEMENTED
HTTP_502_BAD_GATEWAY
HTTP_503_SERVICE_UNAVAILABLE
HTTP_504_GATEWAY_TIMEOUT
HTTP_505_HTTP_VERSION_NOT_SUPPORTED
HTTP_507_INSUFFICIENT_STORAGE
HTTP_511_NETWORK_AUTHENTICATION_REQUIRED

基本类视图

APIView

from rest_framework.view import APIView
APIView是REST framework提供的所有视图的基类,继承自Django的View父类。

APIView与View的不同点:


APIView中仍以常规的类视图定义方法来实现get() 、post() 或者其他请求方式的方法。

from rest_framework.views import APIView
from rest_framework.response import Response

# url(r'^books/$', views.BookListView.as_view()),
class BookListView(APIView):
    def get(self, request):
        books = BookInfo.objects.all()
        serializer = BookInfoSerializer(books, many=True)
        return Response(serializer.data)
view.py
class BookModelAPIView(APIView):
    def get(self,request):
        data1= request.query_params
        print(data1)
        books = BookInfo.objects.all()
        ser = BookModelSerializer(books,many=True)
        return Response(ser.data,status.HTTP_200_OK)

    def post(self,request):
        data = request.data
        print(data,type(data))

        ser = BookModelSerializer(data=data)
        ser.is_valid()
        ser.save()
        return Response('ok',status.HTTP_201_CREATED)

serializer.py
#模型类序列化器
class BookModelSerializer(serializers.ModelSerializer):
    # image_code = serializers.CharField(max_length=4,min_length=4,allow_null=True)
    class Meta:
        model = BookInfo
        fields = "__all__"
        # exclude = '__all__'
        # read_only_fields = ['bread','bcomment']

        extra_kwargs = {
            'btitle':{
                'min_length':1,
            }
        }
    def create(self, validated_data):
        book=BookInfo.objects.create(btitle = validated_data['btitle'],bpub_date = validated_data['bpub_date'],bread = validated_data['bread'],bcomment = validated_data['bcomment'],is_delete = validated_data['is_delete'])
        return book


urls.py
urlpatterns = [
    #模型类序列化器
    url(r'^drf/$',views.BookModelAPIView.as_view()),
GenericAPIView

from rest_framework.generics import GenericAPIView
继承自APIVIew ,自然也继承自Django的view类
主要增加了操作序列化器和数据库查询的方法,为Mixin扩展类的执行提供方法支持。
通常在使用时,可搭配一个或多个Mixin扩展类。
类属性

class BookModelGenericAPIView(GenericAPIView):
    #指定序列化器
    serializer_class = BookModelSerializer
    queryset = BookInfo.objects.all()

    def get(self,request):
        data1= request.query_params
        print(data1)
        # books = BookInfo.objects.all()  类属性指定了queryset这步省略
        # 获取查询对象
        books =self.get_queryset()
        # ser = BookModelSerializer(books,many=True) 类属性指定了序列化器,省略
        #调用序列化器
        ser = self.get_serializer(books,many=True)


        return Response(ser.data,status.HTTP_200_OK)

类方法
serialiezer方法
get_serializer(self, args, *kwargs)

返回序列化器对象,主要用来提供给Mixin扩展类使用,如果我们在视图中想要获取序列化器对象,也可以直接调用此方法

源码
def get_serializer(self,*args, **kwargs):
serializer_class = self.get_serializer_class()
    kwargs['context'] = self.get_serializer_context()
    return serializer_class(*args, **kwargs)

在继承GeneticAPIView的视图函数中调用此方法 self.get_serializer(获取的参数)。
1 执行了get_serializer_class()方法,返回的是类属性 serializer_class,
def get_serializer_class(self):
     return self.serializer_class

2 执行   self.get_serializer_context()方法,得到三个返回值,request,format,view,
将返回值赋予kwargs键context,构成一个字典

3 返回类属性 serializer_class,并且加上(),代表执行类属性对应的序列化器

get_serializer_class(self)

重写
 if self.request.method=='get':
    serializer=ser1;
 if self.request.method=='post':
    serializer=ser2;

queryset方法
get_object(self)

    def get_object(self):
    首先找到类属性指定的查询集,
        queryset = self.filter_queryset(self.get_queryset())

根据lookup_field='pk' 找到url中传递的pk值,
        lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field

    根据pk值,在查询集找到对应pk值的数据对象,
        filter_kwargs = {self.lookup_field: self.kwargs[lookup_url_kwarg]}
        obj = get_object_or_404(queryset, **filter_kwargs)

    返回匹配的对象。
        self.check_object_permissions(self.request, obj)

        return obj
# url(r'^books/(?P<pk>\d+)/$', views.BookDetailView.as_view()),
class BookDetailView(GenericAPIView):
    queryset = BookInfo.objects.all()
    serializer_class = BookInfoSerializer

    def get(self, request, pk):
        book = self.get_object() #get_object()方法根据pk参数查找queryset中的数据对象
        serializer = self.get_serializer(book)
        return Response(serializer.data)

get_queryset(self)
获取所有查询集数据对象
返回视图使用的查询集,主要用来提供给Mixin扩展类使用,是列表视图与详情视图获取数据的基础,默认返回queryset属性,可以重写

defget_queryset(self):
    user = self.request.user
    return user.accounts.all()

扩展类
from rest_framework.mixins import 拓展类

class CreateModelMixin(object):

    def create(self, request, *args, **kwargs):
        通过调用GennericSerializer的get_serializer方法调用序列化器,传入前端发来的data,
        serializer = self.get_serializer(data=request.data)  

        序列化器对数据进行验证,同时启用遇错页面报错
        serializer.is_valid(raise_exception=True)

        调用此方法,将序列化器传入,执行save方法
        self.perform_create(serializer)
        headers = self.get_success_headers(serializer.data)

        返回一个响应对象,
        return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)

    def perform_create(self, serializer):
        serializer.save()

    def get_success_headers(self, data):
        try:
            return {'Location': str(data[api_settings.URL_FIELD_NAME])}
        except (TypeError, KeyError):
            return {}

扩展类子类
from rest_framework.generics import CreateAPIView,ListAPIView
扩展类本身继承的是object类,其中运用的get_serializer方法来自于genericapiview类
定义视图类的是时候,继承两个类 一个拓展类,一个genericapiview
class MixinView(CreateAPIView,ListAPIView):



class MixinView(CreateAPIView,ListAPIView):
    serializer_class = BookModelSerializer
    queryset = BookInfo.objects.all()

    什么都不用写,继承,直接实现 get post 查询创建方法

视图集ViewSet
from rest_framework.viewsets import ViewSet,GenericViewSet,ModelViewSet


ViewSet


from rest_framework.response import Response

from rest_framework.viewsets import ViewSet  #引用视图集,继承于ViewSetMixin, views.APIView
from book.models import BookInfo
from DRF.serializer import BookModelSerializer

class DRFViewSet(ViewSet):
    def list_books(self,request):
        # 使用视图集不用再写请求方法,直接一句业务逻辑写方法名,在url匹配的时候添加键值对对应关系
        """
        展示所有图书信息
        :param request:
        :return:
        """
        # 没有GenericAPIView,没有query_set属性,所以查询还得写
        books = BookInfo.objects.all()

        #序列化器一旦定义就可以导入引用,不用重复写
        ser = BookModelSerializer(books,many=True)

        #返回ref框架的response
        return Response(ser.data)

    def create_book(self,request):
        """
        创建一个图书对象
        :param request:
        :return:
        """
        data = request.data
        ser = BookModelSerializer(data=data)
        ser.is_valid()
        ser.save()
        return Response(ser.data)

    def create_hero(self,request):
        data = request.data
        ser = BookModelSerializer(data=data)
        ser.is_valid()
        ser.save()
        return Response(ser.data)


urls.py中

from . import views
urlpatterns = [
    url(r'^DRFViewSet/$',views.DRFViewSet.as_view({'get':'list_books','post':'create_book'})),
    # 对于同一个字典,不能有同一个key。所以当同一个请求方式过来要执行不同的方法时,可以再创建一个url
    url(r'^DRFViewSet/hero/$',views.DRFViewSet.as_view({'post':'create_hero'})),
]

GenericViewset

#GenericViewSet
class DRFGenericViewSet(GenericViewSet):  #继承ViewSetMixin, generics.GenericAPIView
    # serializer_class = BookModelSerializer #指定序列化器
    queryset = BookInfo.objects.all() #指定查询集

    # 当不同的业务逻辑需要不同的序列化器,指定序列化器类属性不能满足需求
    # 解决:重写get_serializer_class
    # 1根据不同的action指定不同的序列化器
    def get_serializer_class(self):
        if self.action == 'list':
            return BookModelSerializer
        if self.action == 'create':
            return BookSerializer
    #2 根据不同的请求方式指定序列化器
    # def get_serializer_class(self):
    #     if self.request.method == 'GET':
    #         return BookSerializer
    #     if self.request.method == 'POST':
    #         return BookModelSerializer

    def list(self,request):
        books = self.get_queryset()   #视图集对象调用继承自GenericAPIView的方法,get_queryset()
        ser = self.get_serializer(books,many=True)  #调用,内部执行get_serializer_class方法,在当前类中继承重写,根据action==list判断得到的序列化器为BookModelSerializer,执行
        return Response(ser.data)

    def create(self,request):
        data = request.data

        ser = self.get_serializer(data = data)
        ser.is_valid()
        ser.save()

        return Response(ser.validated_data)
继承五个扩展类和GenericViewSet

class ModelViewSet(
   mixins.CreateModelMixin,
   mixins.RetrieveModelMixin,
   mixins.UpdateModelMixin,
   mixins.DestroyModelMixin,
   mixins.ListModelMixin,
   GenericViewSet):

路由Routers
依赖于视图集,只有使用了视图集,才可以使用自动生成路由
在 urls.py中写

有两种形式:
SimpleRouter
from rest_framework.routers import SimpleRouter

view,py
class DRFModelViewSet(ModelViewSet):
    serializer_class = BookModelSerializer
    queryset = BookInfo.objects.all()


urls.py
route = SimpleRouter()
route.register(r'RouteModelSet',views.DRFModelViewSet,base_name='book')
print(route.urls)
urlpatterns += route.urls

DefaultRouter

自定义方法的自动路由


装饰器自动路由
class DRFModelViewSet(ModelViewSet):
    serializer_class = BookModelSerializer
    queryset = BookInfo.objects.all()
    @action(methods=['GET'],detail=True)
    def last(self,request,pk):
        book = BookInfo.objects.get(id=pk)
        ser = self.get_serializer(book)
        return Response(ser.data)


route1 = SimpleRouter()
route1.register(r'RouteModelSet',views.DRFModelViewSet,base_name='book')
print(route1.urls)
urlpatterns += route1.urls

手动添加路由
views.py
class DRFModelViewSet(ModelViewSet):
    serializer_class = BookModelSerializer
    queryset = BookInfo.objects.all()
    def last(self,request,pk):
        book = BookInfo.objects.get(id=pk)
        ser = self.get_serializer(book)
        return Response(ser.data)

urls.py
  url(r'^RouteModelSet/(?P<pk>\d+)/last/$', views.DRFModelViewSet.as_view({'get': 'last',})),

其他功能

认证Authentication + 权限Permissions


全局配置

也可以在每个视图中添加

from rest_framework.authenticationimportSessionAuthentication, BasicAuthentication
from rest_framework.views import APIView
from rest_framework.permissionsimportIsAuthenticated

class ExampleView(APIView):
    authentication_classes = (SessionAuthentication, BasicAuthentication)
    permission_classes = (IsAuthenticated,)

    ...
    继承APIView的类拥有它的属性,验证,权限,限流。
    类属性接受的是 元组或者列表
自定义权限
class MyPermission(BasePermission):
    def has_object_permission(self, request, view, obj):
"""控制对obj对象的访问权限,此案例决绝所有对对象的访问"""
    returnFalse

classBookInfoViewSet(ModelViewSet):
    queryset = BookInfo.objects.all()
    serializer_class = BookInfoSerializer
    permission_classes = [IsAuthenticated, MyPermission]

限流Throttling


全局配置

在视图中添加
from rest_framework.throttling import UserRateThrottle
from rest_framework.views import APIView

classExampleView(APIView):
    throttle_classes = (UserRateThrottle,)
    ...
可选限流类
from rest_framework.authentication import SessionAuthentication
from rest_framework.permissions import IsAuthenticated
from rest_framework.generics import RetrieveAPIView
from rest_framework.throttling import UserRateThrottle

classBookDetailView(RetrieveAPIView):
    queryset = BookInfo.objects.all()
    serializer_class = BookInfoSerializer
    authentication_classes = [SessionAuthentication]
    permission_classes = [IsAuthenticated]
    throttle_classes = (UserRateThrottle,)

ScopedRateThrottle

class ContactListView(APIView):
    throttle_scope = 'contacts'
    ...

class ContactDetailView(APIView):
    throttle_scope = 'contacts'
    ...

class UploadView(APIView):
    throttle_scope = 'uploads'
    ...

REST_FRAMEWORK = {
    'DEFAULT_THROTTLE_CLASSES': (
        'rest_framework.throttling.ScopedRateThrottle',
    ),
    'DEFAULT_THROTTLE_RATES': {
        'contacts': '1000/day',
        'uploads': '20/day'
    }
}

过滤
注意 >> 排序跟过滤互斥,只能存在一个

注册到INSTALL_APP



在视图中指定

classBookListView(ListAPIView):
    queryset = BookInfo.objects.all()
    serializer_class = BookInfoSerializer
    filter_fields = ['btitle', 'bread']

排序

classBookListView(ListAPIView):
    queryset = BookInfo.objects.all()
    serializer_class = BookInfoSerializer
    filter_backends = [OrderingFilter]   指定用哪个类进行排序
    ordering_fields = ('id', 'bread', 'bpub_date')  指定字段排序

分页Pagination
from rest_framework.pagination import PageNumberPagination
全局配置


视图中使用
局部配置
class Pageset(PageNumberPagination):
    #page_query_param='a'   #将默认page参数,改名为a,page=1 >> a=1第一页
    #page_size = 3 #后端控制前端显示的数据条数

常用的:
   #page_size_query_param = 'page_size' # 给前端字段,让前端自己决定显示多少条数据
    max_page_size = 10  #后端设定最大显示数据数

异常处理 Exceptions
REST framework提供了大多异常处理

REST framework定义的异常

APIException 所有异常的父类
ParseError 解析错误
AuthenticationFailed 认证失败
NotAuthenticated 尚未认证
PermissionDenied 权限决绝
NotFound 未找到
MethodNotAllowed 请求方式不支持
NotAcceptable 要获取的数据格式不支持
Throttled 超过限流次数
ValidationError 校验失败

但对于数据库查询异常没有。可自定义
通过自定义异常处理函数。
1 测试数据库异常报错

from django.db import DatabaseError
在任意视图中 raise DatabaseError,
访问该url,直接返回报错界面,没有友好界面。

2 自定义异常处理文件exception.py

from rest_framework.views import exception_handler as drf_exception_handler
from rest_framework import status
from django.db import DatabaseError

def exception_handler(exc, context):
    response = drf_exception_handler(exc, context)

  if response isNone:
        view = context['view']
  if isinstance(exc, DatabaseError):
            print('[%s]: %s' % (view, exc))
            response = Response({'detail': '服务器内部错误'}, status=status.HTTP_507_INSUFFICIENT_STORAGE)

  return response
先判断异常在不在DRF定义好的异常中
然后选定数据库异常。返回

3 在配置文件settings.py中配置

REST_FRAMEWORK = {
'EXCEPTION_HANDLER': 'DRF.exception.exception_handler'
}

如果未声明,会采用默认的方式

REST_FRAMEWORK = {
'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler'
}

自动生成接口文档

上一篇下一篇

猜你喜欢

热点阅读