Запись в 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 в

из Django.
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()

Миграции должны быть запущены снова!

Вернуться на верх