APIView
1.restframework的APIView源码剖析
类的继承: 继承了原生View类并继承了as_view方法
2.APIView的使用
pip install djangorestframework #下载djangorestframework
from rest_framework.views import APIView
class LoginView(APIView):
def get(self, request):
pass
解析器组件
1.使用示例
class LoginView(APIView):
def get(self, request):
pass
def post(self, request):
request.data # 新的request对象 @property
return
2.部分重要关键源码
class APIView(View):
3.实现流程
-
views.LoginView.as_view()
-
LoginView里面没有as_view方法,到父类APIView去找
-
执行View里面的as_view()方法,返回view函数 def view(request, *args, kwargs): self = cls(initkwargs) if hasattr(self, 'get') and not hasattr(self, 'head'): self.head = self.get self.request = request self.args = args self.kwargs = kwargs return self.dispatch(request, *args, **kwargs)
-
url和视图函数之间的绑定关系建立完毕 { "login": view},等待用户请求
-
接收到用户请求:login,到建立好的绑定关系里面执行对应的视图函数:view(request)
-
视图函数的执行结果是什么就返回给用户什么:self.dispatch(), self.dispatch()的执行结果是什么,就返回给用户什么
-
此时的self代表的是LoginView的实例化对象
-
开始找dispatch方法,self里面没有,LoginView里面也没有,在APIView里面有
-
开始执行APIView里面的dispatch
-
最后找到http方法(GET,POST,PUT,DELETE),根据请求类型查找(request.method.lower())
-
开始执行找到的方法(GET),self.get(), self此时代表LoginView的实例化对象 11.1 假设接收到的是POST请求, 执行request.data 11.2 根据分析,所有的解析工作都在request.data里面实现,且data是一个方法(被装饰后的) 11.2 开始执行request.data @property def data(self): if not hasattr(self, 'full_data'): self.load_data_and_files() return self.full_data 11.3 执行self.load_data_and_files 11.4 执行self.data, self.files = self.parse() 11.5 parser = self.negotiator.select_parser(self, self.parsers) 11.5.1 开始找self.parsers 11.5.2 self.get_parses() [ parse() for parse in self.parser_classes ] 11.5.3 parser_classes = api_settings.DEFAULT_PARSER_CLASSES 11.5.4 from rest_framework import api_settings 11.5.5 api_settings = APISettings(None, DEFAULTS, IMPORT_STRINGS) 11.5.6 class APISettings():pass
11.5.7 找不到DEFAULT_PARSER_CLASSES,getattr 'DEFAULT_PARSER_CLASSES': ( 'rest_framework.parsers.JSONParser', 'rest_framework.parsers.FormParser', 'rest_framework.parsers.MultiPartParser' ),
11.5.8 首先找程序的settings
11.5.9 然后找rest_framework的settings
11.6 self.data就是我们想要的数据 11.7 DRF将self.data = data 11.8 request.data
-
在LoginView里面找到了对应的方法,执行该方法,最后返回给用户
-
DRF的所有功能都是在as_view()和dispatch里面重写的
-
而解析器组件在dispatch方法里面重写了,具体是在重新封装的Request对象里面
-
序列化组件
1.通过序列化组件进行get接口设计
GET 127.0.0.1:8000/books/ # 获取所有数据,返回值: [{}, {}]
GET 127.0.0.1:8000/books/{id} # 获取一条数据,返回值:{}
POST 127.0.0.1:8000/books/ # 新增一条数据,返回值:{}
PUT 127.0.0.1:8000/books/{id} # 修改数据,返回值:{}
DELETE 127.0.0.1:8000/books/{id} # 删除数据,返回空
导入模块:from rest_framework import serializers
建立一个序列化类:
class BookSerializer(serializers.Serializer):
publish_name = serializers.CharField(read_only=True, source="publish.name")
authors_list = serializers.SerializerMethodField()
def get_authors_list(self, book_obj):
pass
开始序列化:
class BookView(APIView):
def get(self, request):
origin_data = Book.objects.all() #获取queryset
serialized_data = BookSerializer(origin_data, many=True) #开始序列化
#book_obj = Book.objects.all()
#serialized_data = BookSerializer(book_obj, many=False) get单条数据接口设计
return Response(serialized_data.data) #获取序列化后的数据,返回给客户端
2.post接口设计
def post(self, request):
verified_data = BookSerializer(data=request.data)
if verified_data.is_valid():
book = verified_data.save()
authors=Author.objects.filter(nid__in=request.data
['authors'])
book.authors.add(*authors)
return Response(verified_data.data)
else:
return Response(verified_data.errors)
3.put接口设计
def put(self, request, nid):
book_obj = Book.objects.get(pk=nid)
verified_data = BookSerializer(data=request.data, instance=book_obj)
if verified_data.is_valid():
verified_data.save()
return Response(verified_data.data)
else:
return Response(verified_data.errors)
视图组件
1. 使用视图组件的mixin进行接口逻辑优化
a.导入mixin
from rest_framework.mixinx import (
ListModelMix,
CreateModelMixin,
DestroyModelMixin,
UpdateModelMixin,
RetrieveModelMixin
)
from rest_framework.generics import GenericAPIView
b.定义序列化类
class BookSerializer(serializers.ModelSerializer):
class Meata:
model = Book
fields = ('field_name', )
extra_kwargs = {"publish": {"write_only": True}, }
publish_name = serializers.CharField(read_only=True, source="publish.name")
authors = serializers.SerializerMethodField()
def get_authors(self, book_obj):
pass
c.导入序列化类
from .app_serializers import BookSerializer
d.定义视图类
class BookView(ListModelMix, CreateModelMixin, GenericAPIView):
#queryset和serializer_class是固定的写法
queryset = Book.objects.all()
serializer_class = BookSerializer
def get():
return self.list()
def post():
return self.create()
class BookFilterView(RetrieveModelMixin, DestroyModelMixin, UpdateModelMixin, GenericAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
def get():
return self.retrieve()
def delete():
return self.destroy()
def put():
return self.update()
#注意:单条数据操作的url是这样的:re_path(r'books/(?P<pk>d+)/$, views.BookFilterView.as_view())
2.使用视图组件的view进行接口逻辑优化
a.导入模块
from rest_framework import generics
b.写视图类
class BookView(generics.ListCreateAPIView)
queryset = Book.objects.all()
serializer_class = BookSerializer
class BookFilterView(generics.RetrieveUpdateDestroyAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
3.使用视图组件的viewset进行接口逻辑优化
a.导入模块
from rest_framework.viewsets import ModelViewSet
b.设计url
re_path(r'books/$', views.BookView.as_view({
'get': 'list',
'post': 'create'
})),
re_path(r'books/(?P<pk>d+)/$', views.BookView.as_view({
'get': 'retrieve',
'delete': 'destroy',
'put': 'update'
}))
c.设计视图类
class BookView(ModelViewSet):
queryset = Book.objects.all()
serializer_class = BookSerializer
认证组件
1.使用方法
a.定义认证类
class UserAuth():
def authenticate_header(self, request):
pass
def authenticate(self, request):
pass
b.在需要认证的数据接口里面指定认证类
class BookView(ModelViewSet):
authentication_classes = [UserAuth]
queryset = Book.objects.all()
serializer_class = BookSerializer
2.全局认证
在settings文件里面指定:
REST_FRAMEWORK = {
"DEFAULT_PARSER_CLASSES": (JsonParser, FormParser),
"DEFAULT_AUTHENTICATION_CLASSES": ("serializer.utils.app_authes.UserAuth",)
}
3.源码剖析
- self.dispatch() # self BookView的实例化对象
- self.initial() # self BookView的实例化对象
- self.perform_authentication() # self BookView的实例化对象
- request.user # self Request的实例化对象
- self._authenticate() # self Request的实例化对象
self.user = xxx
权限组件
1.权限组件的使用
a.定义一个权限类
class UserPerm():
def has_permission(self, request, view):
if 有权限:
return True
else:
return False
b.指定权限类
class BookView(APIView):
permission_classes = [UserPerm]
频率组件
1.频率组件的使用
a.定义一个频率类
class RateThrottle():
def allow_request(request, self):
if 没有超过限制:
return True
else:
return False
def wait(self):
return 10
b.指定频率类
class BookView(APIView):
throttle_classes = [RateThrottle]
2.使用DRF的简单频率控制来控制用户访问频率(局部)
-导入模块
from rest_framework.throttling import SimpleRateThrottle
- 定义并继承SimpleRateThrottle
class RateThrottle(SimpleRateThrottle):
# 指定访问频率
rate = '5/m'
# 指定通过什么方式来区分用户
def get_cache_key(self, request, view):
return self.get_ident(request)
- 指定频率类
class BookView(APIView):
throttle_classes = [RateThrottle]
3.使用DRF的简单频率控制来控制用户访问频率(全局)
-导入模块
from rest_framework.throttling import SimpleRateThrottle
- 定义并继承SimpleRateThrottle
class RateThrottle(SimpleRateThrottle):
# 指定访问频率
scope = 'visit_rate'
# 指定通过什么方式来区分用户
def get_cache_key(self, request, view):
return self.get_ident(request)
- 在settings里面指定频率类和访问频率
REST_FRAMEWORK = {
"DEFAULT_THROTTLE_CLASSES": ('serializer.utils.app_throttles.RateThrottle',),
"DEFAULT_THROTTLE_RATES": {
"visit_rate": "5/m"
}
}
url注册器组件
1.url注册器组件的使用
a.导入模块
from django.urls import re_path, include
from .serializer import views
from rest_framework import routers
b.生成一个注册器示例对象
router = routers.DefaultRouter()
c.将需要自动生成url的接口注册
router.register(r"books", views.BookView)
d.开始自动生成url
urlpatterns = [
re_path('^', include(router.urls)),
]
分页器组件
1.使用方法
- 导入模块
from rest_framework.pagination import PageNumberPagination
- 获取数据
books = Book.objects.all()
- 创建一个分页器对象
paginater = PageNumberPagination()
- 开始分页
paged_books = paginater.paginate_queryset(books, request)
- 开始序列化
serialized_books = BookSerializer(paged_books, many=True)
- 返回数据
return Response(serialized_books.data)
2.局部实现
- 导入模块
from rest_framework.pagination import PageNumberPagination
- 自定义一个分页类并集成PageNumberPagination
class MyPagination(PageNumberPagination):
page_size = 2
page_query_param = 'p'
page_size_query_param = 'size'
max_page_size = 5
- 实例化一个分页类对象
paginater = MyPagination()
- 开始分页
paged_books = paginater.paginate_queryset(books, request)
- 开始序列化
serialized_books = BookSerializer(paged_books, many=True)
- 返回数据
return Response(serialized_books.data)
响应器组件
a.导入模块
from rest_framework.renderers import JsonRender
b.指定返回类
class BookView(APIView):
render_classes = [JsonRender]