2

我想让auth_user.email不区分大小写的唯一、可为空且默认为空。以下几乎可以工作:

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 shell 并看到该表已明显修改:

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 的东西或某事。有任何想法吗?

更新:没有任何帮助connection.commit()cursor.close()使用TransactionTestCase无济于事。

4

0 回答 0