如何在 Django 中动态过滤字段名称、条件和值
How to dynamically filter with field name, condition and values in Django
我有一个要求,就是从客户端获取一个对象数组,其中包含字段名称、过滤条件和过滤值,如下所示。
示例对象数组:
[
{field_name: "book_name", filter_condition: "contains", filter_value: "some book name"},
{field_name: "book_category", filter_condition: "not_equal", filter_value: "category value"},
{field_name: "book_author", filter_condition: "starts_with", filter_value: "authoer name"},
{field_name: "book_price", filter_condition: "equal", filter_value: 100}
]
我必须根据上述所有条件进行过滤。假设我有一个名为 Book 的模型和对象数组中的字段(即 book_name、book_category、book_author、book_price)。对于 filter_condition,我编写了一个函数来比较 filter_condition 并分配 Django 查询集 API。例如。
def assign_filter_condition(self, request, filter_condition, field_name, filter_value):
if filter_condition == "contains":
kwargs = {
'{0}__icontains'.format(field_name): filter_value
}
return kwargs
...
这里不知道exclude和NOT query的条件怎么申请
我真的不明白这个逻辑怎么写。任何人都可以帮助逻辑。
提前致谢。
你可以使用 dict 解包来做到这一点
请注意你不需要条件所以是一个字典,数组就足够了
以下代码将引导您到达所需位置。
conditions = [
("book_name", "contains", "some book name"),
("book_category", "not_equal", "category value"),
("book_author", "starts_with", "authoer name"),
("book_price", "equal", 100)
]
def get_filter(values):
name,condition,value = values
key = f"{name}__{condition}"
return key, value
filters = dict(map(get_filter,conditions))
qs = qs.filter(**filters)
在浏览了几篇 Whosebug 帖子后,我明白了其中的逻辑。所以下面是逻辑。
def get_filter(self, field_name, filter_condition, filter_value):
# thanks to the below post
#
# the idea to this below logic is very similar to that in the above mentioned post
if filter_condition.strip() == "contains":
kwargs = {
'{0}__icontains'.format(field_name): filter_value
}
return Q(**kwargs)
if filter_condition.strip() == "not_equal":
kwargs = {
'{0}__iexact'.format(field_name): filter_value
}
return ~Q(**kwargs)
if filter_condition.strip() == "starts_with":
kwargs = {
'{0}__istartswith'.format(field_name): filter_value
}
return Q(**kwargs)
if filter_condition.strip() == "equal":
kwargs = {
'{0}__iexact'.format(field_name): filter_value
}
return Q(**kwargs)
if filter_condition.strip() == "not_equal":
kwargs = {
'{0}__iexact'.format(field_name): filter_value
}
return ~Q(**kwargs)
def get(self, request):
# getting the array of objects data to filter. The array of objects data
# example is in the question
filter_data = request.query_params.getlist('filterData[]')
all_books = Books.objects.all()
# Creating initial Q object
filter_objects = Q()
# Looping through the array of objects
for data in filter_data:
# The main part. Calling get_filter and passing the filter object data.
filter_objects &= self.get_filter(
data["fieldName"], data["filterCondition"],
data["filterValue"])
filtered_data = all_books.filter(filter_objects)
希望对大家有所帮助。 :)
创建一个继承自 DjangoFilterBackends 的 class 并使用它来代替
class MyFilterBackend(DjangoFilterBackend):
def get_filterset_kwargs(self, request, queryset, view):
data = request.query_params
data._mutable = True
for item in data:
try:
print(item)
field = getattr(queryset.model, item)
field: DeferredAttribute
data[item] = [x for x in list(field.field.choices) if x[1] == data[item]][0][0]
except:
pass
return {
'data': request.query_params,
'queryset': queryset,
'request': request,
}
我有一个要求,就是从客户端获取一个对象数组,其中包含字段名称、过滤条件和过滤值,如下所示。
示例对象数组:
[
{field_name: "book_name", filter_condition: "contains", filter_value: "some book name"},
{field_name: "book_category", filter_condition: "not_equal", filter_value: "category value"},
{field_name: "book_author", filter_condition: "starts_with", filter_value: "authoer name"},
{field_name: "book_price", filter_condition: "equal", filter_value: 100}
]
我必须根据上述所有条件进行过滤。假设我有一个名为 Book 的模型和对象数组中的字段(即 book_name、book_category、book_author、book_price)。对于 filter_condition,我编写了一个函数来比较 filter_condition 并分配 Django 查询集 API。例如。
def assign_filter_condition(self, request, filter_condition, field_name, filter_value):
if filter_condition == "contains":
kwargs = {
'{0}__icontains'.format(field_name): filter_value
}
return kwargs
...
这里不知道exclude和NOT query的条件怎么申请
我真的不明白这个逻辑怎么写。任何人都可以帮助逻辑。
提前致谢。
你可以使用 dict 解包来做到这一点 请注意你不需要条件所以是一个字典,数组就足够了 以下代码将引导您到达所需位置。
conditions = [
("book_name", "contains", "some book name"),
("book_category", "not_equal", "category value"),
("book_author", "starts_with", "authoer name"),
("book_price", "equal", 100)
]
def get_filter(values):
name,condition,value = values
key = f"{name}__{condition}"
return key, value
filters = dict(map(get_filter,conditions))
qs = qs.filter(**filters)
在浏览了几篇 Whosebug 帖子后,我明白了其中的逻辑。所以下面是逻辑。
def get_filter(self, field_name, filter_condition, filter_value):
# thanks to the below post
#
# the idea to this below logic is very similar to that in the above mentioned post
if filter_condition.strip() == "contains":
kwargs = {
'{0}__icontains'.format(field_name): filter_value
}
return Q(**kwargs)
if filter_condition.strip() == "not_equal":
kwargs = {
'{0}__iexact'.format(field_name): filter_value
}
return ~Q(**kwargs)
if filter_condition.strip() == "starts_with":
kwargs = {
'{0}__istartswith'.format(field_name): filter_value
}
return Q(**kwargs)
if filter_condition.strip() == "equal":
kwargs = {
'{0}__iexact'.format(field_name): filter_value
}
return Q(**kwargs)
if filter_condition.strip() == "not_equal":
kwargs = {
'{0}__iexact'.format(field_name): filter_value
}
return ~Q(**kwargs)
def get(self, request):
# getting the array of objects data to filter. The array of objects data
# example is in the question
filter_data = request.query_params.getlist('filterData[]')
all_books = Books.objects.all()
# Creating initial Q object
filter_objects = Q()
# Looping through the array of objects
for data in filter_data:
# The main part. Calling get_filter and passing the filter object data.
filter_objects &= self.get_filter(
data["fieldName"], data["filterCondition"],
data["filterValue"])
filtered_data = all_books.filter(filter_objects)
希望对大家有所帮助。 :)
创建一个继承自 DjangoFilterBackends 的 class 并使用它来代替
class MyFilterBackend(DjangoFilterBackend):
def get_filterset_kwargs(self, request, queryset, view):
data = request.query_params
data._mutable = True
for item in data:
try:
print(item)
field = getattr(queryset.model, item)
field: DeferredAttribute
data[item] = [x for x in list(field.field.choices) if x[1] == data[item]][0][0]
except:
pass
return {
'data': request.query_params,
'queryset': queryset,
'request': request,
}