django:unicode、mysql和编码(拉丁文1、koi8-r)

g9icjywg  于 2021-06-20  发布在  Mysql
关注(0)|答案(3)|浏览(563)

django 2.0版。Python3
我的数据库字符集和排序规则:

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中,我尝试将默认\u字符集设置为不同的编码(如果我将默认\u字符集设置为koi8-r,则会出现错误:unicodeencodeerror:“charmap”编解码器无法对6228-6235位置的字符进行编码:字符Map到。与其他编码没有错误,但没有结果)。我试图在settings.py的database部分设置不同的charset和collation值。

'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",
}

我补充道 <meta http-equiv="Content-type" content="text/html; charset=koi8-r (or other)" /><head> index.html模板中的标记。没有结果。
看来django执行了 SET NAMES utf8 每次
为什么在perl中我可以用charset=koi8-r发送头文件,然后在浏览器中使用cgi从这个表中获取正常值?为什么python和django或flask没有类似的结果?perl中的简单示例

agyaoht7

agyaoht71#

我觉得你把网络字符编码和存储编码搞混了。在mysql中,字符串数据的生命周期大致如下:

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

当从磁盘读取字符串数据时,mysql使用 character_set_database 价值观。当客户机通过网络连接时,客户机将指定连接的编码。对于python,这通常是utf-8。然后mysql将数据编码为连接编码。pythonmysql驱动程序然后使用它设置的连接编码对它接收的数据进行解码。
如果这些代码或编码中的任何一个使用了错误的值,那么将创建错误的数据。如果 character_set_database 如果设置不正确,那么mysql将在对网络连接上的坏数据进行编码之前对数据进行错误解码。
解决办法应该简单到改变 character_set_database 在不改变实际数据的情况下将其转换为正确的值。
这可以通过以下方式实现:

ALTER DATABASE dbname CHARACTER SET koi8r COLLATE koi8r_general_ci;

(不要跑 ALTER TABLE tbl_name CONVERT.. -这实际上会重新编码您的数据。由于旧字符集值错误,在编码为新编码之前,您的数据将被错误解码)
将所有python设置更改回默认设置(utf-8等)。不设置 DEFAULT_CHARSET 或任何其他值。
以确保mysql驱动程序正确连接并使用utf-8作为网络连接集 use_unicode=True 以及 charset="utf8" 例如

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

7vux5j2d2#

我解决了这个问题。
第一条路

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),请告诉我

7gyucuyw

7gyucuyw3#

我很确定你需要两步走 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;

注意:如果从文本开始,请使用blob作为中间定义(确保其他规范保持不变(varchar、notnull等)
-- http://mysql.rjweb.org/doc.php/charcoll#fixes_for_various_cases
正如您将在该链接中看到的,对于不同的场景有许多不同的修复。如果你已经应用了其他一些答案,你可能会让事情变得更糟!如果您需要进一步的帮助,请提供一个样品

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

我也许能推断出情况。 ëÏÚÌÑÎËÏ òÏÍÁÎ éÏÓÉÆÏ×ÉÞ 以及 þÅÐÒÑÇÏ×Á éÎÅÓÓÁ ÷ÉËÔÏÒÏ×ÎÁ 看上去完全被弄坏了;快速看一眼就知道可能是应用了错误的转换。韩文原文是什么?

相关问题