我正在尝试为模型编写搜索功能。 客户具有以下字段:
cstid = models.AutoField(primary_key=True, unique=True)
name = models.CharField(max_length=35)
age=models.IntegerField()
gender = models.CharField(max_length=10, default='')
mobile = models.CharField(max_length=15, default='')
email = models.CharField(max_length=50, default='')
address = models.CharField(max_length=80, default='')
city = models.CharField(max_length=25, default='')
我的html表单将通过ajax调用django通过POST提交以下数据:
var data = {
"name": name,
"age": age,
"email": email,
"address": address,
"phone": phone,
"city": city
};
data = $(this).serialize() + "&" + $.param(data);
这些将在django视图中进行验证,并执行搜索查询,如下所示:
def searchpat_for_docwise_appt (request):
from django.core.exceptions import ObjectDoesNotExist
from django.db.models import Q
from django.db.models import CharField
from django.db.models.functions import Lower
CharField.register_lookup(Lower, "lower")
if request.method == 'POST':
name = request.POST.get('name')
age = request.POST.get('age')
# gender = request.POST.get('gender')
phone = request.POST.get('phone')
email = request.POST.get('email').lower()
address = request.POST.get('address')
city = request.POST.get('city')
if age.isdigit():
ANDSearchResult = customer.objects.filter(name__lower__contains=name.lower(), age=age, mobile__contains=phone, email__lower__contains=email.lower(
), address__lower__contains=address.lower(), city__lower__contains=city.lower())
else:
ANDSearchResult = customer.objects.filter(name__lower__contains=name.lower(), mobile__contains=phone, email__lower__contains=email.lower(
), address__lower__contains=address.lower(), city__lower__contains=city.lower())
if len(ANDSearchResult) < 1:
errmsg = 'No search results for AND search'
print("Error message is <%s>" % errmsg)
else:
print ("ANDSearchResult is <%s>" % ANDSearchResult)
errmsg = ''
if age.isdigit():
ORSearchResult = customer.objects.filter(
Q(name__lower__contains=name.lower()) | Q(age=age) | Q(
mobile__contains=phone) | Q(email__lower__contains=email.lower()) | Q(address__lower__contains=address.lower()) | Q(city__lower__contains=city.lower()))
else:
ORSearchResult = customer.objects.filter(
Q(name__lower__contains=name.lower()) | Q(
mobile__contains=phone) | Q(email__lower__contains=email.lower()) | Q(address__lower__contains=address.lower()) | Q(city__lower__contains=city.lower()))
if len(ORSearchResult) < 1:
errmsg = errmsg + 'No search results for OR search'
print("Error message is <%s>" % errmsg)
else:
print ("ORSearchResult is <%s>" % ORSearchResult)
print(errmsg)
return HttpResponse(errmsg)
else:
errmsg = 'No correct POST request. No valid response.'
print("Error message is <%s>" % errmsg)
return HttpResponse(errmsg)
如上所述,我正在同时执行两个不同的查询。我想要像查询这样的AND运算符,其中搜索必须满足所有输入参数。我还需要一个OR运算符,如果任何字段与相应字段的输入字符串匹配,则应提供结果。我的意思是,如果一个患者的名字叫杰夫(Jeff)享年56岁,一个患者的凯恩(Kane)享年23岁。我在名称字段中输入jef,在年龄字段中输入23,都应列出。
当搜索框中有空字符串时,就会出现此问题。带有空字符串的OR搜索将所有对象作为结果。显然,我不想因为我的搜索字符串为空而返回患者记录。
除了冗长的解决方案,它可以检查像这样的搜索查询的所有组合:
if (name != '' and age != '' and phone != '' and email != '' and address != '' and city != '':
ORSearchResult = customer.objects.filter(Q(name__lower__contains=name.lower()) | Q(age=age) | Q(mobile__contains=phone) | Q(email__lower__contains=email.lower()) | Q(address__lower__contains=address.lower()) | Q(city__lower__contains=city.lower()))
elif (age != '' and phone != '' and email != '' and address != '' and city != '':
ORSearchResult = customer.objects.filter(Q(age=age) | Q(mobile__contains=phone) | Q(email__lower__contains=email.lower()) | Q(address__lower__contains=address.lower()) | Q(city__lower__contains=city.lower()))
elif (phone != '' and email != '' and address != '' and city != '':
ORSearchResult = customer.objects.filter(Q(mobile__contains=phone) | Q(email__lower__contains=email.lower()) | Q(address__lower__contains=address.lower()) | Q(city__lower__contains=city.lower()))
.... Other permutations ...
什么是更好的解决方案? 想到的一个显而易见的想法是,尝试将这些过滤器编译为变量并将其传递给过滤器函数。我在正确的轨道上吗?我该怎么办?
答案 0 :(得分:1)
如果我理解正确,那么您要在不同条件之间编写OR-逻辑,因为相应的值不为空(真实性False
)。我们可以使用以下方法构造这样的Q
对象构造函数:
from django.db.models import Q
from functools import reduce
from operator import or_
def or_q_if_truthfull(**kwargs):
filtered = [Q(**{k: v}) for k, v in kwargs.items() if v]
if filtered:
return reduce(or_,filtered)
else:
return Q()
然后我们可以使用以下方法构造所需的Q
对象:
my_q = or_q_if_truthfull(
name__lower__contains=name.lower(),
age=age,
mobile__contains=phone,
email__lower__contains=email.lower()
address__lower__contains=address.lower(),
city__lower__contains=city.lower(),
)
所以我们可以使用:
ORSearchResult = customer.objects.filter(my_q)
注意:代替使用
field__lower__contains=value.lower()
,可以使用field__icontains=value
来执行大小写不变的过滤,因此构造{{1 }}是:
my_q