Django:Unicode,MySQL和编码(latin1,koi8-r)

时间:2018-07-26 11:14:55

标签: python mysql django encoding character-encoding

Django 2.0版。 Python 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'编解码器无法对位置6228-6235中的字符进行编码:字符映射为。使用其他编码时,没有错误,但没有结果)。我试图在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>。没有结果。

似乎Django每次都会执行SET NAMES utf8

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

3 个答案:

答案 0 :(得分:1)

我认为您正在混淆网络字符编码和存储编码。在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")

答案 1 :(得分:0)

我解决了这个问题。

第一种方式

ALTER DATABASE dbname CHARACTER SET koi8r COLLATE koi8r_general_ci;
连接中的

use_unicode=True, charset="utf8"属性。 但是我不能只在测试PC上更改服务器上的活动数据库。

第二种方式

在我的虚拟环境中,我编辑了lib / python3.6 / site-packages / MySQLdb / connections.py:

Connection类中,我添加了:

self.force_koi8r = kwargs2.pop('force_koi8r', kwargs.get('force_koi8r', False))

及以下已修改的部分代码:

def set_character_set(self, charset):
    #if charset == "utf8mb4":
    #    py_charset = "utf8"
    #else:
    #    py_charset = charset

    # bugfix:
    if charset == "utf8mb4":
        py_charset = "utf8"
    elif charset == "latin1" and self.force_koi8r == True:
        py_charset = 'koi8-r'
    else:
        py_charset = charset

现在它可以与force_koi8r=True参数一起正常工作,但这不是一个好的解决方案。此解决方案仅适用于该项目

问题在编码标题中。 Python将这种编码称为'koi8-r'或'koi8_r'。但是MySQL知道它是“ koi8r”。如果我设置了charset = koi8-r-mysql给出了一个错误,如果我设置了charset = koi8r-Python给出了一个错误。 (未知编码)

第三种方式

如果有人知道如何在Python中添加编码别名(默认值:koi8-r,koi8_r,并且我需要添加koi8r),请告诉我

答案 2 :(得分:0)

我很确定您需要两步操作ALTER

您有CHARACTER SET latin1,但有非拉丁1字节。修复字符集时,您需要保留字节:

首先,假设您具有tbl.col的声明:

col VARCHAR(111) CHARACTER SET latin1 NOT NULL

要在不更改字节的情况下转换列:

ALTER TABLE tbl MODIFY COLUMN col VARBINARY(111) NOT NULL;
ALTER TABLE tbl MODIFY COLUMN col VARCHAR(111) CHARACTER SET koi8r NOT NULL;

注意:如果您以TEXT开头,请使用BLOB作为中间定义。 (请确保其他规格相同-VARCHAR,NOT NULL等)

-http://mysql.rjweb.org/doc.php/charcoll#fixes_for_various_cases

您将在该链接中看到,针对不同的情况有许多不同的修复程序。如果您已经应用了其他一些答案,则可能会使情况变得更糟!如果您需要进一步的帮助,请提供一个示例

SELECT col, HEX(col) FROM ... WHERE ...

也许能够推断出事物的立场。 ëÏÚÌÑÎËÏ òÏÍÁÎ éÏÓÉÆÏ×ÉÞþÅÐÒÑÇÏ×Á éÎÅÓÓÁ ÷ÉËÔÏÒÏ×ÎÁ看上去很乱;快速浏览一下,可能是应用了错误的转换。朝鲜语文字是什么?