首页 > 解决方案 > Django:Unicode、MySQL 和编码(latin1、koi8-r)

问题描述

Django 2.0 版。蟒蛇 3

我的数据库字符集和排序规则:

mysql> SELECT @@character_set_database, @@collation_database;
+--------------------------+----------------------+
| @@character_set_database | @@collation_database |
+--------------------------+----------------------+
| latin1                   | latin1_swedish_ci    |
+--------------------------+----------------------+

老开发者使用 Perl 以KOI8-R编码插入数据:(

为了从数据库中获取正确的值,我使用了丑陋的构造str(username).encode('latin1').decode('koi8-r')。什么?我需要在我的所有项目中使用它来将数据发送到输出?或者编写函数来编码上下文字典,但我还需要额外的编码/解码所有数据。它将影响可用性和生产力

没有这个,我会得到类似的东西ëÏÚÌÑÎËÏ òÏÍÁÎ éÏÓÉÆÏ×ÉÞ

如何在 Django 中全局设置编码以防止在每个地方进行编码/解码操作?我改变了不同的编码方式,没有任何反应。

在 settings.py 我尝试将 DEFAULT_CHARSET 设置为不同的编码(如果我将 default_charset 设置为 KOI8-R 我得到一个错误:UnicodeEncodeError: 'charmap' codec can't encode characters in position 6228-6235: character maps to 。使用其他编码没有错误但没有结果)。我试图在 settings.py 的数据库部分设置不同的字符集和排序规则值。

'OPTIONS': {
    'charset': 'latin1',
    'init_command': "SET sql_mode='STRICT_TRANS_TABLES', character_set_client=latin1, character_set_results=latin1, character_set_connection=latin1, collation_connection=latin1_swedish_ci",
}

我在 index.html 模板中添加<meta http-equiv="Content-type" content="text/html; charset=koi8-r (or other)" />了标签。<head>没有结果。

似乎DjangoSET NAMES utf8每次都执行

为什么在 Perl 中我可以发送带有 charset=koi8-r 的标头,并且我使用 CGI 从浏览器中的这个表中获取正常值?为什么使用 Django 或 Flask 在 Python 中没有类似的结果?Perl 中的简单示例

标签: pythonmysqldjangoencodingcharacter-encoding

解决方案


我认为您将网络字符编码与存储编码混淆了。在 MySQL 中,字符串数据的生命周期大致是这样的:

disk_storage --decode--> MySQL --encode--> network --decode--> database_driver

当从磁盘读取字符串数据时,MySQL 使用该character_set_database值对其进行解码。当客户端通过网络连接时,客户端会指定连接的编码。对于 Python,这通常是 UTF-8。MySQL 然后将数据编码为连接编码。然后,Python Mysql 驱动程序使用它设置的连接编码解码它接收到的数据。

如果这些解码或编码中的任何一个使用了错误的值,则会创建错误的数据。如果character_set_database设置不正确,那么 MySQL 将在对网络连接上的坏数据进行编码之前错误地解码数据。

解决方案应该像更改character_set_database为正确的值而不更改实际数据一样简单。

这可以通过以下方式实现:

ALTER DATABASE dbname CHARACTER SET koi8r COLLATE koi8r_general_ci;

(不要运行ALTER TABLE tbl_name CONVERT..- 这实际上会重新编码您的数据。由于旧的 character_set 值错误,您的数据将在编码为新编码之前被错误地解码)

将所有 Python 设置更改回默认值(UTF-8 等)。不要设置DEFAULT_CHARSET或任何其他值。

确保 MySQL 驱动程序正确连接并使用 UTF-8 作为网络连接use_unicode=Truecharset="utf8"

例如

>>> db = MySQLdb.connect(host="localhost", user='root', passwd='passwd', db='sandbox', use_unicode=True, charset="utf8")

推荐阅读