有没有办法在 Django 中进行不区分大小写的 IN 查询?

发布于 2024-08-23 14:38:17 字数 212 浏览 5 评论 0原文

Django 中几乎每种查找都有一个不区分大小写的版本,除了 in,它出现了。

这是一个问题,因为有时我需要进行查找,确定情况会不正确。

Products.objects.filter(code__in=[user_entered_data_as_list])

我能做些什么来解决这个问题吗?人们是否想出了解决这个问题的方法?

Nearly every kind of lookup in Django has a case-insensitive version, EXCEPT in, it appears.

This is a problem because sometimes I need to do a lookup where I am certain the case will be incorrect.

Products.objects.filter(code__in=[user_entered_data_as_list])

Is there anything I can do to deal with this? Have people come up with a hack to work around this issue?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

残花月 2024-08-30 14:38:18

我通过使 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)

I worked around this by making the MySQL database itself case-insensitive. I doubt that the people at Django are interested in adding this as a feature or in providing docs on how to provide your own field lookup (assuming that is even possible without providing code for each db backend)

Here is one way to do it, admittedly it is clunky.

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)
裂开嘴轻声笑有多痛 2024-08-30 14:38:18

如果您的数据库是 MySQL,Django 会不区分大小写地处理 IN 查询。虽然我不确定其他

编辑1:

model_name.objects.filter(location__city__name__in': ['Tokio','Paris',])

将给出以下结果,其中城市名称是

东京 东京 东京或巴黎< /strong> 巴黎还是巴黎


If your database is MySQL, Django treats IN queries case insensitively. Though I am not sure about others

Edit 1:

model_name.objects.filter(location__city__name__in': ['Tokio','Paris',])

will give following result in which city name is

Tokio or TOKIO or tokio or Paris or PARIS or paris

無處可尋 2024-08-30 14:38:18

您可以注释降低的代码并降低输入的数据

from django.db.models.functions import Lower

Products.objects.annotate(lower_code=Lower('code')).filter(lower_code__in=[user_entered_data_as_list_lowered])

You can do it annotating the lowered code and also lowering the entered data

from django.db.models.functions import Lower

Products.objects.annotate(lower_code=Lower('code')).filter(lower_code__in=[user_entered_data_as_list_lowered])
魄砕の薆 2024-08-30 14:38:18

如果不会产生冲突,可能的解决方法是在保存对象时和在过滤器中将字符串转换为大写或小写。

If it won't create conflicts, a possible workaround may be transforming the strings to upper or lowercase both when the object is saved and in the filter.

简单 2024-08-30 14:38:18

这是一个不需要案例准备的 DB 值的解决方案。
它还在数据库引擎端进行过滤,这意味着比迭代 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)

另一个有效的解决方案是使用 extra 和相当可移植的原始 SQL lower() 函数:

MyModel.objects.extra(
    select={'lower_' + fieldname: 'lower(' + fieldname + ')'}
).filter('lover_' + fieldname + '__in'=[x.lower() for x in iterable])

Here is a solution that do not require case-prepared DB values.
Also it makes a filtering on DB-engine side, meaning much more performance than iterating over 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)

The other efficient solution is to use extra with quite portable raw-SQL lower() function:

MyModel.objects.extra(
    select={'lower_' + fieldname: 'lower(' + fieldname + ')'}
).filter('lover_' + fieldname + '__in'=[x.lower() for x in iterable])
故乡的云 2024-08-30 14:38:18

另一个解决方案 - 尽管很粗糙 - 是将原始字符串的不同情况包含在“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

Another solution - albeit crude - is to include the different cases of the original strings in the list argument to the 'in' filter. For example: instead of ['a', 'b', 'c'], use ['a', 'b', 'c', 'A', 'B', 'C'] instead.

Here's a function that builds such a list from a list of strings:

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
永不分离 2024-08-30 14:38:18

使用 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)

A lookup using Q object can be built to hit the database only once:

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)
吐个泡泡 2024-08-30 14:38:18

更优雅一点的方式是这样的:

[x for x in Products.objects.all() if x.code.upper() in [y.upper() for y in user_entered_data_as_list]]

A litle more elegant way would be this:

[x for x in Products.objects.all() if x.code.upper() in [y.upper() for y in user_entered_data_as_list]]
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文