今天在做後臺的時候發現一個錯誤:
Incorrect string value: '\\xF0\\x9F\\x90\\xA8' for column 'signature' at row 1
發現是參數裏面是一個iOS的表情,也就是系統自帶的emoji表情。
後臺用的是django 1.6,數據庫用的是Mysql 5.5.22,緩存用的是redis。
上網瞭解了一下emoji表情,原來一般的字符包括中文用utf8的話,mysql是用3個字節去存儲的,而emoji表情要用4個字節的utf8,也就是utf8mb4格式。
首先更改mysql的數據編碼,修改mysql的配置文件: /etc/mysql/my.cnf 添加:
[client]
default-character-set = utf8mb4
[mysql]
default-character-set = utf8mb4
[mysqld]
character-set-client-handshake = FALSE
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
然後重啓,mysql,查看mysql的編碼
SHOW VARIABLES WHERE Variable_name LIKE 'character\_set\_%' OR Variable_name LIKE 'collation%';
+--------------------------+----------------------------+
| Variable_name | Value |
+--------------------------+----------------------------+
| character_set_client | utf8mb4 |
| character_set_connection | utf8mb4 |
| character_set_database | utf8mb4 |
| character_set_filesystem | binary |
| character_set_results | utf8mb4 |
| character_set_server | utf8mb4 |
| character_set_system | utf8 |
| character_sets_dir | /usr/share/mysql/charsets/ |
| collation_connection | utf8mb4_unicode_ci |
| collation_database | utf8mb4_unicode_ci |
| collation_server | utf8mb4_unicode_ci |
+--------------------------+----------------------------+
OK,mysql改完了,然後創建數據庫:
create database xxx CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
創建數據庫之後是syncdb,這時 MySQLdb模塊 需要1.2.4以上版本,關於MySQLdb模塊的安裝可以參考這篇文章,最新版是1.2.5
syncdb成功之後,再次嘗試插入,還是報錯。
查看了一下這部分的源代碼,發現django/db/backends/mysql/base.py中的DatabaseWrapper類中有個kwargs的屬性,裏面有個key叫charset,默認值是utf8,後面做數據庫連接的時候,會用django的settings中,database的options去更新這一項。
class DatabaseWrapper(BaseDatabaseWrapper):
def get_connection_params(self):
kwargs = {
'conv': django_conversions,
'charset': 'utf8',
}
那麼我們修改一下django的settings.py,在數據庫的配置中加入options項。
DATABASES = {
'default': {
#'ENGINE': 'sqlite3', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
'ENGINE': 'django.db.backends.mysql',
#'NAME': '/opt/media/session.db', # Or path to database file if using sqlite3.
'NAME': DATABASE_NAME,
'USER': 'root', # Not used with sqlite3.
'PASSWORD': DATABASE_PASSWORD, # Not used with sqlite3.
'HOST': DATABASE_HOST, # Set to empty string for localhost. Not used with sqlite3.
'PORT': DATABASE_PORT, # Set to empty string for default. Not used with sqlite3.
'OPTIONS': {'charset':'utf8mb4'},
},
}
然後再嘗試插入emoji表情,結果正常,取出來結果也正常,ios和android都可以正常使用。
由於實際在阿里雲上部署的時候,mysql使用的是docker container,似乎不方便修改container裏面的mysql配置文件(進去container,裏面沒有vi),嘗試不改配置文件,只是在創建數據庫的時候指定character set 爲utf8mb4,collate爲 utf8mb4_unicode_ci,發現其實也可以用,那麼應該是只需要保證連接mysql的時候是用utf8mb4,並且mysql數據的編碼格式是utf8mb4即可。
網上有更完整的關於存儲emoji表情到mysql的例子可以參考:http://blog.manbolo.com/2014/03/31/using-emojis-in-django-model-fields