Запись в mariadb приводит к появлению неUTF-8-эндокодинга
Я использую mariadb с Server charset: UTF-8 Unicode (utf8mb4) и python 3.7.3 и по какой-то непонятной мне причине CSV-файл, прочитанный и записанный в базу данных, сохраняется в какой-то странной кодировке:
models.py:
class Product(models.Model)
data = models.JSONField()
store = models.ForeignKey(Store, on_delete = models.CASCADE)
number = models.PositiveIntegerField()
и при чтении csv-файла:
with open(filename, encoding = "utf-8") as f:
reader = csv.reader(f)
for row in reader:
d = {header[i]: row[i] for i in range(1, len(row))}
logging.error(f"{row[0]} - {d}") # prints "123 - süden"
product = Product.objects.get(store = store, number = row[0]) product.data = d
product.save()
но в моей базе данных строка читается как "number": 123, "data": "s\u00fcden".
Итак, мои трудности здесь:
- csv файл закодирован в UTF-8
- csv файл открыт с кодировкой UTF-8
- консоль правильно печатает кодировку
- phpmyadmin показывает, "ü" сохранено как "\u00fc"
- печать строки в django shell печатает "ü" правильно
Я уже пытался установить кодировку для JSONField:
from django.core.serializers.json import DjangoJSONEncoder
...
data = models.JSONField(encoder = DjangoJSONEncoder)
и затем снова запустили миграции. Простой тест можно сделать в админке, при поиске товаров süden возвращает ноль результатов. Но если вручную изменить значение на süden в базе данных, это явно работает. Также, при поиске 123 в админке, я вижу, что слово süden написано правильно.
Итак, я предполагаю, что мне нужно реализовать некий эквивалент опции pythons json ensure_ascii=False? Как бы мне это сделать?
Поскольку это заняло у меня некоторое время и я получил некоторую помощь на форуме django, я хочу ответить на вопрос. Мне не удалось реализовать свой собственный декодер, и я все еще хотел бы посмотреть, как это работает (очень мало примеров вокруг), но мне удалось решить задачу, перезаписав get_prep_value из JSONField в
class MyJSONField(models.JSONField):
def get_prep_value(self, value):
if value is None:
return value
return json.dumps(value, ensure_ascii = False)
и поэтому модель Product меняется на:
class Product(models.Model):
data = MyJSONField()
store = models.ForeignKey(Store, on_delete = models.CASCADE)
number = models.PositiveIntegerField()
Миграции должны быть запущены снова!