RestFramework之url注册器、响应器、分页组件

一,url注册器

之前我们再写数据类的增删该查视图时,如果使用视图类组件的话,需要写这样两条url:

url(r"^author/$", views.AuthorView.as_view({"get": "list", "post": "create"})), 
url(r"^author/(?P<pk>\d+)/$", views.AuthorView.as_view({"put": "update", "delete": "destroy", "get": "retrieve"})),

每次都这么写,太麻烦了,所以restframework给我们提供了一种便捷的方式,就是url注册器;

在urls.py中这么写:


from django.conf.urls import url, include
from django.contrib import admin
from app01 import views
from rest_framework import routers
router = routers.DefaultRouter()
router.register("author", views.AuthorView)

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    # url(r"^author/$", views.AuthorView.as_view({"get": "list", "post": "create"})),
    # url(r"^author/(?P<pk>\d+)/$", views.AuthorView.as_view({"put": "update", "delete": "destroy", "get": "retrieve"})),
    url(r"^", include(router.urls)),
]

也以看到,它帮我们写了这么多url

根据这个规则,我们不仅可以写我们原来的拿两条url,还可以有两条url:

如:

http://127.0.0.1:8000/author.json/?token=552d69c2-4503-4d16-bacb-cc8da5f1b52c

直接就是返回的数据了:

http://127.0.0.1:8000/author/1.json?token=552d69c2-4503-4d16-bacb-cc8da5f1b52c

二,响应器

当我们用浏览器访问restframework搭建的服务器是,返回的是一个页面

而不是数据,这是restframework帮我们做了这件事,只要是浏览器发的请求就会返回一个页面,使用postman等工具发送请求时,就返回数据;

我们可以看到在apisettings中,有这个默认配置:

'DEFAULT_RENDERER_CLASSES': (
        'rest_framework.renderers.JSONRenderer',
        'rest_framework.renderers.BrowsableAPIRenderer',
    ),

而帮我返回页面的响应器就是第二个,BrowsableAPIRenderer,只要我们在全局中配置这个属性,然后把这个类注释掉,就可以让浏览器也返回的是数据了;

settings中的配置:

REST_FRAMEWORK = {
    'DEFAULT_RENDERER_CLASSES': (
        'rest_framework.renderers.JSONRenderer',
        # 'rest_framework.renderers.BrowsableAPIRenderer',
    ),
}

这样浏览器发请求就不会返回页面了;

三,分页组件

1,视图类需要自己写逻辑

即需要自己写get(), post()方法等逻辑的,就是需要自己获取某个表的queryset时:

以book表的查看(get())为例:


from rest_framework.pagination import PageNumberPagination
class BookView(APIView):
    # parser_classes = [FormParser, ]

    def get(self, request):

        class MyPageNumberPagination(PageNumberPagination):
            page_size = 2
            page_query_param = "page_num"  # 即url上的那个参数,默认时page

            page_size_query_param = "size"  # 临时要取数据的时候,可以在url上加的参数
            max_page_size = 3  # 限制上面那个size最多可以取的数据数量

        book_list = models.Book.objects.all()
        pnp = MyPageNumberPagination()
        paged_book_list = pnp.paginate_queryset(book_list, request)
        bs = BookSerializer(paged_book_list, many=True)
        # print(bs.data)
        return Response(bs.data)

url上:

使用size: 获取4条,但是 max_page_size = 3最大限制取三条:

也可混合使用:

2 ,视图类继承 ModelViewSet

当我们的使用modelviewset时,也就是我们不用自己写get(),post()方法等逻辑了,那我们要怎么使用分页?

这个时候需要看看源码了!看看源码中是怎么写list()方法的:

list()方法:

class ListModelMixin(object):
    """
    List a queryset.
    """
    def list(self, request, *args, **kwargs):
        queryset = self.filter_queryset(self.get_queryset())

        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)

        serializer = self.get_serializer(queryset, many=True)
        return Response(serializer.data)

找  self.paginate_queryset(queryset):

    def paginate_queryset(self, queryset):
        """
        Return a single page of results, or `None` if pagination is disabled.
        """
        if self.paginator is None:
            return None
        return self.paginator.paginate_queryset(queryset, self.request, view=self)

可以看到这个方法中,是用 self.paginator再调用我们真正做分页的那个 paginate_queryset()方法(这个类中的PageNumberPagination)!

明显这个self.paginator是个静态方法:

@property
    def paginator(self):
        """
        The paginator instance associated with the view, or `None`.
        """
        if not hasattr(self, '_paginator'):
            if self.pagination_class is None:
                self._paginator = None
            else:
                self._paginator = self.pagination_class()  # 这里注意分开看是self._paginator = self.pagination_class先找这个类,再去加()实例化
        return self._paginator

也就是他使用的那个分页类是  self.pagination_class,还是原来那套,先在自己的视图类中找 self.pagination_class 中找,然后再去全局settings中找,再去默认的;

默认的是:

pagination_class = api_settings.DEFAULT_PAGINATION_CLASS
'DEFAULT_PAGINATION_CLASS': None,  可以看到默认的是None

所以使用分页器,我们只需要在自己的视图类中写上 pagination_class ,把我们自己的分页类加进去,就可以了:

视图类:

class MyPageNumberPagination(PageNumberPagination):
    page_size = 2
    page_query_param = "page_num"  # 即url上的那个参数,默认时page

    page_size_query_param = "size"  # 临时要取数据的时候,可以在url上加的参数size
    max_page_size = 3  # 限制上面那个size最多可以取的数据数量


class AuthorView(ModelViewSet):
    queryset = models.Author.objects.all()
    serializer_class = AuthorSerializer
    pagination_class = MyPageNumberPagination

 

posted @ 2018-09-21 18:05  Mr.GLH  阅读(481)  评论(0)    收藏  举报
Top↑