rest_framework的使用
首先看看该框架的功能:
1、 解析器
2、 序列化组件
3、 APIView
4、 通用视图(mixin)
5、 分页组件
6、 响应器
7、 路由注册器
8、 认证组件
9、 权限组件
10、 限流
解析器
REST framework 包含许多内置的解析器类,允许接受各种媒体类型(media types)的请求。还支持自定义解析器,这使你可以灵活地设计 API 接受的媒体类型。
在settings文件中配置文件:
REST_FRAMEWORK={
'DEFAULT_PARSER_CLASSES': (
'rest_framework.parsers.JSONParser',
'rest_framework.parsers.FormParser',
),
}
如上,可以使用 DEFAULT_PARSER_CLASSES 设置默认的全局解析器。如上,设置将带有JSON 、表单数据内容的请求,而不是默认的 JSON。详细解释请参照rest_framework文档。
除了默认设置外,还可以对单个视图或视图集设置,详细解释请参照rest_framework文档。
序列化组件
序列化器允许将诸如查询集和模型实例之类的复杂数据转换为原生 Python 数据类型,然后可以将它们轻松地呈现为 JSON ,XML 或其他内容类型。序列化器还提供反序列化,在首次验证传入数据之后,可以将解析的数据转换回复杂类型。
因此,这些是有代码量的,rest_framework对这部分做了优化,引入了Serializers。在实际使用过程中,我们会在应用里,添加serializes.py文件,来引入序列化器。
在serializes.py添加:
from .models import Article, Reporter, testmysql
from rest_framework import serializers
from rest_framework import validators
from rest_framework.validators import UniqueValidator
class testmysqlSerializer(serializers.Serializer):
student_name = serializers.CharField(max_length=16, validators=[validators.UniqueValidator(queryset=testmysql.objects.all(), message='数据已存在')])
course_name = serializers.CharField(max_length=16)
APIView
REST framework 提供了一个 APIView 类,它继承于 Django 的 View 类。
APIView 类与不同的 View 类有所不同:
1、传递给处理方法的 request 对象是 REST framework 的 Request 实例,而不是Django 的 HttpRequest 实例。
2、处理方法可能返回 REST framework 的 Response ,而不是 Django 的 HttpResponse。该视图将管理内容协商,并在响应中设置正确的渲染器。
3、任何 APIException 异常都会被捕获并进行适当的响应。
传入的请求会进行认证,在请求分派给处理方法之前将进行适当的权限检查(允许或限制)。
像往常一样,使用 APIView 类与使用常规 View 类非常相似,传入的请求被分派到适当的处理方法,如 .get() 或 .post() 。此外,可以在类上设置许多属性(AOP)。
在views.py添加:
from django.shortcuts import render
from django.http import JsonResponse
import json
from firstapp.models import testmysql
from .serializers import ArticleSerializer, testmysqlSerializer
from rest_framework.views import APIView
# Create your views here.
class student(APIView):
def post(self, request):
response = {} # 响应
if request.method == "POST":
req = json.loads(request.body)
print(req)
else:
response["msg"] = "请求方法错误"
response["code"] = 400
return JsonResponse(response)
a = testmysqlSerializer(data=req)
if a.is_valid():
testmysql.objects.create(**a.validated_data)
else:
return JsonResponse(a.errors)
response["错误码"] = 200
return JsonResponse(response)
在urls.py添加:
urlpatterns = [
path('student/', student.as_view())
]
如上,是apiView的应用方式,代码不用运行,理解即可。
通用视图(mixin)
基于类的视图的一个主要优点是它们允许你编写可重复使用的行为。 REST framework 通过提供大通用视图,来提供常用模式。我们需要充分利用这一点。
REST framework 提供的通用视图允许您快速构建紧密映射到数据库模型的 API 视图。
如果通用视图不符合需求,可以使用常规的 APIView 类,或者利用 mixin 特性和基类组合出可重用的视图。
mixin可以大大简化代码量,当然,这种方式写出来的接口,灵活度就不高了。
1、mixin相关组件的使用
在urls.py添加:
urlpatterns = [
path('test01/', test01_student.as_view()),
path('test02/<int:pk>/', test02_student.as_view())
]
在views.py中添加:
class test01_student(ListModelMixin, CreateModelMixin, GenericAPIView):
queryset = testmysql.objects.all()
serializer_class = testmysqlSerializer
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
return self.create(request, *args, **kwargs)
class test02_student(UpdateModelMixin, DestroyModelMixin, RetrieveModelMixin, GenericAPIView):
queryset = testmysql.objects.all()
serializer_class = testmysqlSerializer
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)
如上,通过视图写出的接口相当简洁。
2、generics的使用
在views.py中添加:
from rest_framework import generics
class test03_student(generics.ListCreateAPIView):
queryset = testmysql.objects.all()
serializer_class = testmysqlSerializer
class test04_student(generics.RetrieveUpdateDestroyAPIView):
queryset = testmysql.objects.all()
serializer_class = testmysqlSerializer
如上,通过该组件,直接实现了1中的接口功能。
3、ModelViewSet使用
在urls.py中添加:
urlpatterns = [
path('test05/', test05_student.as_view({"get":"list","post":"create"})),
path('test05/<int:pk>/', test05_student.as_view({"get":"retrieve","delete":"destroy","put":"update"})),
]
在views.py中添加:
from rest_framework.viewsets import ModelViewSet
class test05_student(ModelViewSet):
queryset = testmysql.objects.all()
serializer_class = testmysqlSerializer
详细解释请参照rest_framework文档。
分页组件
REST framework 包含对可定制分页样式的支持。这使你可以将较大的结果集分成单独的数据页面。
分页 API 支持:
1、以分页链接的形式作为响应内容的一部分。
2、以分页链接的形式包含在响应的 header 中,如 Content-Range 或 Link .
内置的样式目前是以分页链接的形式作为响应内容的一部分。使用可浏览的 API 时,此样式更易于访问。
分页仅在你使用通用视图或视图集时自动执行。如果你使用的是常规 APIView ,则需要自己调用分页 API 以确保返回分页响应。示例请参阅 mixins.ListModelMixin 和generics.GenericAPIView 类的源代码。
可以通过将分页类设置为 None ,关闭分页。
1、PageNumberPagination
(1) APIView
class test07_student(APIView):
class Pages(PageNumberPagination):
page_size = 10
pagination_class = Pages
def get(self, request):
class Pages(PageNumberPagination):
page_query_param = "page" # 设置url参数page
page_size_query_param = "size" # 设置url参数size
page_size = 10 # 默认显示
book_obj = testmysql.objects.all()
P = Pages()
paged_book_list = P.paginate_queryset(book_obj, request)
T = testmysqlSerializer(paged_book_list, many=True)
data = T.data # 序列化接口
return Response(data)
(2)ModelViewSet
class test06_student(ModelViewSet):
class Pages(PageNumberPagination):
page_size = 10
pagination_class = Pages
queryset = testmysql.objects.all()
serializer_class = testmysqlSerializer
2、LimitOffsetPagination
(1)ModelViewSet
class test08_student(ModelViewSet):
class Pages(LimitOffsetPagination):
default_limit = 10 # 每页显示
offset_query_param = 'offset' # 当前所在的位置
limit_query_param = 'limit' # 往后取几条
pagination_class = Pages
queryset = testmysql.objects.all()
serializer_class = testmysqlSerializer
更多分页组件,请查看rest_framework官方文档。
响应器
你不太可能希望为 REST framework 提供自定义内容协商方案,但如果需要,你可以这样做。要实现自定义内容协商方案,请覆盖 BaseContentNegotiation 。
REST framework 的内容协商类处理选择适当的请求解析器和适当的响应渲染器,因此你应该实现.select_parser(request, parsers) 和 .select_renderer(request, renderers,format_suffix) 方法。
select_parser() 方法应从可用解析器列表中返回一个解析器实例,如果没有任何解析器可以处理传入请求,则返回 None 。
select_renderer() 方法应该返回(渲染器实例,媒体类型)的二元组,或引发NotAcceptable 异常。
解析器parsers在Settings文件中配置,响应器renderer也在该文件配置:
REST_FRAMEWORK={
'DEFAULT_PARSER_CLASSES': (
'rest_framework.parsers.JSONParser',
'rest_framework.parsers.FormParser',
'rest_framework.parsers.MultiPartParser',
),
'DEFAULT_RENDERER_CLASSES': (
'rest_framework.renderers.JSONRenderer',
),
}
与解析器一样,响应器可以根据客户端的请求,来返回格式,如上面的JSON格式,当然,更多内容,请查看相关文档。
路由注册器
因为我们使用的是ViewSet类而不是View类,如ModelViewSet。所以我们实际上不需要自己设计URL conf。可以使用Router类自动处理将资源连接到视图和url中的约定。我们所需要做的就是向路由器注册适当的视图集,然后让它来完成剩下的工作。
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from firstapp.views import add_data, query_data, update_data, delete_data, student, \
test01_student, test02_student, test03_student, test04_student, test05_student, \
test06_student, test07_student, test08_student
# Create a router and register our viewsets with it.
router = DefaultRouter()
router.register(r'test09', test08_student)
# The API URLs are now determined automatically by the router.
urlpatterns = [
path('', include(router.urls)),
path('firstapp/', add_data),
path('firstapp/<int:pk>/', query_data),
path('firstapp/update/<int:pk>/', update_data),
path('firstapp/delete/<int:pk>/', delete_data),
path('student/', student.as_view()),
path('test01/', test01_student.as_view()),
path('test02/<int:pk>/', test02_student.as_view()),
path('test03/', test03_student.as_view()),
path('test04/', test04_student.as_view()),
path('test05/', test05_student.as_view({"get":"list","post":"create"})),
path('test05/<int:pk>/', test05_student.as_view({"get":"retrieve","delete":"destroy","put":"update"})),
path('test06/', test06_student.as_view({"get": "list", "post": "create"})),
path('test06/<int:pk>/', test06_student.as_view({"get": "retrieve", "delete": "destroy", "put": "update"})),
path('test07/', test07_student.as_view()),
path('test07/<int:pk>/', test07_student.as_view()),
path('test08/', test08_student.as_view({"get": "list", "post": "create"})),
path('test08/<int:pk>/', test08_student.as_view({"get": "retrieve", "delete": "destroy", "put": "update"})),
]
如上,通过DefaultRouter()可以自动生成路由,更多路由类,请查看官方文档。
认证组件
身份验证是将传入请求与一组识别凭证(例如请求的用户或其签名的令牌)相关联的机制。然后,权限
和限制策略可以使用这些凭据来确定请求是否应该被允许。
REST framework 提供了许多开箱即用的身份验证方案,同时也允许你实施自定义方案。
身份验证始终在视图的开始处运行,在执行权限和限制检查之前,在允许继续执行任何其他代码之前。
request.user 属性通常会设置为 contrib.auth 包的 User 类的一个实例。
request.auth 属性用于其他身份验证信息,例如,它可以用来表示请求已签名的身份验证令牌。
注意: 不要忘记, 身份验证本身不会(允许或不允许)传入的请求,它只是标识请求的凭据。
默认的认证方案可以在settings.py文件中使用DEFAULT_AUTHENTICATION_CLASSES全局设置。例如:
REST_FRAMEWORK={
'DEFAULT_PARSER_CLASSES': (
'rest_framework.parsers.JSONParser',
'rest_framework.parsers.FormParser',
'rest_framework.parsers.MultiPartParser',
),
'DEFAULT_RENDERER_CLASSES': (
'rest_framework.renderers.JSONRenderer',
),
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.BasicAuthentication',
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.TokenAuthentication',
),
}
如上是3种认证方案:
BasicAuthentication:该认证方案使用 HTTP Basic Authentication,并根据用户的用户名和密码进行签名,通常只适用于测试,如果需要自定义认证,需要继承该类。
TokenAuthentication:此认证方案使用简单的基于令牌的 HTTP 认证方案。令牌身份验证适用于 client-server 架构,例如本机桌面和移动客户端。
SessionAuthentication:此认证方案使用 Django 的默认 session 后端进行认证。Session 身份验证适用于与您的网站在同一会话环境中运行的 AJAX 客户端。
确保在更改设置后运行 manage.py migrate ,这样才生效。rest_framework.authtoken 应用程序提供 Django 数据库迁移。
认证流程应该是前端进行登录,后端生成认证信息,后续的接口,都需要通过认证信息进行认证,这里采用自定义Token:
注册rest_framework.authtoken:
INSTALLED_APPS = [
'rest_framework.authtoken',
]
自定义认证类:
class auth(BaseAuthentication):
def authenticate(self, request):
token = request.query_params.get("token")
usertoken_obj = UserToken.objects.filter(token=token).first()
if usertoken_obj:
return usertoken_obj.user, usertoken_obj.token
else:
raise AuthenticationFailed("Token认证失败")
在认证的视图里添加自定义认证类:
class test10_student(APIView):
authentication_classes = [auth, ]
# permission_classes = [IsAuthenticated]
class Pages(PageNumberPagination):
page_size = 10
pagination_class = Pages
def get(self, request):
class Pages(PageNumberPagination):
page_query_param = "page" # 设置url参数page
page_size_query_param = "size" # 设置url参数size
page_size = 10 # 默认显示
book_obj = testmysql.objects.all()
P = Pages()
# 分页
paged_book_list = P.paginate_queryset(book_obj, request)
T = testmysqlSerializer(paged_book_list, many=True)
data = T.data # 序列化接口
return Response(data)
或者直接设置全局认证,需要在REST_FRAMEWORK注册自定义认证类。
执行迁移:
python manage.py makemigrations
python manage.py migrate
权限组件
与 authentication 和 throttling 一起,permission 决定是应该接受还是拒绝访问请求。
权限检查总是在视图的最开始处运行,在任何其他代码被允许进行之前。权限检查通常会使用request.user 和 request.auth 属性中的认证信息来确定是否允许传入请求。
权限用于授予或拒绝不同类别的用户访问 API 的不同部分。
最简单的权限是允许通过身份验证的用户访问,并拒绝未经身份验证的用户访问。这对应于 REST framework 中的 IsAuthenticated 类。
稍微宽松的权限会允许通过身份验证的用户完全访问,而未通过身份验证的用户只能进行只读访问。这对应于 REST framework 中的 IsAuthenticatedOrReadOnly 类。
自定义的权限可以使用BasePermission,用法跟认证组件类似,可查阅官方文档。
限流
限流与权限类似,因为它确定是否应该授权请求。 限流阀指示临时状态,并用于控制客户端可以对API进行的请求速率。
与权限一样,可能会使用多种限流方式。你的 API 可能对未经身份验证的请求进行限流,对经过身份验证的请求限流较少。
如果你需要对 API 的不同部分使用不同的限流策略,由于某些服务特别占用资源,你可能想要使用同时有多种限流策略的另一种方案。
如果你想要同时实现爆发限流率和持续限流率,也可以使用多个限流阀。例如,你可能希望将用户限制为每分钟最多 60 个请求,并且每天最多 1000 个请求。
限流阀不一定只限制请求频率。例如,存储服务可能还需要对带宽进行限制,而付费数据服务可能希望对正在访问的某些记录进行限制。
使用方式可查阅官方文档,下面是一个例子:
REST_FRAMEWORK = {
'DEFAULT_THROTTLE_CLASSES': [
'rest_framework.throttling.AnonRateThrottle',
'rest_framework.throttling.UserRateThrottle'
],
'DEFAULT_THROTTLE_RATES': {
'anon': '100/day',
'user': '1000/day'
}
}