質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
ORM

ORM(オブジェクト関係マッピング)はオブジェクト指向のシステムとリレーショナルデータベースの間でマッピングを行う技術です。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

SQLAlchemy

SQLAlchemyとはPython 用のORMライブラリです。MIT Licenceのオープンソースとして提供されています。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

2回答

2592閲覧

SQLAlchemy のデフォルト値にインスタンス変数を利用したい

退会済みユーザー

退会済みユーザー

総合スコア0

ORM

ORM(オブジェクト関係マッピング)はオブジェクト指向のシステムとリレーショナルデータベースの間でマッピングを行う技術です。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

SQLAlchemy

SQLAlchemyとはPython 用のORMライブラリです。MIT Licenceのオープンソースとして提供されています。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2019/12/15 12:24

編集2019/12/16 12:39

前提・実現したいこと

SQLAlcemyを利用したDBのinsert処理でDefault値にインスタンス変数を利用して設定したい

該当のソースコード

python

1from datetime import datetime 2from sqlalchemy import create_engine 3from sqlalchemy.orm import sessionmaker, scoped_session 4from sqlalchemy.ext.declarative import declarative_base 5from sqlalchemy import Column, Integer, String, Date, DateTime 6 7DB_FILE = "localdb.sqlite3" 8ENCODING = "utf-8" 9DB_ECHO = True 10 11# mysql 12# DATABASE = f"mysql://{USERNAME}:{PASSWORD}@{HOST}/{DBNAME}?charset={CHARSET}" 13 14# sqlite 15DATABASE = f"sqlite:///{DB_FILE}" 16 17ENGINE = create_engine( 18 DATABASE, 19 encoding=ENCODING, 20 echo=DB_ECHO 21) 22 23# session作成 24session = scoped_session( 25 sessionmaker( 26 autocommit=False, 27 autoflush=False, 28 bind=ENGINE 29 ) 30) 31 32DbBase = declarative_base() 33 34 35class Product(DbBase): 36 """ 37 商品モデル 38 """ 39 __tablename__ = 'products' 40 41 # 操作ユーザ 42 operation_user = "system" 43 44 # DBカラム定義 ############################################ 45 # key id 46 id = Column(Integer, primary_key=True) 47 # 製品ID 48 product_id = Column(String(50), nullable=False) 49 # タイトル 50 title = Column(String(200), nullable=False) 51 # 販売日 52 sales_date = Column(DateTime, nullable=False) 53 54 # 作成日 55 create_date = Column(DateTime, nullable=False, default=datetime.now) 56 # 作成者 57 create_user = Column(String(50), nullable=False, default=operation_user) 58 # 更新日 59 update_date = Column(DateTime, nullable=False, default=datetime.now, onupdate=datetime.now) 60 # 更新者 61 update_user = Column(String(50), nullable=False, default="operation_user", onupdate="operation_user") 62 63 64if __name__ == "__main__": 65 DbBase.metadata.drop_all(bind=ENGINE) 66 DbBase.metadata.create_all(bind=ENGINE) 67 68 items = list() 69 for i in range(0, 100): 70 product = Product() 71 product.product_id = "A" + f"{i:03}" 72 product.title = "ああああ" + f"{i:03}" 73 product.sales_date = datetime.now() 74 75 # 操作ユーザを指定したい 76 product.operation_user = "test" 77 items.append(product) 78 79 session.add_all(items) 80 session.commit()

発生している問題・エラーメッセージ・試したこと

① インスタンス変数をそのまま利用(上記ソース)

operation_user = "system" ・・ create_user = Column(String(50), nullable=False, default=operation_user)

とすると、初期値のsystemとなります

② initで初期化

operation_user = "system" ・・・ def __init__(self, user): self.operation_user = user ・・・ product = Product("test")

結果は変わりませんでした

ここまでは、Columnの定義時点の値が使われるんだろうなぁ、ぐらいで予想はしていたのですが。。。

③ 関数を介して参照

operation_user = "system" def get_operation_user(self): return self.operation_user ・・・ create_user = Column(String(50), nullable=False, default=get_operation_user)

下記エラーとなってしまいます

sqlalchemy.exc.StatementError: (builtins.AttributeError) 'SQLiteExecutionContext' object has no attribute 'operation_user' [SQL: INSERT INTO products (product_id, title, sales_date, create_date, create_user, update_date, update_user) VALUES (?, ?, ?, ?, ?, ?, ?)] [parameters: [{'product_id': 'A000', 'sales_date': datetime.datetime(2019, 12, 15, 21, 4, 6, 432239), 'title': 'ああああ000'}]]

④ システムカラムを作成して参照

operation_user = Column(String(20), system=True) def get_operation_user(context): return context.get_current_parameters()['operation_user'] ・・・ create_user = Column(String(50), nullable=False, default=get_operation_user)

これでいけそうかと思ったのですが、エラーが出てしまいます。

sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) table products has no column named operation_user [SQL: INSERT INTO products (operation_user, product_id, title, sales_date, create_date, create_user, update_date, update_user) VALUES (?, ?, ?, ?, ?, ?, ?, ?)] [parameters: ('test', 'A000', 'ああああ000', '2019-12-15 21:10:56.192422', '2019-12-15 21:10:56.202107', 'test', '2019-12-15 21:10:56.202107', 'operation_user')] (Background on this error at: http://sqlalche.me/e/e3q8)

Columnsystem=Trueとしたことで、DDLには含まれなくしました。(テーブル定義を確認したところ作成はされていませんでした)
しかし、insertのSQLを確認すると、operation_userカラムへinsertしようとしてしまっています。

いろいろ試してみたのですが、どれもうまくいかなかったです。
よろしくお願いいたします。

補足情報(FW/ツールのバージョンなど)

sqlalchemy 1.3.11

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

default という単語を見つけたから、これを使わなきゃと悩んでましたが、
この場合は、単純に初期化関数用意すればいいだけでした(create_init, update_init)

from datetime import datetime from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker, scoped_session, reconstructor from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import Column, Integer, String, Date, DateTime DB_FILE = "localdb.sqlite3" ENCODING = "utf-8" DB_ECHO = True # mysql # DATABASE = f"mysql://{USERNAME}:{PASSWORD}@{HOST}/{DBNAME}?charset={CHARSET}" # sqlite DATABASE = f"sqlite:///{DB_FILE}" ENGINE = create_engine( DATABASE, encoding=ENCODING, echo=DB_ECHO ) # session作成 session = scoped_session( sessionmaker( autocommit=False, autoflush=False, bind=ENGINE ) ) DbBase = declarative_base() class Product(DbBase): """ 商品モデル """ __tablename__ = 'products' # insert 初期化 def create_init(self, operation_user): self.create_user = operation_user self.update_user = operation_user # update 初期化 def update_init(self, operation_user): self.update_user = operation_user # DBカラム定義 ############################################ # key id id = Column(Integer, primary_key=True) # 製品ID product_id = Column(String(50), nullable=False) # タイトル title = Column(String(200), nullable=False) # 販売日 sales_date = Column(DateTime, nullable=False) # 作成日 create_date = Column(DateTime, nullable=False, default=datetime.now) # 作成者 create_user = Column(String(50), nullable=False) # 更新日 update_date = Column(DateTime, nullable=False, default=datetime.now, onupdate=datetime.now) # 更新者 update_user = Column(String(50), nullable=False) if __name__ == "__main__": DbBase.metadata.drop_all(bind=ENGINE) DbBase.metadata.create_all(bind=ENGINE) items = list() for i in range(0, 100): product = Product() product.create_init('create user') product.product_id = "A" + f"{i:03}" product.title = "ああああ" + f"{i:03}" product.sales_date = datetime.now() items.append(product) session.add_all(items) session.commit() product = session.query(Product).filter(Product.id == 1).first() product.update_init('update user') product.title = 'update Title' session.commit()

投稿2019/12/29 16:59

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

get_operation_userの戻り値はカラムに入れる値である必要があるのでは?

def get_operation_user(context): return 'operation_user' class Product(DbBase): ・・・ create_user = Column(String(50), nullable=False,default=get_operation_user)

投稿2019/12/26 21:14

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問