可以django的auth_user.username是varchar(75)? 这怎么可能呢?
在auth_user
上运行alter table以使用username
变成varchar(75)
是否有什么问题? 如果有什么打破了什么?
如果您要将auth_user.username
更改为varchar(75)
,那么您需要修改django吗? 这只是一个在源代码中改变30到75的问题吗?
username = models.CharField(_('username'), max_length=30, unique=True, help_text=_("Required. 30 characters or fewer. Letters, numbers and @/./+/-/_ characters"))
还是还有其他的validation,在这个领域将不得不改变或任何其他影响这样做?
请参阅下面的bartek讨论关于做这件事的原因。
编辑 :在几个月后回顾这个。 对于任何人不知道的前提:有些应用程序没有要求或希望使用用户名,他们只使用电子邮件注册和身份validation。 不幸的是,在django auth.contrib中,用户名是必需的。 您可以开始在用户名字段中input电子邮件,但该字段只有30个字符,并且电子邮件在现实世界中可能很长。 可能甚至比75字符在这里build议更长,但75字符容纳最理智的电子邮件地址。 这个问题就是针对这种情况,正如基于电子邮件authentication的应用程序所遇到的那样。
有一种方法可以实现这一点,而不需要触及核心模型,也没有inheritance,但它肯定是骇人听闻的,我会特别小心地使用它。
如果你看看Django 关于信号的doc,你会看到有一个叫做class_prepared
,它基本上是在元类创build了任何实际的模型类的时候发送的。 那一刻是在魔法发生之前修改任何模型的最后一次机会(即: ModelForm
, ModelAdmin
, syncdb
等)。
所以这个计划很简单,你只需要用一个处理程序来注册这个信号,这个处理程序会在User
模型被调用时检测到,然后改变User
名字段的max_length
属性。
现在的问题是,这个代码应该在哪里? 它必须在User
模型加载之前执行,所以这通常意味着很早 。 不幸的是,你不能(django 1.1.1 ,没有检查另一个版本)把它放在settings
因为在那里inputsignals
将打破东西。
一个更好的select是把它放在一个虚拟应用程序的模型模块中,并将该应用程序放在INSTALLED_APPS
列表/元组之上 (这样就可以在其他任何东西之前导入)。 这是一个你可以在myhackishfix_app/models.py
使用的例子:
from django.db.models.signals import class_prepared def longer_username(sender, *args, **kwargs): # You can't just do `if sender == django.contrib.auth.models.User` # because you would have to import the model # You have to test using __name__ and __module__ if sender.__name__ == "User" and sender.__module__ == "django.contrib.auth.models": sender._meta.get_field("username").max_length = 75 class_prepared.connect(longer_username)
这将有诀窍。
尽pipe如此,
- 您可能还需要更改字段的
help_text
,以反映新的最大长度 - 如果您想使用自动pipe理,您将不得不
UserChangeForm
,UserCreationForm
和AuthenticationForm
因为最大长度不是从模型字段推导出来的,而是直接在表单字段声明中推导出来的。
如果您正在使用South ,则可以创build以下迁移以更改基础数据库中的列:
import datetime from south.db import db from south.v2 import SchemaMigration from django.db import models class Migration(SchemaMigration): def forwards(self, orm): # Changing field 'User.username' db.alter_column('auth_user', 'username', models.CharField(max_length=75)) def backwards(self, orm): # Changing field 'User.username' db.alter_column('auth_user', 'username', models.CharField(max_length=35)) models = { # ... Copy the remainder of the file from the previous migration, being sure # to change the value for auth.user / usename / maxlength
基于Clément和Matt Miller上面的很好的综合答案,我已经将一个实现它的快速应用程序拉到一起。 点安装,迁移,并去。 会把这个作为一个评论,但没有信誉呢!
https://github.com/GoodCloud/django-longer-username
编辑2014-12-08
上面的模块现在已经被弃用,转而使用https://github.com/madssj/django-longer-username-and-email
更新了Django 1.3版本的解决scheme(不修改manage.py):
创build新的Django的应用程序:
monkey_patch/ __init__.py models.py
首先安装它:(settings.py)
INSTALLED_APPS = ( 'monkey_patch', #... )
这里是models.py:
from django.contrib.auth.models import User from django.core.validators import MaxLengthValidator NEW_USERNAME_LENGTH = 300 def monkey_patch_username(): username = User._meta.get_field("username") username.max_length = NEW_USERNAME_LENGTH for v in username.validators: if isinstance(v, MaxLengthValidator): v.limit_value = NEW_USERNAME_LENGTH monkey_patch_username()
上面的解决scheme似乎更新模型的长度。 但是,要在pipe理中反映自定义长度,还需要覆盖pipe理员表单(令人沮丧的是,他们不会简单地从模型中inheritance长度)。
from django.contrib.auth.forms import UserChangeForm, UserCreationForm UserChangeForm.base_fields['username'].max_length = NEW_USERNAME_LENGTH UserChangeForm.base_fields['username'].widget.attrs['maxlength'] = NEW_USERNAME_LENGTH UserChangeForm.base_fields['username'].validators[0].limit_value = NEW_USERNAME_LENGTH UserChangeForm.base_fields['username'].help_text = UserChangeForm.base_fields['username'].help_text.replace('30', str(NEW_USERNAME_LENGTH)) UserCreationForm.base_fields['username'].max_length = NEW_USERNAME_LENGTH UserCreationForm.base_fields['username'].widget.attrs['maxlength'] = NEW_USERNAME_LENGTH UserCreationForm.base_fields['username'].validators[0].limit_value = NEW_USERNAME_LENGTH UserCreationForm.base_fields['username'].help_text = UserChangeForm.base_fields['username'].help_text.replace('30', str(NEW_USERNAME_LENGTH))
据我所知,可以重写用户模型,因为Django 1.5将解决问题。 简单的例子
如果你只是简单地修改数据库表,那么你仍然需要处理Django的validation,所以不能让你使用超过30个字符。 此外,用户名validation,以便它不能像 我的坏,看起来像它处理。 以下是django.contrib.auth中models.py的用户名字段: @
这样的特殊字符,所以只是简单地修改字段的长度将无法正常工作。
username = models.CharField(_('username'), max_length=30, unique=True, help_text=_("Required. 30 characters or fewer. Letters, numbers and @/./+/-/_ characters"))
创build电子邮件authentication并不难。 这是一个超级简单的电子邮件身份validation后端,您可以使用。 你需要做的是添加一些validation,以确保电子邮件地址是唯一的,你就完成了。 那很简单。
是的,可以做到。 至less我认为这应该起作用; 我最终取代了整个authentication模式,所以如果这个问题没有解决的话,我们已经做好了准备。
如果您没有关心的用户logging:
- 删除auth_user表
- 在模型中将用户名更改为max_length = 75
- 执行syncdb
如果你有需要保留的用户logging,那么它就更复杂了,因为你需要以某种方式迁移它们。 最容易的是从旧到新表的数据备份和恢复,如下所示:
- 备份用户表数据
- 放下桌子
- 执行syncdb
- 将用户数据重新导入到新表中; 注意恢复原始的id值
另外,使用你的疯狂的python-django技能,将用户模型实例从旧复制到新,并replace:
- 创build您的自定义模型,并暂时站在默认模型旁边
- 编写一个将实例从默认模型复制到新模型的脚本
- 用您的自定义模型replace默认模型
后者并不像听起来那么难,但显然需要更多的工作。
从根本上说,问题是有些人希望使用电子邮件地址作为唯一标识符,而Django中的用户authentication系统需要一个最多30个字符的唯一用户名。 也许这将在未来发生变化,但正如我正在写的那样,Django 1.3就是这样。
我们知道,很多电子邮件地址的30个字符太短, 甚至75个字符也不足以代表某些电子邮件地址,正如数据库中电子邮件地址的最佳长度是什么? 。
我喜欢简单的解决scheme,所以我build议将电子邮件地址散列成符合Django用户名限制的用户名。 根据Django中的用户身份validation ,用户名最多不超过30个字符,由字母数字字符和_,@,+,组成。 和 – 。 因此,如果我们使用base-64编码仔细replace特殊字符,我们有180位。 所以我们可以使用像SHA-1这样的160位散列函数,如下所示:
import hashlib import base64 def hash_user(email_address): """Create a username from an email address""" hash = hashlib.sha1(email_address).digest() return base64.b64encode(hash, '_.').replace('=', '')
简而言之,该function将任何电子邮件地址的用户名关联起来。 我知道哈希函数有一个很小的碰撞概率,但是这在大多数应用中都不是问题。
只需在settings.py的底部添加下面的代码即可
from django.contrib.auth.models import User User._meta.get_field("username").max_length = 75
我使用django 1.4.3这使得它很容易,我没有改变我的代码中的任何其他事情后,我意识到我想使用长的电子邮件地址作为用户名。
如果你有直接访问数据库的地方,那就把它改成你想要的字符数量,我的情况是100个字符。
在您的应用程序模型(myapp / models.py)中添加以下内容
from django.contrib.auth.models import User class UserProfile(models.Model): # This field is required. User._meta.get_field("username").max_length = 100 user = models.OneToOneField(User)
然后在你的settings.py中指定模型:
AUTH_USER_MODEL = 'myapp.UserProfile'
最好的解决scheme是使用电子邮件字段的电子邮件和用户名的用户名。
在inputlogin表单validation中,查找数据是用户名还是电子邮件,如果是电子邮件,则查询电子邮件字段。
这只需要在相应的视图中修改contrib.auth.forms.login_form
几行即可。
而且这比试图修改模型和数据库表要好得多。
如果你使用venv(虚拟环境),最简单的解决scheme可能就是直接更新核心代码,即打开以下两个文件: – venv / lib / python2.7 / sites-packages / django / contrib / auth / model .py – venv / lib / python2.7 / sites-packages / django / contrib / auth / forms.pysearch所有用户名字段,并将max_length从30更改为100.这是安全的,因为您已经使用venv,不会影响任何其他的Django项目。