##経緯
日付範囲検索する場合に、From~Toの両方に検索日付を入力した場合は問題なかったが、どちらか片方だけを入力した場合にエラーが起きるという問題が発生。
そもそも、範囲検索のロジック記述方法がよくわかっていなかったのが原因。
(以下ロジックの補足)
・date_min・・・検索項目From側
・date_max・・・検索項目To側
・date_start・・・データベースdatetimeField
##誤りロジック(パターンA)
class c_SerchView(ListView):
template_name = 'report_app/serch.html'
model = ReportModel
def get_queryset(self):
date_min = self.request.GET.get('date_min')
date_max = self.request.GET.get('date_max')
if date_min:
object_list = ReportModel.objects.filter(date_start__gte=date_min,date_start__lte=date_max)
else:
object_list = ReportModel.objects.filter(date_start__gte=today,date_start__lte=today)
return object_list
i_serch = c_SerchView.as_view()
この場合の動きは下記のとおり。両方入力した時しか正常に検索できない。
× 2020/08/01~空欄 の場合・・・エラー発生
× 空欄~2020/08/31 の場合・・・エラーは出ないが1件も検出されない
◎ 2020/08/01~2020/08/31の場合・・・正常に検出される
× 2020/08/01~2020/08/01の場合・・・1件も検出されない
##誤りロジック(パターンB)
class c_SerchView(ListView):
template_name = 'report_app/serch.html'
model = ReportModel
context_object_name = 'object_list' #デフォルトがobject_listなので名前を変えない場合は本来これは記載しなくてもいい
def get_queryset(self):
date_min = self.request.GET.get('date_min')
date_max = self.request.GET.get('date_max')
if date_min:
object_list = ReportModel.objects.filter(date_start__gte=date_min).order_by('date_start')
elif date_max:
object_list = ReportModel.objects.filter(date_start__lte=date_max).order_by('date_start')
elif date_min and date_max:
object_list = ReportModel.objects.filter(date_start__range=[date_min, date_max]).order_by('date_start')
else:
object_list = ReportModel.objects.filter(date_start__isnull=True)
return object_list
i_serch = c_SerchView.as_view()
この場合は、
検索項目の両方(20200824~20200831)に日付を入れて範囲検索した場合に、20200824以降の全てが検出される(つまり、to側の範囲が効いてない)
##解決ロジック
class c_SerchView(ListView):
template_name = 'report_app/serch.html'
model = ReportModel
context_object_name = 'object_list' #デフォルトがobject_listなので名前を変えない場合は本来これは記載しなくてもいい
def get_queryset(self):
date_min = self.request.GET.get('date_min')
date_max = self.request.GET.get('date_max')
if date_min and date_max:
object_list = ReportModel.objects.filter(date_start__range=[date_min, date_max]).order_by('date_start')
elif date_min:
object_list = ReportModel.objects.filter(date_start__gte=date_min).order_by('date_start')
elif date_max:
object_list = ReportModel.objects.filter(date_start__lte=date_max).order_by('date_start')
else:
object_list = ReportModel.objects.filter(date_start__isnull=True)
return object_list
i_serch = c_SerchView.as_view()
####これで、なんとか片側検索、両方検索ができるようになりました。
今回はdateFieldなのでこれでOK。
でもこれだとdatetimeFieldの場合は、両側同一日付の検索ができず1件も検出されないという状態になる。。。その解決策は、次№05に記載。
##勉強メモ「範囲検索」
基本方針は django_filterを使って、gte, lteを指定するだけ。
■filterメソッドの使い方
gte ・・・以上
gt ・・・より大きい(その数値は含まない)
lte ・・・以下
lt ・・・未満(その数値は含まない)
range ・・・の間
例)
#指定日以上
object_list = ReportModel.objects.filter(date_start__gte=date_min).order_by('date_start')
#2つの日付間のものを全て(f同一日付検索も可能)
object_list = ReportModel.objects.filter(date_start__range=[date_min, date_max]).order_by('date_start')
#範囲関係なく全て
object_list = ReportModel.objects.all().order_by('date_start').order_by('date_start')