如何在Django中有条件地添加过滤字段和值

huangapple go评论72阅读模式
英文:

how to conditionally add filter fields and value in Django

问题

考虑以下示例模型。

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 是一个空列表。因此,在从 Server 模型进行筛选时,我想添加 os_list、server_owner_list 和 server_located,并排除 server_name。在未来,数据库模型将添加更多字段,我可能会从客户端请求接收额外的值列表,其中可能包含空的数组。因此,我不想编写一堆 if-else 条件来检查哪些列表为空而哪些不为空。

请问有谁能帮助我如何编写可扩展的 ORM?

编辑:

所以,从前端的 React 表格中,我将使用列过滤。从列下拉菜单中,如果用户选择了列下拉菜单中的数据,选择的数据将以数组格式存在。如果用户重置了先前选择的数据,将会得到一个空数组。因此,当用户按下筛选按钮时,数据将传递到后端。

因此,在后端,我会收到空的数组。所以如果:

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
    )
elif len(os_filter_val) > 0 and len(server_owner_list) == 0:
    Server.objects.filter(os__in=os_filter_val)
...
...
...

因此,在这里,如果字段更多,那么我必须编写许多 if-else 条件来检查是否有任何空列表。如果存在空列表,则不要将其包含在查询集中。

是否有一种方法可以检查空列表并仅添加非空列表,而不编写 if-else 条件?

英文:

Consider the below sample model.

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)
    ...
    ...

In the future, this model will have more fields.

So from the request, I would get list of values that I need to filter. Consider the below sample data.

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

I want to exclude the lists which are empty. From the above example, server_name is an empty list. So while filtering from the Server model I want to add os_list, server_owner_list and server_located and exclude the server_name. In the future, more fields will be added to the DB model, and I might receive an extra list of values from the client request. which could have empty list of array. So I don't want to write a bunch of if-else conditions to check which lists are empty and not empty.

Can anyone please help me how can I write scalable ORM for this.

Edit:

so from a frontend react table, I will use column filtering. from the column dropdown, if the user selects the data from the column dropdown, selected data will be there in the array format. If the user resets the data which he had selected previously will be an empty array. so when the user presses the filter the data will be passed to the backend.

So in the backend, I would receive the empty list of array. So if

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)

So in the above example consider for server_owner_list I got an empty array and I don't want to include it in the filter queryset what I would generally do is.

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)
....
....
....

So here if fields are more then I have to write a lot of if-else condition to check whether there are any empty lists. If its there do not include it in the queryset.

So is there any way where we can check for the empty list and add only the nonempty lists without writing the if-else conditions.

答案1

得分: 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,)
英文:

Try this code.Change OR and AND as per your requirement and also add if condition in your url parameters.

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,)

答案2

得分: 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

但除此之外,我建议您阅读一些关于在null和范围内的筛选以及基本筛选的内容。

英文:

For filtering, in general, I recommend you Django-Filters. It will save you a lot of if-else conditions. For specific in filter, you can write a custom filter class:

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

But besides that I recommend you to read about some tips with in null and ranges and base filtering

huangapple
  • 本文由 发表于 2020年1月6日 19:42:44
  • 转载请务必保留本文链接:https://go.coder-hub.com/59611511.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定