Djangoのほぼすべての種類のルックアップには、大文字と小文字を区別しないバージョンがあります。
ケースが正しくないと確信している場合にルックアップを実行する必要があるため、これは問題です。
Products.objects.filter(code__in=[user_entered_data_as_list])
これに対処するために私にできることはありますか?人々はこの問題を回避するためのハックを思いついたことがありますか?
Djangoのほぼすべての種類のルックアップには、大文字と小文字を区別しないバージョンがあります。
ケースが正しくないと確信している場合にルックアップを実行する必要があるため、これは問題です。
Products.objects.filter(code__in=[user_entered_data_as_list])
これに対処するために私にできることはありますか?人々はこの問題を回避するためのハックを思いついたことがありますか?
MySQLデータベース自体で大文字と小文字を区別しないようにすることで、これを回避しました。Djangoの人々がこれを機能として追加したり、独自のフィールドルックアップを提供する方法に関するドキュメントを提供したりすることに興味があるとは思えません(各dbバックエンドにコードを提供しなくても可能であると仮定します)
これを行う1つの方法は、確かに不格好です。
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',])
都市名が次のような結果になります
トキオまたはトキオまたはトキオまたはパリまたはパリまたはパリ
競合が発生しない場合、考えられる回避策は、オブジェクトが保存されているときとであるときの両方で、文字列を大文字または小文字に変換することfilter
です。
これは、ケースで準備されたDB値を必要としないソリューションです。また、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)
他の効率的な解決策は、非常に移植性の高いraw-SQLlower()
関数でextraを使用することです。
MyModel.objects.extra(
select={'lower_' + fieldname: 'lower(' + fieldname + ')'}
).filter('lover_' + fieldname + '__in'=[x.lower() for x in iterable])
もう1つの解決策は、大雑把ではありますが、元の文字列のさまざまなケースを「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
オブジェクトを使用したルックアップは、データベースを1回だけヒットするように構築できます。
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]]