参考博客:https://www.cnblogs.com/yuanchenqi/articles/8719520.html
一、数据解析器
1.Django默认的数据解析
在我们使用django框架时,浏览器如果发送以下类型的POST数据:
Content-Type=application/x-www-form-urlencoded
Content-Type=application/form-data
则django会自动帮我们将请求体中的数据转换为字典,保存在request.POST中。
但是,如果浏览器发送的是json数据:
Content-Type=application/json
则django无法为我们转换,我们只能从request.body中获取原始数据,自己进行转换。
2.restframework提供的解析器
如果我们使用restframework,他给我们提供了几个常用的数据解析器,列表如下:
from rest_framework import parsers # 处理json数据,media_type = 'application/json' parsers.JSONParser # 处理x-www-form-urlencoded数据,media_type = 'application/x-www-form-urlencoded' parsers.FormParser # 处理multipart/form-data数据,media_type = 'multipart/form-data' parsers.MultiPartParser # 处理所有数据,media_type = '*/*' parsers.FileUploadParser
如果我们在视图类中不指定需要使用的解析器,则默认会使用三种:
在APIView类中可以看到:
class APIView(View): # The following policies may be set at either globally, or per-view. renderer_classes = api_settings.DEFAULT_RENDERER_CLASSES parser_classes = api_settings.DEFAULT_PARSER_CLASSES authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES ... ...
在DEFAULTS中找到 DEFAULT_PARSER_CLASSES :
'DEFAULT_PARSER_CLASSES': [ 'rest_framework.parsers.JSONParser', 'rest_framework.parsers.FormParser', 'rest_framework.parsers.MultiPartParser' ],
默认使用了JSONParser、FormParser和MultiPartParser三种解析器。
3.在视图类中指定可以使用的解析器
class LoginView(APIView): authentication_classes = [] parser_classes = [parsers.JSONParser,parsers.FormParser] ... ...
我们可以在视图类中使用parser_classes列表来指定该视图类可以使用的解析器。
当然,我们也可以仿造JSONParser等解析器实现自己的解析器。
二、URL控制
1.自动生成URL路由条目
在 [Python自学] restframework (2) (视图类的封装) 中的level-3中,一个视图类提供5种操作,但是要对应两条urls路由条目。
其实restframework也给我们提供了一个封装,来自动生成相应的urls:
from django.contrib import admin from django.urls import path, re_path, include from demo import views from rest_framework import routers router = routers.DefaultRouter() router.register(r'authors', views.AuthorViewSet) urlpatterns = [ path('admin/', admin.site.urls), re_path('^publishes/$', views.PublishView.as_view(), name="publish"), re_path('^publishes/(?P<pk>d+)/$', views.PublishDetailView.as_view(), name="publishdetail"), re_path('^books/$', views.BookView.as_view(), name="book"), re_path('^books/(?P<pk>d+)/$', views.BookDetailView.as_view(), name="bookdetail"), # re_path('^authors/$', views.AuthorViewSet.as_view({"get": "list", "post": "create"}), name="author"), # re_path('^authors/(?P<pk>d+)/$', views.AuthorViewSet.as_view( # {"get": "retrieve", "put": "update", "patch": "partial_update", "delete": "destroy"}), name="authordetail"), re_path('^login/$', views.LoginView.as_view(), name="login"), re_path('', include(router.urls)) ]
这样,就不用自己写两条authors的路由条目了。
2.测试结果
1)浏览器访问authors全部数据,http://127.0.0.1:8000/authors/?token=81ba24601ce5be47ff2d96142a8ccb76:
2)浏览器访问authors全部数据,http://127.0.0.1:8000/authors.json?token=81ba24601ce5be47ff2d96142a8ccb76:
3)浏览器访问authors全部数据,http://127.0.0.1:8000/authors/?format=json&token=81ba24601ce5be47ff2d96142a8ccb76:
4)浏览器访问authors中id为1的数据,http://127.0.0.1:8000/authors/1/?token=81ba24601ce5be47ff2d96142a8ccb76:
3.总结
使用restframework提供的url控制功能,可以自动为我们生成4条路由条目:
^authors/$ [name='author-list'] ^authors.(?P<format>[a-z0-9]+)/?$ [name='author-list'] ^authors/(?P<pk>[^/.]+)/$ [name='author-detail'] ^authors/(?P<pk>[^/.]+).(?P<format>[a-z0-9]+)/?$ [name='author-detail']
其中,当使用浏览器访问时,authors.json和authors的区别在于是否提供渲染页面。前者只返回纯数据,后者会返回restframework提供的页面。
三、分页
1.直接在视图类中添加分页
在 [Python自学] restframework (1) 中,我们手工从数据库中获取books数据,并序列化返回给浏览器。GET获取全量数据的代码如下:
class BookModelSerializers(serializers.ModelSerializer): class Meta: model = Book fields = "__all__" class BookView(APIView): def get(self, request): book_list = Book.objects.all() bs = BookModelSerializers(book_list, many=True) return Response(bs.data) def post(self, request): pass
如果我们想为其添加分页,每次只返回固定的条数:
class BookView(APIView): def get(self, request): book_list = Book.objects.all() # 添加分页 from rest_framework.pagination import PageNumberPagination pnp = PageNumberPagination() # 获取每一页 book_page = pnp.paginate_queryset(book_list, request, self) # 将book_page传入进行序列化 bs = BookModelSerializers(book_page, many=True, context={'request': request}) return Response(bs.data)
每页显示的页数,我们可以在settings中的REST_FRAMEWORK中配置:
REST_FRAMEWORK = { # "DEFAULT_AUTHENTICATION_CLASSES": ["demo.utils.TokenAuth"], # "DEFAULT_PERMISSION_CLASSES":["demo.utils.SVIPPermission"] "PAGE_SIZE": 2, }
测试结果:
访问 http://127.0.0.1:8000/books/默认显示第一页的两条数据:
访问 http://127.0.0.1:8000/books/?page=3显示指定页的数据:
2.自定义分页子类
在前面我们的PAGE_SIZE是在settings中配置的,我们也可以自定义一个类,继承自 PageNumberPagination类:
from rest_framework.pagination import PageNumberPagination class MyPageNumberPagination(PageNumberPagination): page_size = 1 # 在url中指定页数的参数名http://127.0.0.1:8000/books/?page=1 page_query_param = 'page' # 在url中指定每页显示条数http://127.0.0.1:8000/books/?page=1&size=2 page_size_query_param = 'size' class BookView(APIView): # authentication_classes = [TokenAuth] def get(self, request): book_list = Book.objects.all() # 这里使用我们自定义的类 pnp = MyPageNumberPagination() # 获取每一页 book_page = pnp.paginate_queryset(book_list, request, self) # 将book_page传入进行序列化 bs = BookModelSerializers(book_page, many=True, context={'request': request}) return Response(bs.data)
这样,我们在自己定义的子类中就可以指定page_size等参数,无需到settings中去配置了。而且这样可以让每个视图类由不同的分页特性。例如可以让books和authors每页显示条数不同。
3.另外一种分页类(limit和offset)
除了 PageNumberPagination类,restframe还提供了另一个类 LimitOffsetPagination:
from rest_framework.pagination import LimitOffsetPagination class MyLimitOffsetPagination(LimitOffsetPagination): # 相当于PageNumberPagination类的page_size default_limit = 1 # url中的limit参数,控制每页显示条数 limit_query_param = 'limit' # url中的offset参数,控制偏移多少 offset_query_param = 'offset' class BookView(APIView): # authentication_classes = [TokenAuth] def get(self, request): book_list = Book.objects.all() # 这里使用我们自定义的类 pnp = MyLimitOffsetPagination() # 获取每一页 book_page = pnp.paginate_queryset(book_list, request, self) # 将book_page传入进行序列化 bs = BookModelSerializers(book_page, many=True, context={'request': request}) return Response(bs.data)
使用 MyLimitOffsetPagination 类的话,访问的url会不同,例如:
limit=2表示每页显示两条数据(默认设置的是1条)。
offset=1表示向后偏一条数据(注意,是一条数据,不加offset=1时,显示的是id为8和9的数据,加了offset=1显示的时id为9和10的数据)。
4.封装后的视图类如何使用分页类
在[Python自学] restframework (2) (视图类的封装)中,我们对视图类的封装有三个级别,以最后level-3作为例子,如何使用分页器:
from rest_framework.pagination import PageNumberPagination class MyPageNumberPagination(PageNumberPagination): page_size = 1 page_query_param = 'page' page_size_query_param = 'size' # Author序列化类 class AuthorModelSerializers(serializers.ModelSerializer): class Meta: model = Author fields = "__all__" class AuthorViewSet(viewsets.ModelViewSet): queryset = Author.objects.all() serializer_class = AuthorModelSerializers pagination_class = MyPageNumberPagination
这样设置以后,restframe就会自动的去使用 MyPageNumberPagination 类进行分页操作了。具体流程可以跟踪源代码。原理类似认证、权限、频率组件。
f≥Ö‿Ö≤