Django:如何像在分页中那样将查询参数添加到查询集中?
Django: How to add query params to queryset as is done in Pagination?
我们的网站是DRF后台,Vue前台。它结合了广泛的过滤器选项,因此任何端点都可以有许多查询参数——比如 example.com?name__icontains=bob&...etc.
在一个视图中,我们需要 return 一列的总和。我们不想为前端创建一个单独的端点,而是想将它添加到原始视图的结果中。像这样...
{
"pagination": {
...pagination stuff...
},
"results": [
{
"id": 1,
"task": "DMSD-50",
...other fields...,
"duration": 204
},
{
"id": 2,
"task": "DMSD-53",
...other fields...,
"duration": 121
},
...more rows...
],
"totals": {
"duration": 955
}
}
我的第一次尝试是将其添加到视图的 get()
方法中:
def get(self, request, *args, **kwargs):
response = super().get(request, *args, **kwargs)
queryset = self.get_queryset()
totals = queryset.aggregate(total_duration=Sum('duration'))
response['totals'] = {
'duration': totals['total_duration'] or 0
}
return response
...在我执行完整(未过滤)列表时有效。但是当我在 URL 中添加过滤器时,总数总是相同的。这让我意识到 get_queryset()
不会添加来自 URL 的查询参数。然后我意识到分页 class 必须合并查询参数,所以我的第二个解决方案是将此代码添加到我们的自定义分页 class。这行得通,但它似乎是一个 hack。
获取已添加查询参数的查询集或自行添加查询集的最佳方法是什么?我知道这些参数在 kwargs 中可用,所以如果(例如)我的视图仅在“名称”上过滤,我可以通过 kwargs['name']
访问过滤器 - 简单。但是,正如我所说,可以有很多过滤器参数,而且它们肯定因视图而异。
如果我遍历 kwargs,我想我可能会得到除过滤器 args 之外的其他东西 - 想到排序顺序 - 但我猜可能还有其他东西。我需要一种万无一失的方法来获取所有过滤器参数和仅过滤器参数。
创建空上下文
Context = {}
使用 request.GET
中的每个现有过滤器更新上下文
If request.GET.get('filter'):
Context['filter] = request.GET.get('filter')
向查询集添加过滤器
Query.objects.filter(**Context )
我假设您正在使用一些通用视图或至少继承自 ListModelMixin
。 get_queryset
方法不过滤查询集,该任务由视图的 filter_queryset
method 完成,因此当您覆盖 get
方法并且不在那里调用该方法时没有过滤。更改您的代码以像这样使用它:
class YourView(generics.ListAPIView): # Just an assumption here
...
def get(self, request, *args, **kwargs):
response = super().get(request, *args, **kwargs)
queryset = self.filter_queryset(self.get_queryset())
totals = queryset.aggregate(total_duration=Sum('duration'))
response['totals'] = {
'duration': totals['total_duration'] or 0
}
return response
为了更好地理解内置视图的工作原理,您可能需要查看它 source code [GitHub]。
我们的网站是DRF后台,Vue前台。它结合了广泛的过滤器选项,因此任何端点都可以有许多查询参数——比如 example.com?name__icontains=bob&...etc.
在一个视图中,我们需要 return 一列的总和。我们不想为前端创建一个单独的端点,而是想将它添加到原始视图的结果中。像这样...
{
"pagination": {
...pagination stuff...
},
"results": [
{
"id": 1,
"task": "DMSD-50",
...other fields...,
"duration": 204
},
{
"id": 2,
"task": "DMSD-53",
...other fields...,
"duration": 121
},
...more rows...
],
"totals": {
"duration": 955
}
}
我的第一次尝试是将其添加到视图的 get()
方法中:
def get(self, request, *args, **kwargs):
response = super().get(request, *args, **kwargs)
queryset = self.get_queryset()
totals = queryset.aggregate(total_duration=Sum('duration'))
response['totals'] = {
'duration': totals['total_duration'] or 0
}
return response
...在我执行完整(未过滤)列表时有效。但是当我在 URL 中添加过滤器时,总数总是相同的。这让我意识到 get_queryset()
不会添加来自 URL 的查询参数。然后我意识到分页 class 必须合并查询参数,所以我的第二个解决方案是将此代码添加到我们的自定义分页 class。这行得通,但它似乎是一个 hack。
获取已添加查询参数的查询集或自行添加查询集的最佳方法是什么?我知道这些参数在 kwargs 中可用,所以如果(例如)我的视图仅在“名称”上过滤,我可以通过 kwargs['name']
访问过滤器 - 简单。但是,正如我所说,可以有很多过滤器参数,而且它们肯定因视图而异。
如果我遍历 kwargs,我想我可能会得到除过滤器 args 之外的其他东西 - 想到排序顺序 - 但我猜可能还有其他东西。我需要一种万无一失的方法来获取所有过滤器参数和仅过滤器参数。
创建空上下文
Context = {}
使用 request.GET
中的每个现有过滤器更新上下文If request.GET.get('filter'): Context['filter] = request.GET.get('filter')
向查询集添加过滤器
Query.objects.filter(**Context )
我假设您正在使用一些通用视图或至少继承自 ListModelMixin
。 get_queryset
方法不过滤查询集,该任务由视图的 filter_queryset
method 完成,因此当您覆盖 get
方法并且不在那里调用该方法时没有过滤。更改您的代码以像这样使用它:
class YourView(generics.ListAPIView): # Just an assumption here
...
def get(self, request, *args, **kwargs):
response = super().get(request, *args, **kwargs)
queryset = self.filter_queryset(self.get_queryset())
totals = queryset.aggregate(total_duration=Sum('duration'))
response['totals'] = {
'duration': totals['total_duration'] or 0
}
return response
为了更好地理解内置视图的工作原理,您可能需要查看它 source code [GitHub]。