Django:使auth_user.email不区分大小写并且可以为空

时间:2012-12-12 01:59:41

标签: sql django sqlite unit-testing django-models

我想使auth_user.email不区分大小写的唯一,可空和默认为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()))使用空字符串电子邮件创建用户。

但是,在单元测试中,我相信会阻止后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无效。

0 个答案:

没有答案