在django rest框架中使用django-filters时,默认查询过滤表单将为所有字段添加所有查询参数,而空字段最终将作为空字符串传递给后端。空字符串不是None,因此status = self.request.query_params.get('status', None)
仍会将空字符串添加到变量中,这将使其进入queryset.filter函数。当要过滤的字段不是字符串时,这非常糟糕。
所以我的问题是我做错了什么吗?有没有办法检查空字符串参数?我不确定自己是否正在正确过滤(我可能无缘无故地进行了两次过滤,但由于要与django-rest-frameworks可浏览API内置集成,因此我想在其中使用django-filters。
我的解决方法是三元运算符在调用query_params.get
后检查空字符串
以下是我对该API的查看代码:
class JobList(generics.ListCreateAPIView):
serializer_class = JobCreateSerializer
permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
filter_backends = (filters.OrderingFilter, DjangoFilterBackend)
filterset_fields = ('status', 'success', 'worker_id', 'owner', 'job_type')
ordering_fields = ('priority', 'submitted', 'assigned', 'completed')
def perform_create(self, serializer):
serializer.save(owner=self.request.user)
def get(self, request, format=None):
# IMPORTANT: use self.get_queryset() any place you want filtering to be enabled
# for built in filtering or ordering you must call self.filter_queryset
jobs = self.filter_queryset(self.get_queryset())
serializer = JobSerializer(jobs, context={'request': request}, many=True)
return Response(serializer.data)
def get_queryset(self):
"""
This view should return a list of all the purchases
for the currently authenticated user.
"""
queryset = Job.objects.all()
status = self.request.query_params.get('status', None)
status = status if not status == '' else None
success = self.request.query_params.get('success', None)
success = success if not success == '' else None
worker_id = self.request.query_params.get('worker_id', None)
worker_id = worker_id if not worker_id == '' else None
owner_id = self.request.query_params.get('owner', None)
owner_id = owner_id if not owner_id == '' else None
job_type = self.request.query_params.get('job_type', None)
job_type = job_type if not job_type == '' else None
if status is not None:
queryset = queryset.filter(status=status)
if success is not None:
queryset = queryset.filter(success=success)
if worker_id is not None:
queryset = queryset.filter(worker_id=worker_id)
if owner_id is not None:
queryset = queryset.filter(owner=owner_id)
if job_type is not None:
queryset = queryset.filter(job_type=job_type)
return queryset
答案 0 :(得分:0)
为什么不将默认值设置为空字符串,而是将其用作保护值而不是None
?
status = self.request.query_params.get("status", "")
success = self.request.query_params.get("success", "")
# ...
if status:
queryset = queryset.filter(status=status)
if success:
queryset = queryset.filter(success=success)
# ...
答案 1 :(得分:0)
如果您使用if status:
而不是if status is not None:
,则空字符串和None
都将得到False
。对于整数来说,这样做很危险,因为0
将返回false,但这在这里不是问题,因为所有参数都是字符串。
您还可以将''
定义为默认值,然后检查非零长度的字符串:
status = self.request.query_params.get('status', '')
# ...
if len(status):
答案 2 :(得分:0)
谢谢您的回答,我认为它们是有效的方法,但它们都在进行手动检查。我一直在寻找一种内置的方式来将query_params附带的JSON本机类型转换为Python本机类型(false到False,null到None等)。希望避免手动检查和转换每个query_param。
如果Django Rest框架中没有这样的东西,那真让我大吃一惊。因此,我创建了一个辅助函数,该函数可以从query_params到Python dict进行简单的一级深度转换。我希望这对其他人有帮助,或者如果有人知道DRF中类似的便利功能,我将不胜感激。或者,如果有人可以告诉我为什么这是一种不好的方法,我也将不胜感激!
def query_params_parser(self, fields_list):
json_values_dict = {}
for field in fields_list:
value = '"' + self.request.query_params.get(field) + '"' if not self.query_params.get(field, '') == '' else 'null'
json_values_dict['"' + field + '"'] = value
json_string = '{'
for idx, (key, value) in enumerate(json_values_dict.items()):
json_string += f'{key}: {value}'
if idx < len(json_values_dict) - 1:
json_string += ','
json_string += '}'
final_dict = json.loads(json_string)
return final_dict
def get_queryset(self):
"""
This view should return a list of all the purchases
for the currently authenticated user.
"""
queryset = Job.objects.all()
# parse json query_params
# query_params, list of fields
# returns dict
params_dict = self.query_params_parser(['status',
'success',
'worker_id',
'owner',
'job_type'])
status = params_dict['status']
success = params_dict['success']
worker_id = params_dict['worker_id']
owner = params_dict['owner']
job_type = params_dict['job_type']
if status is not None:
queryset = queryset.filter(status=status)
if success is not None:
queryset = queryset.filter(success=success)
if worker_id is not None:
queryset = queryset.filter(worker_id=worker_id)
if owner is not None:
queryset = queryset.filter(owner=owner)
if job_type is not None:
queryset = queryset.filter(job_type=job_type)
return queryset
上面的函数在有限的测试下可以工作,因此它可能有很多错误。