【问题标题】:how to conditionally add filter fields and value in Django如何在 Django 中有条件地添加过滤器字段和值
【发布时间】:2020-04-23 23:05:14
【问题描述】:

考虑以下示例模型。

class Server(models.Model):
    os = models.CharField(max_length=30)
    server_owner = models.CharField(max_length=30)
    server_located = models.CharField(max_length=20)
    server_name = models.CharField(max_length=20)
    ...
    ...

未来这个模型会有更多的字段。

所以从请求中,我会得到我需要过滤的值列表。考虑以下示例数据。

os_list = ["Windows", "Linux", "Mac"]
server_owner_list = ["John", "Will", "Jake", "Shyam"],
server_located = ["India", "USA"]
server_name = []
...
...
...

我想排除空列表。在上面的示例中, server_name 是一个空列表。因此,在从服务器模型过滤时,我想添加 os_list、server_owner_list 和 server_located 并排除 server_name。将来,更多字段将添加到 DB 模型中,我可能会从客户端请求中收到额外的值列表。可能有空的数组列表。所以我不想写一堆 if-else 条件来检查哪些列表是空的而不是空的。

谁能帮助我如何为此编写可扩展的 ORM。

编辑:

所以从前端反应表中,我将使用列过滤。从列下拉列表中,如果用户从列下拉列表中选择数据,则所选数据将以数组格式存在。如果用户重置他之前选择的数据将是一个空数组。所以当用户按下过滤器时,数据将被传递到后端。

所以在后端,我会收到数组的空列表。所以如果

os_filter_val = request.query_params.getlist('osFilter[]')
server_owner_list = request.query_params.getlist('serverOwnerFilter[]')      
Server.Objects.filter(
                os__in=os_filter_val,
                server_owner__in=server_owner_list)

因此,在上面的示例中,考虑 server_owner_list 我得到了一个空数组,我不想将它包含在过滤器查询集中,我通常会这样做。

if len(os_filter_val) > 0 and len(server_owner_list) > 0:
    Server.Objects.filter(
                os__in=os_filter_val,
                server_owner__in=server_owner_list)
else if(os_filter_val) > 0 and len(server_ownder_list) == 0:
    Server.Objects.filter(os__in=os_filter_val)
....
....
....

所以这里如果字段更多,那么我必须写很多 if-else 条件来检查是否有任何空列表。如果它没有包含在查询集中。

那么有什么方法可以检查空列表并仅添加非空列表而不编写 if-else 条件。

【问题讨论】:

  • 为什么必须删除空列表?您在其中执行需要该查询的代码是什么?并且由于您在 QueryDictMultiValueDict 中收到要过滤的列表(再次向我们展示一些代码),因此仅迭代 dict 并删除空项目有什么问题?
  • @dirkgroten 这将用于表过滤。我正在尝试编写通用代码。这是使用它的地方。我将在问题中添加示例代码。

标签: django orm django-rest-framework


【解决方案1】:

对于过滤,一般来说,我推荐你Django-Filters。它将为您节省很多 if-else 条件。对于具体的in过滤器,可以编写自定义过滤器类:

from rest_framework import generics
from django_filters import rest_framework as filters
from myapp import Server


class ServerFilter(filters.FilterSet):
    osFilter = filters.NumberFilter(field_name="id", lookup_expr='in')

    class Meta:
        model = Server
        fields = ['osFilter',]


class ServerList(generics.ListAPIView):
    queryset = Server.objects.all()
    serializer_class = ServerSerializer
    filter_backends = (filters.DjangoFilterBackend,)
    filterset_class = ServerFilter

但除此之外,我建议您阅读一些 tips with in null and rangesbase filtering

【讨论】:

    【解决方案2】:

    试试这个代码。根据您的要求更改 OR 和 AND,并在您的 url 参数中添加 if 条件。

    from django.db.models import Q
        os_filter_val = request.query_params.getlist('osFilter[]')
            server_owner_list = request.query_params.getlist('serverOwnerFilter[]')
            q_objects = Q()
            if os_filter_val:
                q_objects.add(Q(os__in=os_filter_val), Q.OR)
            if server_owner_list:
                q_objects.add(Q(server_owner__in=server_owner_list), Q.OR)
            Server.Objects.filter(q_objects,)
    

    【讨论】:

    • 同样在这里,我们使用 if 条件。我对代码做了一点改动,我使用了使用 Q 对象并添加它们的想法。值得一票。
    猜你喜欢
    • 1970-01-01
    • 2021-11-26
    • 2019-06-18
    • 2017-05-06
    • 2019-09-30
    • 1970-01-01
    • 2020-03-28
    • 2022-12-23
    • 1970-01-01
    相关资源
    最近更新 更多