DRF
-
概述
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'
}
自动生成接口文档