几乎 Django 中的每一种查找都有一个不区分大小写的版本,除了它出现。
这是一个问题,因为有时我需要在我确定情况不正确的地方进行查找。
Products.objects.filter(code__in=[user_entered_data_as_list])
我能做些什么来解决这个问题吗?人们有没有想出一个技巧来解决这个问题?
几乎 Django 中的每一种查找都有一个不区分大小写的版本,除了它出现。
这是一个问题,因为有时我需要在我确定情况不正确的地方进行查找。
Products.objects.filter(code__in=[user_entered_data_as_list])
我能做些什么来解决这个问题吗?人们有没有想出一个技巧来解决这个问题?
我通过使 MySQL 数据库本身不区分大小写来解决这个问题。我怀疑 Django 的人是否有兴趣将此作为功能添加或提供有关如何提供您自己的字段查找的文档(假设甚至可以在不为每个数据库后端提供代码的情况下)
这是一种方法,诚然它很笨重。
products = Product.objects.filter(**normal_filters_here)
results = Product.objects.none()
for d in user_entered_data_as_list:
results |= products.filter(code__iexact=d)
如果你的数据库是 MySQL,Django 会不区分大小写地处理 IN 查询。虽然我不确定其他人
编辑1:
model_name.objects.filter(location__city__name__in': ['Tokio','Paris',])
将给出以下结果,其中城市名称是
Tokio or TOKIO or tokio or Paris or PARIS or paris
这是一个不需要案例准备的数据库值的解决方案。它还在数据库引擎端进行过滤,这意味着比迭代更多的性能objects.all()
。
def case_insensitive_in_filter(fieldname, iterable):
"""returns Q(fieldname__in=iterable) but case insensitive"""
q_list = map(lambda n: Q(**{fieldname+'__iexact': n}), iterable)
return reduce(lambda a, b: a | b, q_list)
另一个有效的解决方案是使用额外的非常可移植的 raw-SQLlower()
函数:
MyModel.objects.extra(
select={'lower_' + fieldname: 'lower(' + fieldname + ')'}
).filter('lover_' + fieldname + '__in'=[x.lower() for x in iterable])
如果它不会产生冲突,一个可能的解决方法可能是在保存对象时将字符串转换为大写或小写filter
。
另一种解决方案 - 尽管很粗略 - 是将原始字符串的不同情况包含在“in”过滤器的列表参数中。例如:用 ['a', 'b', 'c', 'A', 'B', 'C'] 代替 ['a', 'b', 'c']。
这是一个从字符串列表构建这样一个列表的函数:
def build_list_for_case_insensitive_query(the_strings):
results = list()
for the_string in the_strings:
results.append(the_string)
if the_string.upper() not in results:
results.append(the_string.upper())
if the_string.lower() not in results:
results.append(the_string.lower())
return results
可以构建使用Q
对象的查找以仅命中数据库一次:
from django.db.models import Q
user_inputed_codes = ['eN', 'De', 'FR']
lookup = Q()
for code in user_inputed_codes:
lookup |= Q(code__iexact=code)
filtered_products = Products.objects.filter(lookup)
一个更优雅的方式是这样的:
[x for x in Products.objects.all() if x.code.upper() in [y.upper() for y in user_entered_data_as_list]]