Django + MySQL - Администратор сайта - Добавить пользователя - OperationalError - SAVEPOINT не существует

Мы пытаемся создать пользовательскую модель и поведение пользователя, но потом заметили, что даже при установке Django по умолчанию возникают проблемы при добавлении нового пользователя через администратора Django:

Проблема возникает даже в других версиях Django (пробовал в Django 1.8 и в последней версии Django 1.11.3). Удивительно, но проблема не возникает при использовании баз данных SQLite или PostgreSQL. Также добавление пользователя через $./manage.py createuser и программно будет работать. Редактирование существующих применений, таких как ранее созданные admin суперпользователь через терминал тоже будет работать. Механизмы CRUD для групповой работы по назначению, следовательно, только Add User вид влияет.

Возможные точки сбоев включают ядро Django (любая версия), двоичный файл MySQL (входит в XAMPP для Mac, пробовал также разные версии) или коннектор MySQL-Python (версия 1.2.5). Подобная проблема здесь, с использованием Django 1.10 и MySQL.

Шаги для тиражирования:

  1. Установите последнюю версию Django: $ pip install django

  2. Установите драйвер Python-MySQL: $ pip install MySQL-python

  3. Создайте новый проект: $ django-admin.py startproject sandbox

  4. Создайте новую базу данных в MySQL и установите конфигурацию базы данных в settings.py

  5. Миграция моделей приложений Django: $ ./manage.py migrate

  6. Создать admin суперпользователя: $ ./manage.py createsuperuser

  7. Запустите связанный сервер Django: $ ./manage.py runserver

  8. Идти к http://127.0.0.1:8000/admin/login и войти в систему с admin Учетные данные суперпользователя.

  9. Попробуйте нажать кнопку " Добавить пользователя ". Прилагается ошибка на скриншоте.

Примеры журналов запросов к базе данных:

Query   SET NAMES utf8
Query   set autocommit=1
Query   SELECT `django_session`.`session_key`, `django_session`.`session_data`, `django_session`.`expire_date` FROM `django_session` WHERE (`django_session`.`session_key` = 'ikql6mk9voxq4g0go9avuvuxxrpvwx9w' AND `django_session`.`expire_date` > '2017-07-10 06:58:15.823513')
Query   SELECT `auth_user`.`id`, `auth_user`.`password`, `auth_user`.`last_login`, `auth_user`.`is_superuser`, `auth_user`.`username`, `auth_user`.`first_name`, `auth_user`.`last_name`, `auth_user`.`email`, `auth_user`.`is_staff`, `auth_user`.`is_active`, `auth_user`.`date_joined` FROM `auth_user` WHERE `auth_user`.`id` = 1
Query   SAVEPOINT `s123145414516736_x1`
Query   RELEASE SAVEPOINT `s123145414516736_x1`
Query   ROLLBACK TO SAVEPOINT `s123145414516736_x1`
Query   rollback
Query   set autocommit=1
Quit

Похоже, что SAVEPOINT ROLLBACK был выполнен после того, как SAVEPOINT RELEASE вызвало отсутствие SAVEPOINT. Исходя из документов MySQL о SavePoint, естественный порядок выглядит как ROLLBACK, а затем RELEASE.

Вот сообщения трассировки. Других изменений в Django по умолчанию нет settings.py за исключением конфигурации базы данных / учетных данных для подключения к серверу MySQL:

Environment:


Request Method: GET
Request URL: http://127.0.0.1:8000/admin/auth/user/add/

Django Version: 1.11.3
Python Version: 2.7.8
Installed Applications:
['django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles']
Installed Middleware:
['django.middleware.security.SecurityMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.common.CommonMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'django.middleware.clickjacking.XFrameOptionsMiddleware']



Traceback:

File "/Users/ranelpadon/.virtualenvs/django__1_11/lib/python2.7/site-packages/django/core/handlers/exception.py" in inner
  41.             response = get_response(request)

File "/Users/ranelpadon/.virtualenvs/django__1_11/lib/python2.7/site-packages/django/core/handlers/base.py" in _get_response
  187.                 response = self.process_exception_by_middleware(e, request)

File "/Users/ranelpadon/.virtualenvs/django__1_11/lib/python2.7/site-packages/django/core/handlers/base.py" in _get_response
  185.                 response = wrapped_callback(request, *callback_args, **callback_kwargs)

File "/Users/ranelpadon/.virtualenvs/django__1_11/lib/python2.7/site-packages/django/contrib/admin/options.py" in wrapper
  551.                 return self.admin_site.admin_view(view)(*args, **kwargs)

File "/Users/ranelpadon/.virtualenvs/django__1_11/lib/python2.7/site-packages/django/utils/decorators.py" in _wrapped_view
  149.                     response = view_func(request, *args, **kwargs)

File "/Users/ranelpadon/.virtualenvs/django__1_11/lib/python2.7/site-packages/django/views/decorators/cache.py" in _wrapped_view_func
  57.         response = view_func(request, *args, **kwargs)

File "/Users/ranelpadon/.virtualenvs/django__1_11/lib/python2.7/site-packages/django/contrib/admin/sites.py" in inner
  224.             return view(request, *args, **kwargs)

File "/Users/ranelpadon/.virtualenvs/django__1_11/lib/python2.7/site-packages/django/utils/decorators.py" in _wrapper
  67.             return bound_func(*args, **kwargs)

File "/Users/ranelpadon/.virtualenvs/django__1_11/lib/python2.7/site-packages/django/views/decorators/debug.py" in sensitive_post_parameters_wrapper
  76.             return view(request, *args, **kwargs)

File "/Users/ranelpadon/.virtualenvs/django__1_11/lib/python2.7/site-packages/django/utils/decorators.py" in bound_func
  63.                 return func.__get__(self, type(self))(*args2, **kwargs2)

File "/Users/ranelpadon/.virtualenvs/django__1_11/lib/python2.7/site-packages/django/utils/decorators.py" in _wrapper
  67.             return bound_func(*args, **kwargs)

File "/Users/ranelpadon/.virtualenvs/django__1_11/lib/python2.7/site-packages/django/utils/decorators.py" in _wrapped_view
  149.                     response = view_func(request, *args, **kwargs)

File "/Users/ranelpadon/.virtualenvs/django__1_11/lib/python2.7/site-packages/django/utils/decorators.py" in bound_func
  63.                 return func.__get__(self, type(self))(*args2, **kwargs2)

File "/Users/ranelpadon/.virtualenvs/django__1_11/lib/python2.7/site-packages/django/contrib/auth/admin.py" in add_view
  103.             return self._add_view(request, form_url, extra_context)

File "/Users/ranelpadon/.virtualenvs/django__1_11/lib/python2.7/site-packages/django/contrib/auth/admin.py" in _add_view
  131.                                                extra_context)

File "/Users/ranelpadon/.virtualenvs/django__1_11/lib/python2.7/site-packages/django/contrib/admin/options.py" in add_view
  1508.         return self.changeform_view(request, None, form_url, extra_context)

File "/Users/ranelpadon/.virtualenvs/django__1_11/lib/python2.7/site-packages/django/utils/decorators.py" in _wrapper
  67.             return bound_func(*args, **kwargs)

File "/Users/ranelpadon/.virtualenvs/django__1_11/lib/python2.7/site-packages/django/utils/decorators.py" in _wrapped_view
  149.                     response = view_func(request, *args, **kwargs)

File "/Users/ranelpadon/.virtualenvs/django__1_11/lib/python2.7/site-packages/django/utils/decorators.py" in bound_func
  63.                 return func.__get__(self, type(self))(*args2, **kwargs2)

File "/Users/ranelpadon/.virtualenvs/django__1_11/lib/python2.7/site-packages/django/contrib/admin/options.py" in changeform_view
  1408.             return self._changeform_view(request, object_id, form_url, extra_context)

File "/Users/ranelpadon/.virtualenvs/django__1_11/lib/python2.7/site-packages/django/db/transaction.py" in __exit__
  210.                                 connection.savepoint_rollback(sid)

File "/Users/ranelpadon/.virtualenvs/django__1_11/lib/python2.7/site-packages/django/db/backends/base/base.py" in savepoint_rollback
  348.         self._savepoint_rollback(sid)

File "/Users/ranelpadon/.virtualenvs/django__1_11/lib/python2.7/site-packages/django/db/backends/base/base.py" in _savepoint_rollback
  308.             cursor.execute(self.ops.savepoint_rollback_sql(sid))

File "/Users/ranelpadon/.virtualenvs/django__1_11/lib/python2.7/site-packages/django/db/backends/utils.py" in execute
  80.             return super(CursorDebugWrapper, self).execute(sql, params)

File "/Users/ranelpadon/.virtualenvs/django__1_11/lib/python2.7/site-packages/django/db/backends/utils.py" in execute
  65.                 return self.cursor.execute(sql, params)

File "/Users/ranelpadon/.virtualenvs/django__1_11/lib/python2.7/site-packages/django/db/utils.py" in __exit__
  94.                 six.reraise(dj_exc_type, dj_exc_value, traceback)

File "/Users/ranelpadon/.virtualenvs/django__1_11/lib/python2.7/site-packages/django/db/backends/utils.py" in execute
  63.                 return self.cursor.execute(sql)

File "/Users/ranelpadon/.virtualenvs/django__1_11/lib/python2.7/site-packages/django/db/backends/mysql/base.py" in execute
  101.             return self.cursor.execute(query, args)

File "/Users/ranelpadon/.virtualenvs/django__1_11/lib/python2.7/site-packages/MySQLdb/cursors.py" in execute
  205.             self.errorhandler(self, exc, value)

File "/Users/ranelpadon/.virtualenvs/django__1_11/lib/python2.7/site-packages/MySQLdb/connections.py" in defaulterrorhandler
  36.     raise errorclass, errorvalue

Exception Type: OperationalError at /admin/auth/user/add/
Exception Value: (1305, 'SAVEPOINT s123145452511232_x1 does not exist')

3 ответа

Эта ошибка преследовала меня долгое время, поэтому я решил копать дальше и попытаться устранить ее раз и навсегда.

Основная причина: проблема SAVEPOINT - это ошибка, которая возникает только в MySQL-Python разъем.

Исправлено: Использование других драйверов MySQL для Python (например, mysqlclient).

Детали / Выводы:

  • Попробовал двоичные файлы MySQL в Homebrew, MAMP и XAMPP для Mac.
  • Перепробовал разные версии MySQL, 5.6 (libmysqlclient.18.dylib) и 5,7 (libmysqlclient.20.dylib).
  • Пробовал различные драйверы Python для MySQL.

Никаких отношений не найдено путем изменения двоичных файлов / версий MySQL. Но я сузил проблему, протестировав различные драйверы MySQL, обычно используемые в Python:

  1. MySQLdb (широко используемый, но старый коннектор базы данных, последний коммит был 7 лет назад!):

    $ pip install MySQL-python

  2. mysqlclient (современная версия MySQL-python, но с множеством исправлений и улучшений):

    $ pip install mysqlclient

  3. PyMySQL (чистый драйвер базы данных Python MySQL):

    $ pip install PyMySQL

    Затем добавьте settings.py (чуть ниже import os):

    try:
        import pymysql
        pymysql.install_as_MySQLdb()
    except:
        pass
    
  4. MySQL-Connector-Python от Oracle (чистый драйвер базы данных Python MySQL):

    $ pip install mysql-connector-python-rf

    Затем отредактируйте базу данных ENGINE конфигурация в settings.py:

    'ENGINE': 'mysql.connector.django',
    

Проблема SAVEPOINT возникает только при использовании коннектора MySQL-python (драйвер #1), но не в других (драйверы #2, #3, #4). В моем случае я выбрал mysqlclient. Проблема ушла сейчас.

Я решил это, переопределив UserAdmin. Похоже, есть проблема с вложенными атомарными транзакциями в кластерных БД.

Добавьте следующие строки в Custom UserAdmin, который наследуется от базового Django UserAdmin:

      @sensitive_post_parameters_m
@csrf_protect_m
def add_view(self, request, form_url='', extra_context=None):
    return self._add_view(request, form_url, extra_context)

У меня был проект, который был только что обновлен с Python 2 до 3, и это произошло потому, что я установил mysqlclient и это то, что вызвало это (на python 3.5), взятое из одного из предложений выше:

$ pip install PyMySQL

in settings.py added:

try:
    import pymysql
    pymysql.install_as_MySQLdb()
except:
    pass
Другие вопросы по тегам