【发布时间】:2021-11-10 20:00:32
【问题描述】:
有谁知道如何使用 sqlalchemy 或专门使用 flask_sqlalchemy 设置 MySQL 表列来保存 utf8mb4 字符集?此处描述了连接https://docs.sqlalchemy.org/en/14/dialects/mysql.html,但我不知道如何更改表属性以使烧瓶迁移正确创建表。
我看到的问题是某些电子邮件内容(我正在尝试保存)可能有 4 字节 Unicode,并且无法插入到表中并出现此错误
(pymysql.err.DataError) (1366, "Incorrect string value: '\\xEF\\xBB\\xBF\\x0D\\x0A>...' for column `test`.`email`.`content_text` at row 1")
对应于email中的这个字符串sn-p
>=20
> =EF=BB=BF
>=20
并且可以像这样被复制为测试,如果发送到数据库将重新创建错误:
print(f'bad chr >> {chr(65279)} <<')
要使表能够存储此字符,您可以使用 alter 这不是很好,因为它的 post 声明。
ALTER TABLE email
DEFAULT CHARACTER SET utf8mb4,
MODIFY content_text MEDIUMTEXT
CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL
所以我想在表的声明中这样做,但无法弄清楚这是如何使用烧瓶 orm 接口完成的。
这是一个重新创建问题的测试脚本(在测试数据库存在并且测试用户已授予所有权限以创建表之后)
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
from sqlalchemy.dialects.mysql import MEDIUMTEXT
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://test:test@localhost/test?charset=utf8mb4'
db = SQLAlchemy(app)
Migrate(app,db)
class Email(db.Model):
__tablename__ = 'email'
id = db.Column(db.Integer, primary_key=True)
content_text = db.Column(MEDIUMTEXT)
@app.cli.command("test_schema")
def test_schema():
for i, row in enumerate(db.session.execute('desc email'), 1):
[print(f'row {i} {row._fields[y]:<10s} : {str(col):<20s}') for y,col in enumerate(row)]
print()
@app.cli.command("test_problem")
def test_problem():
new_mail = Email( content_text = f'bad chr >> {chr(65279)} <<' )
db.session.add( new_mail )
db.session.commit()
@app.cli.command("drop")
def drop():
db.session.execute('drop table email')
多次调用它来创建架构,然后用我添加的命令行函数测试问题。
# creates the table provided test db is created and user has grant all set to that test db
FLASK_APP=test_schema.py flask db init
FLASK_APP=test_schema.py flask db migrate
FLASK_APP=test_schema.py flask db upgrade
# test the problem
FLASK_APP=test_schema.py flask test_problem
所以我希望能够在不更改数据库的情况下定义 content_text = db.Column(MEDIUMTEXT)。
这些是任何ALTER TABLE 之前的数据库对象:
> SHOW CREATE DATABASE test;
CREATE DATABASE 'test' /*!40100 DEFAULT CHARACTER SET latin1 */
> SHOW CREATE TABLE email;
CREATE TABLE 'email' (
'id' int(11) NOT NULL AUTO_INCREMENT,
'content_text' mediumtext DEFAULT NULL,
PRIMARY KEY ('id')
) ENGINE=InnoDB DEFAULT CHARSET=latin1
【问题讨论】:
-
所以如果我理解正确,您想知道如何在创建表后自动使用正确的字符集创建列,而不必执行
ALTER TABLE?使用 charset utf8mb4 创建数据库是否可以接受? -
您的意思是所有表都默认为 utf8mb4 ?更改数据库会将应用程序的特定责任推给数据库管理员,并且出于其他原因您可能不希望在所有表上都这样做。所以我个人认为解决方案应该在表的声明中。
-
我搜索了方言的 sqlalchemy 处理,我发现这个工作
content_text = db.Column(MEDIUMTEXT(unicode=True))不确定它是否有任何副作用。
标签: python mysql unicode sqlalchemy flask-sqlalchemy