7

カスタム ユーザー モデルと動作を作成しようとしていますが、Django Admin を介して新しいユーザーを追加するときに、デフォルトの Django インストールでも問題があることに気付きました。

この問題は、他の Django バージョンでも発生します ( Django 1.8で試し、最新の Django 1.11.3で試しました)。驚くべきことに、SQLite または PostgreSQL データベースを使用している場合、この問題は発生しません。また、プログラムを使用してユーザーを追加することもできます$./manage.py createuseradmin以前に作成したスーパーユーザーなどの既存のユーザーをターミナル経由で編集することもできます。グループの CRUD メカニズムは意図したとおりに機能するため、Add Userビューのみが影響を受けます。

障害の可能性のあるポイントには、Django コア(任意のバージョン)、MySQL バイナリ(XAMPP for 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 で新しいデータベースを作成し、db config を設定します。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 RELEASE の後に SAVEPOINT ROLLBACK が実行され、SAVEPOINT が失われたようです。MySQL の SavePoint docsに基づくと、自然な順序は ROLLBACK から RELEASE のようです。

トレースバック メッセージは次のとおりです。settings.pyMySQL サーバーに接続するためのデータベース構成/資格情報を除いて、Django のデフォルトに他の変更はありません。

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')
4

3 に答える 3

7

このバグは長い間私を悩ませていたので、さらに掘り下げて、完全に解決しようとしました。

根本原因: SAVEPOINT の問題は、MySQL-Pythonコネクタでのみ発生するバグです。

修正: Python 用の他の MySQL ドライバーを使用します (例: mysqlclient)。

詳細/調査結果:

  • Homebrew、MAMP、XAMPP for Mac で MySQL バイナリを試しました。
  • さまざまな MySQL バージョン、5.6 ( libmysqlclient.18.dylib) および 5.7 ( libmysqlclient.20.dylib) を試しました。
  • さまざまな Python の MySQL ドライバーを試しました。

MySQL バイナリ/バージョンを変更しても関係は見つかりませんでした。しかし、Python で一般的に使用されるさまざまな MySQL ドライバーをテストすることで、問題を絞り込みました。

  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 by Oracle (純粋な Python MySQL データベース ドライバー):

    $ pip install mysql-connector-python-rf

    次に、でデータベースのENGINE構成を編集しsettings.pyます。

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

SAVEPOINT の問題は、MySQL-pythonコネクタ (#1 ドライバー) を使用している場合にのみ発生し、その他 (#2、#3、#4 ドライバー) では発生しません。私の場合、mysqlclientを選択しました。問題はなくなりました。

于 2017-07-22T14:27:46.703 に答える