開発部第2グループの佐藤です。
Django 2.2.23から3.2.6へのバージョンアップしたところ、ORMが生成するクエリが一部変更されていました。調査した変更内容と対応方法を共有します。使用しているDBはMySQLです。
起こったこと
booleanフィールドでfilterする際生成されるクエリが変更されていました。 MyModel.objects.filter(is_hoge=True)
から出力されるクエリは以下の通りです
# サンプルのclass class MyModel(TimeStampedModel): is_hoge = models.BooleanField() is_piyo = models.BooleanField() # クエリ例 MyModel.objects.filter(is_hoge=True) MyModel.objects.filter(is_piyo=False)
// 今までの出力 SELECT * FROM app_my_model WHERE is_hoge=1; SELECT * FROM app_my_model WHERE is_piyo=0; // アップデート後の出力 SELECT * FROM app_my_model WHERE is_hoge; SELECT * FROM app_my_model WHERE NOT is_piyo;
MySQLではBooleanFieldはTINYINT型のカラムとなり、テーブルに格納される値はTrueの場合は1、Falseの場合は0となります。
WHERE is_hoge の状態でも今までと同じ検索結果が出力されますが、is_hogeがTINYINT型であるため、-128〜127の0を除いた値(もしくは1〜255)の範囲検索が実行され、INDEXも効かなくなります。
リリースノートには変更の記載はなく、Djangoのissueが発行されています。https://code.djangoproject.com/ticket/32691
対応
クエリを今まで通り is_hoge=1
、 is_piyo=0
と出力させるための修正例は以下の通りです。
from django.db import models MyModel.objects.filter(is_hoge=models.Value(1)) MyModel.objects.filter(is_piyo=models.Value(0))
なかなか発見しづらい変更内容です。皆様もご注意ください。