1. 程式人生 > >django,mysql儲存emoji表情,utf8mb4

django,mysql儲存emoji表情,utf8mb4

今天在做後臺的時候發現一個錯誤:

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即可。