python - django-rest-framework,在列表响应中添加“包含”,带有分页
问题描述
使用我目前在 django-rest-framework 中开发的 API,我正在尝试实现类似于 json-api 标准中的功能的东西。给定书籍模型:
class Book(models.Model):
title = models.CharField(max_length=255)
author = models.ForeignKey(Author, on_delete=models.CASCADE)
publisher = models.ForeignKey(Publisher, on_delete=models.CASCADE)
我想在 url 中包含一个参数,include
让用户定义是否要在响应中包含author
和模型。publisher
额外的问题是我正在使用限制/偏移分页。因此,以下网址:
https://my-api-domain/api/books?limit=5&offset=0&include=authors
应该返回如下内容:
{
"count": 152,
"next": "https://my-api-domain/api/books/limit=5&offset=5&include=authors"
"previous": null,
"results": [
{"id": 1, "title": "Book 1", "author": 1, "publisher": 18},
{"id": 2, "title": "Book 2", "author": 2, "publisher": 26},
...
],
"include": {
"authors": [
{"id": 1, "first_name": "Author", "last_name": "One"},
{"id": 2, "first_name": "Author", "last_name": "Two"},
... for all author ids in paged `results` field above
]
}
}
到目前为止,我的观点如下:
class BookViewSet(viewsets.ModelViewSet):
queryset = Book.objects.all()
serializer_class = BookSerializer
permission_classes = (IsAuthenticated,)
pagination_class = LimitOffsetPagination
filter_class = BookFilterSet
filter_backends = [DjangoFilterBackend]
def list(self, request, *args, **kwargs):
# Grab include from url parameters
include = request.query_params.get('include', None)
# Apply incoming filters to books
queryset = self.filter_queryset(self.get_queryset())
# Apply pagination to queryset
page = self.paginate_queryset(queryset)
# Assemble include data if necessary
if include is not None:
include_data = {}
includes = include.split(',')
response_data = serializer.data
response_data['includes'] = {}
for entity in includes:
if entity == 'authors':
authors = Author.objects.distinct().filter(book__in=page)
authors_serializer = AuthorSerializer(authors, many=True)
include_data['authors'] = authors_serializer.data
elif entity == 'publishers':
publishers = Publisher.objects.distinct().filter(book__in=page)
publishers_serializer = PublisherSerializer(publishers, many=True)
include_data['publishers'] = publishers_serializer.data
serializer = self.get_serializer(page, many=True)
# PROBLEM: How can I inject include_data into my response below???
return self.get_paginated_response(serializer.data)
所以我能够接受传入的请求,获取过滤和分页的查询,并提取正确的author
序列publisher
化数据。但是,我不确定通过分页响应如何注入这些数据(参见上述代码的最后两行)。
关于如何实现这一点的任何想法?在视图中执行此操作是否正确?或者我是否需要以某种方式获取序列化程序中的所有内容?如果我这样做,有没有办法在我的响应中将include
数组作为数组的兄弟results
(而不是include
嵌入results
)?
另外,我意识到有一个django-rest-framwork-jsonapi
包,但是它也会以一种需要我对我的客户端代码进行重大更改的方式转换我的数据,这是我试图避免的。因此,我在这里提出的“轻”版本。
解决方案
添加
class CustomPagination(pagination.PageNumberPagination):
def get_paginated_response(self, data, include_data):
return Response({
'links': {
'next': self.get_next_link(),
'previous': self.get_previous_link()
},
'count': self.page.paginator.count,
'results': data,
'include': include_data
})
并配置其使用
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'my_project.apps.core.pagination.CustomPagination',
'PAGE_SIZE': 100
}
然后在你的列表方法中做
return self.get_paginated_response(serializer.data, include_data)
推荐阅读
- javascript - 将动画脚本应用到不同的 Div/img
- python - 导入 Django 2.0 实用程序函数(与 django 1.1 相比)
- python - matplotlib导航栏错误'FigureCanvasTkAgg'对象在tkinter中没有属性'manager'
- php - 停止亚马逊 ec2 健康检查器检查文件
- python - 如何根据预定义的行索引逐行更改张量的值
- java - 如何将值传递给 JavaFX 中的当前/上一个阶段?
- python - 有没有办法让用户提供将在我的程序中运行的 Python 代码?
- gradle - 使用从 4.9 迁移的 Gradle 5.3.1 发布
- javascript - 为什么可以将元素推送到数组但不能在 mongodb 中正确保存?
- mysql - ER_NON_UNIQ_ERROR 以及如何正确设计表