SQLAlchemyとAlembic を導入した際、エラーが出ることが多かったので、紹介します。
SQLAlchemyではコマンドでの操作やAlter Tableなどは行えませんが、
Alembicではコマンドを用いたスキーマの操作やAlter Tableを行うことができ、便利です。
目次
- sqlalchemy.exc.ArgumentError
- sqlalchemy.exc.InvalidRequestError
- AttributeError
- ImportError
- ERROR [alembic.util.messaging]
SQLAlchemy とは
PythonのORM(Object Relational Mapper)です。
alembic とは
SQLAlchemy を使用した データベースmigrationライブラリです。
1. sqlalchemy.exc.ArgumentError
1-1
sqlalchemy.exc.ArgumentError: Mapper mapped class User->users could not assemble any primary key columns for mapped table ‘users’
このエラーはカンマをつけていたり、
1 2 3 4 5 6 |
class UserDataModel(Base): __tablename__ = 'users' id = Column(Integer(), primary_key=True, autoincrement=True), name = Column(String(100), nullable=False), password = Column(String(255), nullable=False) |
Column()の中にカラム名を書いていたりすることが原因で起きます。
1 2 3 4 5 6 |
class UserDataModel(Base): __tablename__ = 'users' Column('id', Integer(), primary_key=True, autoincrement=True) Column('name', String(100), nullable=False) Column('password', String(255), nullable=False) |
解決法としてはカンマを付けず「id = Column()」のような形で定義しなければいけないです。
1 2 3 4 5 6 |
class UserDataModel(Base): __tablename__ = 'users' id = Column(Integer(), primary_key=True, autoincrement=True) name = Column(String(100), nullable=False) password = Column(String(255), nullable=False) |
1-2
sqlalchemy.exc.ArgumentError: Error creating backref ‘users’ on relationship ‘UserDataModel.reports’: property of that name exists on mapper ‘mapped class ReportDataModel->reports’
このエラーはrelationshipのbackrefで別のモデルで定義されたrelationshipの変数名を定義した際に起きます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
class UserDataModel(Base): __tablename__ = 'users' id = Column(Integer(), primary_key=True, autoincrement=True) name = Column(String(100), nullable=False) # ここのrelationshipのbackrefでusersは定義できない reports = relationship("ReportDataModel", backref="users") class ReportDataModel(Base): __tablename__ = 'reports' id = Column(Integer, primary_key=True, autoincrement=True) user_id = Column(Integer, ForeignKey("users.id"), nullable=False) ## ここでusersを宣言すると他のモデルで定義されるrelationshipのbackrefにusers(同名)は使えなくなる。 users = relationship("ReportDetailDataModel") report_detail = relationship("ReportDetailDataModel", backref="reports") |
解決法としては別名で定義する、もしくはbackrefを用いていないrelationshipを削除する必要があります。1対多の1側でbackrefを用いている際は、多側ではrelationshipは不要です。
https://docs.sqlalchemy.org/en/14/orm/backref.html
2. sqlalchemy.exc.InvalidRequestError
sqlalchemy.exc.InvalidRequestError: When initializing mapper mapped class UserDataModel->users, expression ‘ReportDataModel’ failed to locate a name (‘ReportDataModel’). If this is a class name, consider adding this relationship() to the <class ‘db.models.user.UserDataModel’> class after both dependent classes have been defined.
このエラーはrelationshipの第一引数に文字列でクラスを指定する必要があるが、 import しないことで起こります。
解決法としては、relationship の第一引数で文字列として指定したクラスを import する必要があります。
1 2 |
from report import ReportDataModel reports = relationship("ReportDataModel", backref="user_data_model") |
3. AttributeError
AttributeError: ‘NoneType’ object has no attribute ‘fullname’
このエラーは SQLAlchemy のモデルが Base を継承していないと起こります。
1 2 3 4 5 6 |
from sqlalchemy import Column, String, Integer class UserModel: __tablename__ = 'users' id = Column(Integer, primary_key=True) name = Column(String(100), nullable=False) |
解決法としてはBaseを継承してあげましょう。
1 2 3 4 5 6 7 |
from sqlalchemy import Column, String, Integer from setting import Base class UserModel(Base): __tablename__ = 'users' id = Column(Integer, primary_key=True) name = Column(String(100), nullable=False) |
4. ImportError
ImportError: cannot import name ‘UserDataModel’ from partially initialized module ‘db.models.user’ (most likely due to a circular import)
このエラーは循環参照(呼び出し先で呼び出し元が呼び出されている)をしている時に起きます。
解決法としては、TYPE_CHECKINGする必要があります。
TYPE_CHECKINGについては、こちらに詳しく書かれています。
5. ERROR [alembic.util.messaging]
ERROR [alembic.util.messaging] Can’t locate revision identified by ‘90333886164c’
INFO [sqlalchemy.engine.Engine] [generated in 0.00011s] {}
FAILED: Can’t locate revision identified by ‘90333886164c’
このエラーは Alembic で upgrade して、テーブルを作成した後に Alembicのdowngrade でテーブルを消さずに直接 DB からテーブルを削除すると、Alembic が作成したマイグレーションを管理するalembic_version テーブルに upgrade した際のバージョンのレコードが残ることで起きます。
解決法としては、alembic_vesion テーブルのレコードを削除するか、alembic_version テーブル自体を削除する必要があります。
終わりに
SQLAlchemyのモデル定義方法が2通りあったり、マイグレーションならではのエラーなどあったりで、解決に時間を取られたので、SQLAlchemyとAlembicを導入する際はご参考ください。
参考
https://stackoverflow.com/questions/9088957/sqlalchemy-cannot-find-a-class-name
https://qiita.com/kitarikes/items/9c5d6cbc557ed62bb512
https://zenn.dev/ganariya/articles/python-lazy-annotation
https://stackoverflow.com/questions/27399602/sqlalchemy-exc-argumenterror-error-creating-backref