Невозможно установить значение character_set_results для latin1

Я решил использовать Django 1.7 впервые с Python 3. Мне нужно уметь работать с устаревшим latin1 база данных, которая содержит utf8 данные. Я знаю, что это отстой, но база данных настолько велика, что изменить это невозможно. Поэтому я попробовал следующее:

DATABASES = {
    'ENGINE' : 'django.db.backends.mysql', // using MySQL-python fork with support for py3
    ...
    'OPTIONS' : {
        'init_command': "SET character_set_results = 'latin1'",
        #'read_default_file': '/etc/my.cnf.d/client.cnf', // I've also tried this one
    }
}

Я также попробовал Python-MySQL-коннектор из Oracle со следующей настройкой

DATABASES = {
    'ENGINE' : 'mysql.connector.django', // using MySQL-python fork with support for py3
    'OPTIONS' : {
        'option_files': ['/etc/my.cnf.d/client.cnf'],
    }
}

/etc/my.cnf.d/client.cnf

[client]
init-command='SET character_set_results = "latin1"'
# password, host, username

В обоих случаях я могу подключиться к базе данных, но похоже, что Django устанавливает значение character_set_results обратно в utf8.

Я пытался следовать

from django.db import connection

with connection.cursor() as c:
   // I expect variable to be 'latin1'
   c.execute("show variables like 'character_set_results%'")
   c.fetchone() // returns ('character_set_results', 'utf8')

   // here I try to set it manually
   c.execute("SET character_set_results = 'latin1'")
   c.execute("show variables like 'character_set_results%'")
   c.fetchone() // returns ('character_set_results', 'latin1') // now it's OK
  • Я уверен, что Джанго использует client.cfg файл и исправить [section]потому что он содержит имя пользователя / пароль и успешно подключается к базе данных
  • Когда я использую mysql Команда в терминале Linux, который использует тот же файл конфигурации, все работает как положено

Так что я предполагаю, что Джанго как-то навязывает character_set_results переменная быть utf8, Является ли это возможным? Есть ли способ, как я могу решить эту проблему?

большое спасибо

3 ответа

Решение

Я наконец понял это (я не знаю, почему я всегда нахожу решение после публикации его в SO)

from django.db.backends.signals import connection_created

def connection_setup(**kwargs):
    conn = kwargs['connection']
    with conn.cursor() as cursor:
        cursor.execute("SET character_set_results = 'latin1'")
        cursor.close()

Я пробовал это раньше с Oracle python-mysql-connector и это бросило

RuntimeError: maximum recursion depth exceeded in comparison

но это работает с MySQL-driver ветка py3. Я думаю, это может быть ошибка в python-mysql-connector или же Django о котором я сообщу. Может быть, это кому-нибудь поможет.

Не совсем полноценный ответ, но слишком длинный для комментария, так что...

Наборы MySQL от Django kwargs['charset']='utf8' по умолчанию в DatabaseWrapper.get_connection_params(), Этот dict затем передается MySQLdb Connection.__init__, который документирует, что:

кодировок
Если указан, набор символов подключения будет изменен
к этому набору символов (MySQL-4.1 и новее). Из этого следует
use_unicode=True.

Таким образом, отправной точкой может быть просто добавить "charset":"latin1" в вашем OPTIONS диктовать?

ПРЕДУПРЕЖДЕНИЕ: я не уверен, что это решит вашу проблему, и это может даже создать другие проблемы, но хорошо, что наличие данных в кодировке utf8 в базе данных latin1, безусловно, не лучшая отправная точка:-/ (здесь, сделали это, и я чувствую твою боль).

С помощью Python коннектора mysql в файле client.cfg, который вы используете в качестве файла опций, вместо опции init-command (которая игнорируется соединителем) используйте write, charset=latin1, это будет работать.

[client]
charset=latin1
# password, host, username
Другие вопросы по тегам