首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Django-Filters空字符串查询参数导致验证错误

Django-Filters空字符串查询参数导致验证错误
EN

Stack Overflow用户
提问于 2019-03-14 03:56:11
回答 3查看 2.5K关注 0票数 2

当使用django-filters和django rest框架时,默认的查询过滤表单将添加所有字段的所有查询参数,并且空字段最终作为空字符串传递到后端。空字符串不是None,因此status = self.request.query_params.get('status', None)仍然会将空字符串添加到变量中,这将使其传递到queryset.filter函数。当要过滤的字段不是字符串时,这是非常糟糕的。

所以我的问题是我做错了什么吗?有没有办法检查空字符串参数?我甚至不确定我的过滤是否正确(我可能无缘无故地过滤了两次,但我想要django-filter,因为它内置了django-rest-framework可浏览API。

我的解决方法是在调用query_params.get之后使用三元运算符检查空字符串

下面是我的API视图代码:

代码语言:javascript
运行
复制
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
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2019-03-14 04:16:02

如果使用if status:而不是if status is not None:,则空字符串和None都会提供False。这对于int来说很危险,因为0将返回false,但这在这里不是问题,因为所有参数都是字符串。

您还可以将''定义为默认值,然后检查非零长度的字符串:

代码语言:javascript
运行
复制
status = self.request.query_params.get('status', '')
# ...
if len(status):
票数 2
EN

Stack Overflow用户

发布于 2019-03-14 04:15:53

为什么不将缺省值设置为空字符串,并将其用作保护值而不是None

代码语言:javascript
运行
复制
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
EN

Stack Overflow用户

发布于 2019-03-14 07:08:13

感谢您的回答,我认为它们是有效的方法,但它们都在进行手动检查。我正在寻找一种内置的方法来将query_params附带的JSON原生类型转换为Python原生类型(false到False,null到None,等等)。希望避免手动检查和转换每个query_param。

如果这样的东西在Django Rest框架中不可用,我会很吃惊。所以我创建了一个助手函数,它可以完成从query_params到Python dict的简单的一级深度转换。我希望这对其他人有帮助,或者如果有人知道DRF中类似的便利功能,我将不胜感激。或者如果有人能告诉我为什么这是一个糟糕的方法,我也会很感激!

代码语言:javascript
运行
复制
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

上面的函数在有限的测试下工作,所以它可能有很多bug。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/55150233

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档