Błąd MySQL "incorrect string value" podczas zapisywania ciągu unicode w Django
Dostałem dziwny komunikat o błędzie, gdy próbowałem zapisać first_name, last_name do modelu Auth_user Django.
Nieudane przykłady
user = User.object.create_user(username, email, password)
user.first_name = u'Rytis'
user.last_name = u'Slatkevičius'
user.save()
>>> Incorrect string value: '\xC4\x8Dius' for column 'last_name' at row 104
user.first_name = u'Валерий'
user.last_name = u'Богданов'
user.save()
>>> Incorrect string value: '\xD0\x92\xD0\xB0\xD0\xBB...' for column 'first_name' at row 104
user.first_name = u'Krzysztof'
user.last_name = u'Szukiełojć'
user.save()
>>> Incorrect string value: '\xC5\x82oj\xC4\x87' for column 'last_name' at row 104
Przykłady sukcesu
user.first_name = u'Marcin'
user.last_name = u'Król'
user.save()
>>> SUCCEED
Ustawienia MySQL
mysql> show variables like 'char%';
+--------------------------+----------------------------+
| Variable_name | Value |
+--------------------------+----------------------------+
| character_set_client | utf8 |
| character_set_connection | utf8 |
| character_set_database | utf8 |
| character_set_filesystem | binary |
| character_set_results | utf8 |
| character_set_server | utf8 |
| character_set_system | utf8 |
| character_sets_dir | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
8 rows in set (0.00 sec)
Table charset and collation
Tabela auth_user ma kod utf-8 z kolacją utf8_general_ci.
Wyniki polecenia UPDATE
Nie wywołało żadnego błędu podczas aktualizacji powyższych wartości do auth_user tabelę za pomocą polecenia UPDATE.
mysql> update auth_user set last_name='Slatkevičiusa' where id=1;
Query OK, 1 row affected, 1 warning (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> select last_name from auth_user where id=100;
+---------------+
| last_name |
+---------------+
| Slatkevi?iusa |
+---------------+
1 row in set (0.00 sec)
PostgreSQL
Nieudane wartości wymienione powyżej mogą zostać zaktualizowane do tabeli PostgreSQL, gdy zmieniłem backend bazy danych w Django. To dziwne.
mysql> SHOW CHARACTER SET;
+----------+-----------------------------+---------------------+--------+
| Charset | Description | Default collation | Maxlen |
+----------+-----------------------------+---------------------+--------+
...
| utf8 | UTF-8 Unicode | utf8_general_ci | 3 |
...
Ale od http://www.postgresql.org/docs/8.1/interactive/multibyte.html , znalazłem:
Name Bytes/Char
UTF8 1-4
Czy to oznacza, że znak unicode ma maxlen 4 bajtów w PostgreSQL, ale 3 bajty w MySQL, co spowodowało powyższy błąd?
8 answers
Miałem ten sam problem i rozwiązałem go zmieniając zestaw znaków w kolumnie. Mimo że Twoja baza danych ma domyślny zestaw znaków utf-8
, myślę, że możliwe jest, aby kolumny bazy danych miały inny zestaw znaków w MySQL. Oto zapytanie SQL, którego użyłem:
ALTER TABLE database.table MODIFY COLUMN col VARCHAR(255)
CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL;
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-04 14:59:08
Żadna z tych odpowiedzi nie rozwiązała problemu. Główną przyczyną jest:
Nie można przechowywać 4-bajtowych znaków w MySQL z zestawem znaków utf-8.
MySQL ma limit 3 bajtów na utf-8 znaków (tak, to wariactwo, ładnie podsumowane przez dewelopera Django tutaj)
Aby to rozwiązać, musisz:
- ZMIEŃ bazę danych, tabelę i kolumny MySQL, aby używać zestawu znaków utf8mb4 (dostępne tylko z MySQL 5.5 dalej)
- Określ zestaw znaków w Twoim pliku ustawień Django jak poniżej:
Settings.py
DATABASES = {
'default': {
'ENGINE':'django.db.backends.mysql',
...
'OPTIONS': {'charset': 'utf8mb4'},
}
}
Uwaga: Podczas odtwarzania bazy danych możesz napotkać problem " określony klucz był zbyt długi".
Najbardziej prawdopodobną przyczyną jest CharField
, która ma max_length 255 i jakiś indeks (np. unique). Ponieważ utf8mb4 zużywa o 33% więcej miejsca niż utf-8, będziesz musiał zmniejszyć te pola o 33%.
W tym przypadku zmień max_length od 255 do 191.
Alternatywnie możesz edytować konfigurację MySQL, aby usunąć to ograniczenie ale nie bez django hackery
UPDATE: po prostu natknąłem się na ten problem ponownie i skończyło się przejście na PostgreSQL ponieważ nie byłem w stanie zmniejszyć mój VARCHAR
do 191 znaków.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-30 21:07:56
Jeśli masz ten problem Oto skrypt Pythona, aby automatycznie zmienić wszystkie kolumny bazy danych mysql.
#! /usr/bin/env python
import MySQLdb
host = "localhost"
passwd = "passwd"
user = "youruser"
dbname = "yourdbname"
db = MySQLdb.connect(host=host, user=user, passwd=passwd, db=dbname)
cursor = db.cursor()
cursor.execute("ALTER DATABASE `%s` CHARACTER SET 'utf8' COLLATE 'utf8_unicode_ci'" % dbname)
sql = "SELECT DISTINCT(table_name) FROM information_schema.columns WHERE table_schema = '%s'" % dbname
cursor.execute(sql)
results = cursor.fetchall()
for row in results:
sql = "ALTER TABLE `%s` convert to character set DEFAULT COLLATE DEFAULT" % (row[0])
cursor.execute(sql)
db.close()
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-05 22:35:28
Jeśli jest to nowy projekt, po prostu rzuciłbym bazę danych i utworzył nowy z odpowiednim charsetem:
CREATE DATABASE <dbname> CHARACTER SET utf8;
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-21 19:57:05
Właśnie wymyśliłem jedną metodę, aby uniknąć powyższych błędów.
Zapisz do bazy danych
user.first_name = u'Rytis'.encode('unicode_escape')
user.last_name = u'Slatkevičius'.encode('unicode_escape')
user.save()
>>> SUCCEED
print user.last_name
>>> Slatkevi\u010dius
print user.last_name.decode('unicode_escape')
>>> Slatkevičius
Czy jest to jedyna metoda zapisywania takich ciągów w tabeli MySQL i dekodowania ich przed renderowaniem do szablonów do wyświetlenia?
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-01-21 15:29:09
Możesz zmienić zestawienie swojego pola tekstowego na UTF8_general_ci i problem zostanie rozwiązany.
Uwaga, tego nie można zrobić w Django.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-02 15:54:06
Nie próbujesz zapisać ciągów unicode, próbujesz zapisać bajty w kodowaniu UTF-8. Uczyń z nich rzeczywiste literały ciągu unicode:
user.last_name = u'Slatkevičius'
Lub (jeśli nie masz liter ciągów) dekodować je za pomocą kodowania utf-8:
user.last_name = lastname.decode('utf-8')
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-01-21 11:44:50
Po prostu zmień swój stół, nie ma potrzeby niczego. po prostu uruchom to zapytanie w bazie danych.
ALTER TABLE table_name
CONVERT TO CHARACTER SET utf8
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-13 12:41:40