我正在将Django rest framework用于我的REST API。我有端点,其中有一些要过滤的参数,如下所示:
# in my view
from_date = self.request.query_params.get('from', None)
to_date = self.request.query_params.get('to', None)
category = self.request.query_params.get('category', None)
color = self.request.query_params.get('color', None)
然后在选择数据的地方有if / else代码。第一次只有两个参数,所以还可以,但是后来我添加了更多的参数进行过滤,现在我认为这段代码看起来不太好,我认为需要进行一些优化。而且,不同参数的组合现在不起作用。
实际代码(在我看来):
if from_date is not None and to_date is not None:
something = Something.objects.filter(send_date__range=(from_date, to_date))
elif category:
something = Something.objects.filter(values__something__category__name__iexact=category)
elif color:
something = Something.objects.filter(values__something__color__name__iexact=color)
else:
something = Something.objects.all()
DRF中是否有内置的选项或Django中的某种类型的组合过滤,考虑到值可以为None,如何将参数组合到一个大查询中?
例如,如果用户使用日期发送起始日期和起始日期查询过滤器数据。但是用户还希望使用 from_date , to_date 和颜色或其他参数组合来过滤数据。一些参数可以省略。该代码仅是最低版本。我有更多参数,我不想为每种参数组合都写if和else。
类似于的东西(但如果其中一个值是None,则不使用该值将无法工作):
Something.objects.filter(send_date__range=(from_date, to_date))
.filter(values__something__category__name__iexact=category)
.filter(values__something__color__name__iexact=color)
答案 0 :(得分:1)
将参数转换为查询过滤器不能完全自动化,因为只有您知道应该以哪种方式在哪些字段上过滤哪些参数。但是除非您有or
和and
准则的疯狂组合,否则它应该非常简单,因为您可以无限制地链接.filter()
个呼叫,只要您想and
全部条件:
something = Something.objects.all()
if from_date and to_date:
something = something.filter(send_date__range=(from_date, to_date))
if category:
something = something.filter(values__something__category__name__iexact=category)
if color:
something = something.filter(values__something__color__name__iexact=color)
这涵盖了所有组合并且看起来很容易管理,不是吗?
如果您需要or
(某些)条件,则需要Q objects,但是可以用相同的方式进行链接:
from django.db.models.query_utils import Q
qq = Q()
if category:
qq = qq | Q(values__something__category__name__iexact=category)
if color:
qq = qq | Q(values__something__color__name__iexact=color)
something = Something.objects.filter(qq)
答案 1 :(得分:1)
这是我用于自定义过滤的模式。如果最终需要围绕每个过滤器参数进行更多的自定义实现,则可以使用诸如策略设计模式之类的东西,它可以消除if-else链。
FILTER_PARAMS = {'from': 'from_date', 'to': 'to_date', 'category': 'values__something__category__name__iexact', 'color': 'values__something__color__name__iexact'}
def get(self):
filter_params = self.get_filter_params(self.request.query_params)
qs = queryset.filter(**filter_params)
def get_filter_params(self, query_params):
fields = {}
for k, v in query_params.items():
if k in self.FILTER_PARAMS:
fields[self.FILTER_PARAMS[k]] = v
return fields