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
しても役に立ちません。