Django:MySQLのdatetime型を日付一致で取り出す方法(QuerySetで)

Django:MySQLのdatetime型を日付一致で取り出す方法(QuerySetで)

これも短い記事になりそうな気がしますが、備忘録ですのであしからず。

具体例:楽天市場のTrackingデータ収集

RMSの中をスクレイピングしてこんな姿のCSVファイルを作成しました。

このデータをDBに格納しようとした時、重複防止の処理をどう書くかが1つの課題となります。

  1. ファイルを読込み、for inループで1レコードずつ存在確認を行い、存在したらスキップする
  2. ファイルを読込み、先頭の時間から日付だけ抽出。DBに日付で検索を行い同日のデータが存在する場合は同ファイルのレコードすべてをスキップする。

【工程1】の場合は何らかの理由で取り込めなかった値に対して再トライすることができます。
【工程2】の場合は重複データの確認回数が大幅に減るため(工程1と比べ)動作が格段に速くなります。

まぁ、運用してしまえば『取込みの終わったファイルは削除する』などのルールで【工程1】であっても毎回時間のかかる取込みが発生することはないと思いますが、コード記載中の動作テストでは「毎回処理に時間がかかりやがる」と、まぁイライラするわけです。
で「同日の値が1件でもあったら処理止めちゃえばいいじゃん」と思い実装しようとしたのですが、「QuerySetでdatime型のdate抽出ってどうやったっけ?」と。

QuerySetでdatime型のカラムをdateで抽出する方法

filterメソッドにて【 フィールド名__date = date 】で抽出

先程の事例にてコードを見てみます。

■MySQLテーブル構造 ※Models.py 抜粋

class Trackings(models.Model):
    """トラッキング"""
    TYPE_CHOICES = ((1, '総合'),(2, 'PC'),(3, 'SP'), (4, 'アプリ'),)
    ACTION_CHOICES = ((1, '閲覧'),(2, 'かご入れ'), (3, '決済'),(4, '共同購入'),(5, '入札'),(6, 'プレゼント応募'),(7, '問合せ'),(8, '資料請求'),)
    observation_datetime = models.DateTimeField(verbose_name='観測日時')
    client = models.ForeignKey(Clients, verbose_name='クライアント', on_delete=models.PROTECT)
    shop = models.ForeignKey(Shops, verbose_name='店舗', on_delete=models.PROTECT)
    types = models.IntegerField(verbose_name='販売メディア', choices=TYPE_CHOICES)
    action_type = models.IntegerField(verbose_name='行動タイプ', choices=ACTION_CHOICES)
    detail_action = models.CharField(verbose_name='詳細行動', max_length=20, blank=False, null=True)
    precipitation = models.CharField(verbose_name='検索ワード', max_length=100, blank=False, null=True)
    daylight_hours = models.CharField(verbose_name='商品ページ名', max_length=200, blank=False, null=True)
    humidity = models.CharField(verbose_name='商品ページ', max_length=255, blank=False, null=True)
    user_code = models.CharField(verbose_name='顧客コード', max_length=100, blank=False, null=True)
    created_at = models.DateTimeField(verbose_name='作成日時', auto_now_add=True)
    updated_at = models.DateTimeField(verbose_name='更新日時', auto_now=True)
    class Meta:
        verbose_name_plural = 'Trackings'
        def __str__(self):
            return self.observation_datetime

■Views.py ※QuerySet部のみ抽出

# 存在チェック用QuerySet
date = "2021-04-15"
check = Trackings.objects.filter(observation_datetime__date=date) \
  .filter(shop_id__exact=shop_id) \
  .filter(client_id__exact=client_id)\
  .filter(types__exact=2).first()

他にやろうとすればレンジを組んで取得したい日から翌日までの間で検索かけるとか。
まぁ【__date】を付けてイコールで結べば良いだけなので、range検索する方法は馬鹿げてますけどね。

まとめ

一日の始まり時間を調整したいなどの理由がない限り、【__range】よりも【__date】を使うことになると思います。

\ 最新情報をチェック /

コメントを残す

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください