2

auth_user.email大文字と小文字を区別しない一意の nullable でデフォルトの nullを作成したい。以下はほとんど機能します:

from django.db.models.signals import post_syncdb
import app.models

SQLITE_AUTH_REFORM = [
"PRAGMA writable_schema = 1;",
"""UPDATE SQLITE_MASTER SET SQL =
'CREATE TABLE auth_user (
    "id" integer NOT NULL PRIMARY KEY,
    "username" varchar(30) NOT NULL UNIQUE,
    "first_name" varchar(30) NOT NULL,
    "last_name" varchar(30) NOT NULL,
    "email" varchar(75) DEFAULT NULL,
    "password" varchar(128) NOT NULL,
    "is_staff" bool NOT NULL,
    "is_active" bool NOT NULL,
    "is_superuser" bool NOT NULL,
    "last_login" datetime NOT NULL,
    "date_joined" datetime NOT NULL
)' WHERE NAME = 'auth_user';""",
"PRAGMA writable_schema = 0;",
]

def post_syncdb_callback(sender, **kwargs):
    from django.db import connections
    from django.conf import settings
    cursor = connections['default'].cursor()

    if 'sqlite' in settings.DATABASES['default']['ENGINE']:
        for stmt in SQLITE_AUTH_REFORM:
            cursor.execute(stmt)
        cursor.execute(
            "CREATE UNIQUE INDEX IF NOT EXISTS auth_user_email_unique "
            "ON auth_user (email COLLATE NOCASE);"
        )
    else:  # Oracle
        cursor.execute(
            "CREATE UNIQUE INDEX auth_user_email_unique "
            "ON auth_user (upper(email));"
        )
    cursor.cursor.close()

post_syncdb.connect(post_syncdb_callback, sender=app.models)

できます

User.objects.create(username=str(random.random()), email=None)

心ゆくまで。また、

User.objects.create(username=str(random.random()), email='Foo')
User.objects.create(username=str(random.random()), email='foo')
...
IntegrityError: column email is not unique

唯一の問題は、これが機能してDEFAULT NULLいないように見えることです:User.objects.create(username=str(random.random()))空の文字列の電子メールでユーザーを作成します。

ただし、単体テストでは、post-syncdb フックの動作を妨げる何かが起こっていると思われます。

class DjangoUserTest(TestCase):

    def test_unique_nullable_email(self):
        import IPython; IPython.embed()
        u1 = User.objects.create(username="u1", email=None)
        u2 = User.objects.create(username="u2", email=None)

ipython シェルにドロップすると、テーブルが明らかに変更されていることがわかります。

In [1]: from django.db import connection

In [2]: c = connection.cursor()

In [3]: r = c.execute("select `sql` from sqlite_master WHERE tbl_name = 'auth_user';")

In [4]: r.fetchall()
Out[4]: 
[(u'CREATE TABLE auth_user (\n    "id" integer NOT NULL PRIMARY KEY,\n    "username" varchar(30) NOT NULL UNIQUE,\n    "first_name" varchar(30) NOT NULL,\n    "last_name" varchar(30) NOT NULL,\n    "email" varchar(75) DEFAULT NULL,\n    "password" varchar(128) NOT NULL,\n    "is_staff" bool NOT NULL,\n    "is_active" bool NOT NULL,\n    "is_superuser" bool NOT NULL,\n    "last_login" datetime NOT NULL,\n    "date_joined" datetime NOT NULL\n)',),
 (None,),
 (u'CREATE UNIQUE INDEX auth_user_email_unique ON auth_user (email COLLATE NOCASE)',)]

ただし、作成しようとすると、IntegrityError: auth_user.email may not be NULL. select sql from sqlite_master WHERE tbl_name = 'auth_user';が明確に言うと、どうしてこうなっ"email" varchar(75) DEFAULT NULLた。post_syncdb や sth をコミットするだけでいいような気がします。何か案は?

更新: の量はありませんがconnection.commit()cursor.close()使用TransactionTestCaseしても役に立ちません。

4

0 に答える 0