swagger 如何在django rfw中使用drf-spectacular为自定义分页生成模式?

k3bvogb1  于 2023-05-28  发布在  Go
关注(0)|答案(3)|浏览(237)

我正在努力在django rest框架中为我的自定义分页正确地生成模式。我使用drf-spectacular来生成模式。我的自定义分页包括一个 total-pages 字段,它没有随djangos PageNumberPagination一起提供。响应被正确地序列化并返回,并且包括 total-pages,但是我的swagger文档中的模式不包括该字段。下面是我的代码:

  • 分页.py*
from rest_framework import pagination
from rest_framework.response import Response

class CustomPagination(pagination.PageNumberPagination):
    page_size = 10
    page_size_query_param = 'page_size'
    max_page_size = 100
    page_query_param = 'p'
    
    def get_paginated_response(self, data):
        return Response({
            'page_size': self.page_size,
            'total_objects': self.page.paginator.count,
            'total_pages': self.page.paginator.num_pages,
            'current_page_number': self.page.number,
            'next': self.get_next_link(),
            'previous': self.get_previous_link(),
            'results': data,
        })

以下是我的观点:

  • views.py*
@extend_schema_view(
    get=extend_schema(
        parameters=[OpenApiParameter("q", OpenApiTypes.STR, OpenApiParameter.QUERY),],
        request=TestStandardSearchSerializer,
        responses=TestStandardSerializer
        )
    )
class TestStandardSearchView(ListAPIView):
    serializer_class = TestStandardSearchSerializer
    queryset = TestStandard.objects.all()
    pagination_class = CustomPagination
   
    def get(self, request, *args, **kwargs):
        query = self.request.query_params.get('q')
        queryset = SearchQuerySet().all().filter(content=query).order_by('acronym')
        page = self.paginate_queryset(queryset)
        serializer = self.get_serializer(page, many=True)
        return self.get_paginated_response(serializer.data)
    
    def get_serializer_class(self):
        if self.request.method == 'GET':
           return TestStandardSearchSerializer

我的swagger文档中的响应模式如下:

PaginatedTestStandardList
{
count   integer                            example: 123
next    string($uri)     nullable: true    example: http://api.example.org/accounts/?p=4
previous    string($uri) nullable: true    example: http://api.example.org/accounts/?p=2
results [TestStandard{...}]
}

标准的django分页在schema中是正确的,但不是我的自定义分页响应。我期望/想要的是将我的自定义分页响应正确地与 total-pages 字段集成在与'count','next'和'previous'相同的级别上。
我所尝试的...我有一个使用PaginatorInspector提供自定义模式的 drf_yasg 工作解决方案。但这在 drf-spectacular 中不可用。我还在 @extend_schema_view 中使用了 inline_serializer 和自定义响应,例如:

responses={
            200: inline_serializer(
           name='PaginatedTestStandardSearchResponse',
           fields={
               'total-pages': serializers.IntegerField(),
               'results': TestStandardSearchSerializer()
           },

这导致了一个模式,其中 total-pages 嵌套在results中。我正在使用:

drf-spectacular     0.21.2
Django              3.2.12
django-rest-swagger 2.2.0
djangorestframework 3.12.4

任何帮助都很感激。我最近刚开始使用django rfw和openapi模式生成。很抱歉,我错过了一些明显的东西。

rur96b6h

rur96b6h1#

您需要覆盖CustomPagination中的方法get_paginated_response_schema。有关如何组合它的参考,您可以在pagination.pyrest_framework包内的文件www.example.com上看到它。
如果你想知道它是如何工作的,你可以在www.example.com文件中的drf-spectacular包中找到它openapi.py,method _get_response_for_code。我希望这能解决你的问题。

plupiseo

plupiseo2#

最后,我使用了get_paginated_response()。这终于解决了我的问题。现在swagger文档中显示了正确的分页参数。
这是我的自定义分页器:

from rest_framework import pagination
   from rest_framework.response import Response

   class CustomPagination(pagination.PageNumberPagination):
       page_size = 10
       page_size_query_param = 'page_size'
       max_page_size = 100
       page_query_param = 'p'
    
       def get_paginated_response(self, data):
           print(data)
           print()
           return Response({
               'count': self.page.paginator.count,
               'next': self.get_next_link(),
               'previous': self.get_previous_link(),
               'page_size': self.page_size,
               'total_objects': self.page.paginator.count,
               'total_pages': self.page.paginator.num_pages,
               'current_page_number': self.page.number,
               'results': data,
           })
    
      def get_paginated_response_schema(self, schema):            
          return {
              'type': 'object',
              'properties': {
                  'count': {
                      'type': 'integer',
                      'example': 123,
                  },
                  'next': {
                      'type': 'string',
                      'nullable': True,
                      'format': 'uri',
                      'example': 'http://api.example.org/accounts/? 
                          {page_query_param}=4'.format(
                          page_query_param=self.page_query_param)
                  },
                  'previous': {
                      'type': 'string',
                      'nullable': True,
                      'format': 'uri',
                      'example': 'http://api.example.org/accounts/? 
                          {page_query_param}=2'.format(
                          page_query_param=self.page_query_param)
                  },                
                  'page_size' : {
                      'type': 'integer',
                      'example': 123,
                  },
                  'total_pages': {
                      'type': 'integer',
                      'example': 123,
                  },
                  'current_page_number': {
                      'type': 'integer',
                      'example': 123,
                  },
                  'results': schema,
              },
          }
aoyhnmkz

aoyhnmkz3#

当我遇到同样的总页数问题时,我遵循了@Agung Wiyono的建议,下面的代码对我很有效。它与@Anti提供的代码几乎相同,但使用了super。这样,我们只修改了基本方法,而没有完全重写它们。

class PageNumberPaginationWithCount(pagination.PageNumberPagination):
    def get_paginated_response(self, *args, **kwargs):
        response = super(PageNumberPaginationWithCount, self).get_paginated_response(*args, **kwargs)
        response.data['total_pages'] = self.page.paginator.num_pages
        return response

    def get_paginated_response_schema(self, *args, **kwargs):
        schema = super(PageNumberPaginationWithCount, self).get_paginated_response_schema(*args, **kwargs)
        schema['properties']['total_pages'] = {
            'type': 'integer',
            'example': 123,
        }
        return schema

相关问题