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.
Шаги для тиражирования:
Установите последнюю версию Django:
$ pip install django
Установите драйвер Python-MySQL:
$ pip install MySQL-python
Создайте новый проект:
$ django-admin.py startproject sandbox
Создайте новую базу данных в MySQL и установите конфигурацию базы данных в
settings.py
Миграция моделей приложений Django:
$ ./manage.py migrate
Создать
admin
суперпользователя:$ ./manage.py createsuperuser
Запустите связанный сервер Django:
$ ./manage.py runserver
Идти к
http://127.0.0.1:8000/admin/login
и войти в систему сadmin
Учетные данные суперпользователя.Попробуйте нажать кнопку " Добавить пользователя ". Прилагается ошибка на скриншоте.
Примеры журналов запросов к базе данных:
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:
MySQLdb (широко используемый, но старый коннектор базы данных, последний коммит был 7 лет назад!):
$ pip install MySQL-python
mysqlclient (современная версия
MySQL-python
, но с множеством исправлений и улучшений):$ pip install mysqlclient
PyMySQL (чистый драйвер базы данных Python MySQL):
$ pip install PyMySQL
Затем добавьте
settings.py
(чуть нижеimport os
):try: import pymysql pymysql.install_as_MySQLdb() except: pass
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