如何在SQLAlchemy中全局设置MySQL表的字符集与校对规则,无需逐表配置__table_args__
全局配置SQLAlchemy MySQL表的字符集与校对规则
我完全懂你这种重复写__table_args__的烦躁——每次定义模型都要加一遍确实太啰嗦了。其实SQLAlchemy有两种简洁的全局配置方式,不用再逐个表手动指定这些参数:
方法一:自定义基类继承(最推荐)
创建一个带全局表参数的自定义Base基类,所有模型都继承这个基类,自动复用字符集和校对规则配置:
from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import Column, Integer, String, Text, ForeignKeyConstraint from sqlalchemy.orm import relationship # 初始化自定义基类,设置全局MySQL表参数 Base = declarative_base() Base.__table_args__ = { 'mysql_default_charset': 'utf8', 'mysql_collate': 'utf8_bin' } # 后续模型直接继承这个Base即可 class Blob(Base): __tablename__ = 'stash_blob' id = Column(String(40), primary_key=True) matches = relationship('Match', back_populates='blob') # 这里无需额外定义__table_args__,自动继承基类的字符集配置 class Match(Base): __tablename__ = 'stash_match' id = Column(Integer, primary_key=True, autoincrement=True) blob_id = Column(String(40)) text = Column(Text, nullable=False) regex = Column(Text, nullable=False) blob = relationship('Blob', back_populates='matches') # 如果有额外的表参数(比如外键约束),直接定义即可,会和基类的配置自动合并 __table_args__ = ( ForeignKeyConstraint([blob_id], [Blob.id], onupdate='CASCADE', ondelete='CASCADE'), )
原理说明
基类的__table_args__会被子类自动继承,如果子类自己也定义了__table_args__,SQLAlchemy会智能合并字典类型的参数(比如基类的字符集配置和子类的外键约束不会冲突)。
方法二:事件监听(灵活适配场景)
如果不想修改基类的继承逻辑,可以通过SQLAlchemy的事件监听机制,在表创建前自动注入字符集参数:
from sqlalchemy import event from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import Column, Integer, String, Text, ForeignKeyConstraint from sqlalchemy.orm import relationship Base = declarative_base() # 监听metadata的before_create事件,全局修改表参数 @event.listens_for(Base.metadata, "before_create") def apply_global_charset_collation(target, connection, **kwargs): # 遍历所有待创建的表,自动添加字符集配置 for table in target.tables.values(): # 使用setdefault避免覆盖已有的表参数 table.kwargs.setdefault('mysql_default_charset', 'utf8') table.kwargs.setdefault('mysql_collate', 'utf8_bin') # 模型定义无需额外配置 class Blob(Base): __tablename__ = 'stash_blob' id = Column(String(40), primary_key=True) matches = relationship('Match', back_populates='blob') class Match(Base): __tablename__ = 'stash_match' id = Column(Integer, primary_key=True, autoincrement=True) blob_id = Column(String(40)) text = Column(Text, nullable=False) regex = Column(Text, nullable=False) blob = relationship('Blob', back_populates='matches') __table_args__ = ( ForeignKeyConstraint([blob_id], [Blob.id], onupdate='CASCADE', ondelete='CASCADE'), )
补充:为什么之前的配置无效?
你之前尝试的URLcharset参数和create_engine的encoding参数,作用是设置客户端与服务器之间的连接编码,以及SQLAlchemy内部处理字符串的编码,并不会影响MySQL表本身的默认字符集——表的字符集是在CREATE TABLE语句中定义的,必须通过表级参数来指定。
内容的提问来源于stack exchange,提问作者Shuzheng
相关产品推荐
相关产品推荐

