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
答案 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=True
和charset="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 ...
我也许能够推断出事物的立场。 ëÏÚÌÑÎËÏ òÏÍÁÎ éÏÓÉÆÏ×ÉÞ
和þÅÐÒÑÇÏ×Á éÎÅÓÓÁ ÷ÉËÔÏÒÏ×ÎÁ
看上去很乱;快速浏览一下,可能是应用了错误的转换。朝鲜语文字是什么?