[英]django-rest-framework, adding 'includes' to list response, with pagination
With an API I am currently working on in django-rest-framework, I am attempting to implement something similar to a feature in the json-api standard. 我正在使用django-rest-framework中正在使用的API,尝试实现类似于json-api标准中的功能。 Given a book model: 给定一个书本模型:
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)
I want to include a parameter in the url, include
, which lets the user define if they want to include author
and publisher
models in the response. 我想在网址中包含一个参数include
,该参数可以让用户定义是否要在响应中包括author
和publisher
模型。 The additional gotcha, is I am using limit/offset pagination. 额外的陷阱,是我正在使用限制/偏移分页。 Thus, the following url: 因此,以下网址:
https://my-api-domain/api/books?limit=5&offset=0&include=authors
should return something that looks like: 应该返回如下内容:
{
"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
]
}
}
So far, my view looks like: 到目前为止,我的观点看起来像:
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)
So I am able to take the incoming request, get the filtered and paged query, and pull the proper author
and publisher
serialized data. 因此,我能够处理传入的请求,获取经过过滤和分页的查询,并提取适当的author
和publisher
序列化的数据。 However, I am not sure, with the pagination response, how to inject this data (see the last two lines of the above code). 但是,对于分页响应,我不确定如何注入此数据(请参见上面代码的最后两行)。
Any thoughts on how this can be accomplished? 关于如何实现这一目标有什么想法? Is doing this in the view even the right spot? 在视图中这样做是否正确? Or do I somehow need to be grabbing everything in my serializer? 还是我需要以某种方式获取序列化器中的所有内容? And if I do that, is there any way to get the include
array as a sibling to the results
array in my response (rather than include
being embedded in results
)? 如果我这样做了,有什么办法可以将include
数组作为我的响应中的results
数组的同级对象(而不是将include
嵌入到results
)?
Also, I realize that there is a django-rest-framwork-jsonapi
package, however it also transforms my data in such a way that would require me doing drastic changes to my client code, which I am trying to avoid. 另外,我意识到这里有一个django-rest-framwork-jsonapi
包,但是它也以一种方式转换我的数据,这要求我对我的客户端代码进行大刀阔斧的修改,而我试图避免这种情况。 Thus the 'light' version I am proposing here. 因此,我在这里提出“轻量”版本。
add 加
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
})
and configure its use 并配置其使用
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'my_project.apps.core.pagination.CustomPagination',
'PAGE_SIZE': 100
}
then in your list method do 然后在您的列表方法中
return self.get_paginated_response(serializer.data, include_data)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.