【Django】№04：dateField日付範囲検索の方法


##経緯
日付範囲検索する場合に、From～Toの両方に検索日付を入力した場合は問題なかったが、どちらか片方だけを入力した場合にエラーが起きるという問題が発生。
そもそも、範囲検索のロジック記述方法がよくわかっていなかったのが原因。

（以下ロジックの補足）
　・date_min･･･検索項目From側
　・date_max･･･検索項目To側
　・date_start･･･データベースdatetimeField
&emsp;

##誤りロジック（パターンＡ）
```ruby:report_app/views.py

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　の場合･･･エラーは出ないが１件も検出されない
◎ 2020/08/01～2020/08/31の場合･･･正常に検出される
×　2020/08/01～2020/08/01の場合･･･１件も検出されない
&emsp;
&emsp;


##誤りロジック（パターンＢ）

```ruby:report_app/views.py
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側の範囲が効いてない）
&emsp;
&emsp;


##解決ロジック

```ruby:report_app/views.py
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()
```
&emsp;
####これで、なんとか片側検索、両方検索ができるようになりました。
今回はdateFieldなのでこれでＯＫ。
でもこれだとdatetimeFieldの場合は、両側同一日付の検索ができず１件も検出されないという状態になる。。。その解決策は、次№05に記載。
&emsp;
&emsp;

##勉強メモ「範囲検索」
基本方針は django_filterを使って、gte, lteを指定するだけ。

■filterメソッドの使い方
　gte ・・・以上
　gt　・・・より大きい（その数値は含まない）
　lte ・・・以下
　lt　・・・未満（その数値は含まない）
　range　・・・の間

例）

```ruby:report_app/views.py

#指定日以上
object_list = ReportModel.objects.filter(date_start__gte=date_min).order_by('date_start')

#２つの日付間のものを全て（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')
```