Python SQLAlchemy Tech

Python SQLAlchemy Modelでテーブル・カラムの文字コードutf8mb4を設定する方法

SQLAlchemyはPythonからRDBMS(MySQL等)にアクセスするライブラリの一つで、柔軟で多機能なORM機能などが含まれています。

このページでは、文字列・テキストを日本語で格納するために、文字コードをutf8mb4などに変更する方法を、現役のエンジニアが解説しています。

  • データベース、テーブル単位でデフォルトの文字コードを設定する方法
  • カラム単位で文字コード・参照順位を設定する方法

 

結論

テーブルのデフォルト文字コードを指定する

class Base(object):
    __table_args__ = {
        "mysql_default_charset": "utf8mb4",
        "mysql_collate": "utf8mb4_general_ci",
    }

Base = declarative_base(cls=Base)
Base.query = session.query_property()

 

テーブルの各カラムごとに文字コード・照合順序を設定する

class TableModel(Base):
    #...
    column_name = Column(mysql.VARCHAR(40, collation='utf8mb4_general_ci'), nullable=False)
    #...
    comment = Column(mysql.TEXT(collation='utf8mb4_general_ci'), nullable=False)
    #...

 

実行環境

$ mysql --version
mysql Ver 15.1 Distrib 10.3.29-MariaDB, for debian-linux-gnu (x86_64) using readline 5.2

$ python --version
Python 3.9.2

$ pip freeze
PyMySQL==1.0.2
SQLAlchemy==1.4.5

 

(参考)データベースのデフォルト文字コード設定

開発指針にもよりますが、基本的にはデータベース単位でデフォルトの文字コード・参照順位を設定します。

テーブル、各カラムで文字コードが設定されていなければ、データベースに設定されたデフォルトの文字コードが反映されます。

デフォルト文字コードは、データベースの作成時のcreate文の
character set [文字コード]で行います。

MySQL []> CREATE DATABASE db_jpn CHARACTER SET utf8mb4;
Query OK, 1 row affected (0.001 sec)


MySQL [db_jpn]> show variables like 'character\_set\_%';
+--------------------------+---------+
| Variable_name            | Value   |
+--------------------------+---------+
| character_set_client     | binary  |
| character_set_connection | binary  |
| character_set_database   | utf8mb4 |
| character_set_filesystem | binary  |
| character_set_results    | binary  |
| character_set_server     | binary  |
| character_set_system     | utf8    |
+--------------------------+---------+
7 rows in set (0.002 sec)

 

テーブルのデフォルト文字コード設定

SQLAlchemyのモデル(Model)定義は、ORMを使用したりマイグレーションのときに参照されます。

まずは、文字コード(charset)を全く指定しない場合のマイグレーションを確認してみましょう。

特にカスタマイズせずにBaseクラスを取得します。

Base = declarative_base()
Base.query = session.query_property()

class User(Base):
    __tablename__ = 'users'
    id = Column(BigInteger, primary_key=True, autoincrement=True, nullable=False)
    name = Column(mysql.VARCHAR(100), nullable=False)
    affiliation = Column(mysql.VARCHAR(100), nullable=False)
    job_title = Column(mysql.VARCHAR(100), nullable=False)
    expertise = Column(mysql.VARCHAR(100), nullable=False)
    birthday = Column(mysql.DATETIME)
    comment = Column(mysql.TEXT(100), nullable=False)

マイグレーションを実行して作成されたテーブルを確認してみると…

MySQL []> show create table users;
+-------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table                                                                                                                                                                                                                                                                                                                                              |
+-------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| users | CREATE TABLE `users` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `name` varbinary(100) NOT NULL,
  `affiliation` varbinary(100) NOT NULL,
  `job_title` varbinary(100) NOT NULL,
  `expertise` varbinary(100) NOT NULL,
  `birthday` datetime DEFAULT NULL,
  `comment` tinyblob NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=binary |
+-------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.001 sec)

 

show create table ...コマンドで見てみると、DEFAULT CHARSET がデータベースのデフォルト値(今回はbinary)となっています。

モデル定義でテーブルのデフォルト文字コードを設定するには以下のようにします。今回、テーブルのデフォルト文字コードとしてutf8mb4を設定してみます。

モデル定義でデフォルト文字コードを設定するには、Baseクラスにパラメータをセットし、このBaseを継承して各モデルを作成します。

class Base(object):
    __table_args__ = {
        "mysql_default_charset": "utf8mb4",
        "mysql_collate": "utf8mb4_general_ci",
    }

Base = declarative_base(cls=Base)
Base.query = session.query_property()

class User(Base):
    __tablename__ = 'users'
    id = Column(BigInteger, primary_key=True, autoincrement=True, nullable=False)
    name = Column(mysql.VARCHAR(100), nullable=False)
    affiliation = Column(mysql.VARCHAR(100), nullable=False)
    job_title = Column(mysql.VARCHAR(100), nullable=False)
    expertise = Column(mysql.VARCHAR(100), nullable=False)
    birthday = Column(mysql.DATETIME)
    comment = Column(mysql.TEXT(100), nullable=False)
MySQL []> show create table users;
+-------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table                                                                                                                                                                                                                                                                                                                                   |
+-------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| users | CREATE TABLE `users` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `name` varchar(100) NOT NULL,
  `affiliation` varchar(100) NOT NULL,
  `job_title` varchar(100) NOT NULL,
  `expertise` varchar(100) NOT NULL,
  `birthday` datetime DEFAULT NULL,
  `comment` text NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 |
+-------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

 

DEFAULT CHARSET=utf8mb4となっているのを確認できました。

これで各カラムの文字コードも(特段の設定がなければ)utf8mb4となります。

 

カラムごとの文字コード設定

データベース単位、テーブル単位で設定されているデフォルトの文字コードではなく、カラムごとに文字コード・参照順位を設定したい場面もあるかと思います。

この場合は、カラムごとに文字コード・照合順序を設定することも可能です。

Base = declarative_base()
Base.query = session.query_property()

class User(Base):
    __tablename__ = 'users'
    id = Column(BigInteger, primary_key=True, autoincrement=True, nullable=False)
    name = Column(mysql.VARCHAR(100, collation='utf8mb4_general_ci'), nullable=False)
    affiliation = Column(mysql.VARCHAR(100, collation='utf8mb4_general_ci'), nullable=False)
    job_title = Column(mysql.VARCHAR(100, collation='utf8mb4_general_ci'), nullable=False)
    expertise = Column(mysql.VARCHAR(100, collation='utf8mb4_general_ci'), nullable=False)
    birthday = Column(mysql.DATETIME)
    comment = Column(mysql.TEXT(100, collation='utf8mb4_general_ci'), nullable=False)

 

今回参考にしたページ・資料

Composing Mapped Hierarchies with Mixins — SQLAlchemy 1.4 Documentation

 

  • この記事を書いた人

次世代ペンギン

長いのでペンギンとお呼びください。システム開発・プログラミングのお仕事をしています。甘味とコーヒーは生命線。多くの人に役立つ情報のシェアが目標です。

人気の記事

1

会社員でプログラマーとして働いている人、インフラやネットワークのエンジニアとして働いている人の中には、フリーランスのプログラマーとして独立、もしくは転向したい人もいるので ...

2

キャリアアップのため、または高収入を目指して、しっかりプログラミングを学びたいという人が増えてきましたね。 この記事では現役のエンジニアである私が、実際に仕事で稼げるよう ...

3

フリーランスのプログラマーにとって収入の向上に最も直結するのはスキルです。 必要なスキル、スキルの獲得方法が気になる人も多いでしょう。 また、これからフリーランスを目指す ...

4

Vuetifyの v-progress-circular コンポーネントは、数値データや処理状況を環状(円状)のデザインで教えてくれるUIデザインです。 ローディングのス ...

5

Vuexのstore(ストア)を使うと、各コンポーネント間で個別にデータのやり取りすることなく、データを一元的に管理できます。Vueでは欠かせない機能といえるでしょう。 ...

-Python, SQLAlchemy, Tech
-, , ,

© 2021 ペンギンのーと