LoginSignup
4
3

More than 1 year has passed since last update.

[SQLAlchemy] 圧倒的神速理解!!!MySQLにおいてcreated_at, updated_atカラムを作成する方法!!!

Posted at

この記事を読んでできること

レコード生成時刻(created_at)とレコード更新時刻(updated_at)をSQLAlchemyを使用して作成できる

記述しないこと

  • SQLAlchemyとは
  • 基本的なモデルの記述方法

使用技術

  • Python==3.10.4
  • fastapi==0.78.0
  • mysqlclient==2.1.0
  • pydantic==1.9.1
  • SQLAlchemy==1.4.36
  • SQLAlchemy-Utils==0.38.2
  • uvicorn==0.17.6

今回は DBにMySQLを使用します!

まずはコード例

models/customer.py
from sqlalchemy import DateTime, BigInteger, Column, String, text
from sqlalchemy.sql import func

# Baseクラス作成用にインポート
from sqlalchemy.ext.declarative import declarative_base

# mysqlのutf8は3バイト文字に制限されている為、4バイト文字も処理するutf8mb4をデフォルトで使用する。
class Base(object):
    __table_args__ = {"mysql_default_charset": "utf8mb4"}

# Baseクラスを作成
Base = declarative_base(cls=Base)

class Customer(Base):
    __tablename__ = "customer"
    id = Column(BigInteger, primary_key=True, nullable=False)
    last_name = Column(String(20), nullable=False)
    first_name = Column(String(20), nullable=False)
    email = Column(String(50), nullable=False)
    created_at = Column(
        DateTime(timezone=True), nullable=False, server_default=func.now()
    )
    updated_at = Column(
        DateTime(timezone=True),
        nullable=False,
        server_default=text("CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP"),
    )

migrationすると以下のような感じでテーブルが作成される
スクリーンショット 2022-11-29 11.09.29.png (27.8 kB)

created_at

timezoneを指定する

  • Pythonの表中ライブラリdatetimeを使用すれば以下のように日本時間のtimezoneを表示することが可能
    • ちなみにdatetimeで生成されるオブジェクトにはという概念がある
      • aware(timezoneが有る)
      • naive(timezoneが無い)
datetime.py
from datetime import datetime, timedelta, timezone
    from dateutil import tz
    from zoneinfo import ZoneInfo
    
    # パターン1
    now = datetime.now(ZoneInfo("Asia/Tokyo"))
    print(now)
    # 2022-10-27 13:51:55.293383+09:00
	
    # パターン2
    JST = tz.gettz("Asia/Tokyo")
    dt = datetime.now(JST)
    print(dt)
    # 2022-10-27 13:51:55.293613+09:00
    
    # パターン3
    JST = timezone(timedelta(hours=+9), "JST")
    time = datetime.now(JST)
    print(time)
    # 2022-10-27 13:51:55.293648+09:00
  • パターン3はUTC(協定世界時)とJST(日本時間)の誤差が9時間と知っている前提がないと理解できない(読む人の背景知識に理解が左右される)
  • つまり、コメントにて説明を追加することが必須となり、コメント前提のコードってどうなの?となるので暗黙知を許容するコードは書きたくないというのが筆者の考えである

なお。。。

SQLAlchemyでは上記をモデル定義に記述しても正常な挙動が確認できなかった
なので、timezone=Trueで指定
SQLAlchemy Datatypes

今の時刻を生成する

以下の公式ドキュメントより参照
SQLAlchemy serverdefault=func.now()

updated_at

これを知るのに調査の時間がすごくかかったよ。。。。。

この実装を通しての所感

  • SQLAlchemy、やれることがたくさんあるけど複雑すぎる
  • timezone一つにしても奥が深い
  • やっぱり黙って公式ドキュメント参照!
  • この実装はなぜいいのか、ダメなのかを意識する

参考

今回は特に重要

4
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3