django的auth_user.username可以是varchar(75)吗?怎么可能这样呢?

时间:2010-04-09 18:57:38

标签: django django-models django-authentication

auth_user上运行alter table以使usernamevarchar(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"))

或者该字段是否还有其他验证需要更改或其他任何后果?

请参阅以下有关bartek的评论讨论。

编辑:经过几个月的回顾。对于不了解前提的人:某些应用程序没有要求或希望使用用户名,他们只使用电子邮件进行注册。 AUTH。不幸的是,在django auth.contrib中,用户名是必需的。您可以开始在用户名字段中添加电子邮件,但该字段只有30个字符,而现实世界中的电子邮件可能很长。可能比这里建议的75个字符更长,但75个字符可以容纳最理智的电子邮件地址。问题针对的是这种情况,正如基于电子邮件验证的应用程序所遇到的那样。

13 个答案:

答案 0 :(得分:78)

有一种方法可以在不触及核心模型的情况下实现这一目标,并且没有继承,但它肯定是hackish,我会特别小心地使用它。

如果你看一下Django的文档on signals,你会看到有一个名为class_prepared,它基本上是在元类创建任何实际模型类后发送的。那个时刻是你在任何魔法发生之前修改任何模型的最后机会(即:ModelFormModelAdminsyncdb等......)。 / p>

因此计划很简单,您只需使用处理程序注册该信号,该处理程序将检测何时为User模型调用它,然后更改max_length的{​​{1}}属性字段。

现在问题是,这段代码应该在哪里生活?它必须在加载username模型之前执行,因此通常意味着很早。不幸的是,您不能(django 1.1.1 ,未检查其他版本)将其放在User中,因为导入settings会导致内容破坏。

更好的选择是将它放在虚拟应用程序的模型模块中,并将该应用程序放在signals列表/元组之上(因此它会在其他任何内容之前导入)。以下是您在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) ,以反映新的最大长度
  • 如果您想使用自动管理员,您必须继承help_textUserChangeFormUserCreationForm,因为最大长度不是从模型字段中推断出来的,而是直接在表格字段声明。

如果您正在使用South,则可以创建以下迁移以更改基础数据库中的列:

AuthenticationForm

答案 1 :(得分:25)

根据Clément和Matt Miller的上述综合答案,我汇集了一个实现它的快速应用程序。 Pip安装,迁移和转发。将此作为评论,但还没有信誉!

https://github.com/GoodCloud/django-longer-username

编辑2014-12-08

现已弃用上述模块,转而使用https://github.com/madssj/django-longer-username-and-email

答案 2 :(得分:21)

更新了Django 1.3版本的解决方案(无需修改manage.py):

创建新的django-app:

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()

答案 3 :(得分:5)

上述解决方案似乎确实更新了模型长度。但是,要在管理员中反映您的自定义长度,您还需要覆盖管理表单(令人沮丧的是,它们不会简单地从模型继承长度)。

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))

答案 4 :(得分:2)

据我所知,自Django 1.5以来可以override user model解决问题。简单示例here

答案 5 :(得分:1)

如果您只是修改数据库表,您仍然需要处理Django的验证,所以它不会让你制作一个超过30个字符。 此外,用户名验证,以便它不能具有像@这样的特殊字符,所以简单地修改字段的长度无论如何都不会起作用。我的不好,看起来就像处理那样。这是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"))

创建电子邮件身份验证并不难。这是你可以使用的super simple email auth backend。您需要做的就是添加一些验证以确保电子邮件地址是唯一的并且您已完成。这很容易。

答案 6 :(得分:1)

是的,可以做到。至少我认为这应该有效;我最终取代了整个auth模型,所以如果不能解决这个问题我准备好了......

如果您没有关注的用户记录:

  1. 删除auth_user表
  2. 在模型中将用户名更改为max_length = 75
  3. 执行syncdb
  4. 如果您有用户记录需要保留,那么它会更复杂,因为您需要以某种方式迁移它们。最简单的是从旧表到新表的备份和恢复数据,如:

    1. 备份用户表数据
    2. 放下桌子
    3. 执行syncdb
    4. 将用户数据重新导入新表;注意恢复原始id值
    5. 或者,使用您的mad python-django skillz,将用户模型实例从old复制到new并替换:

      1. 创建自定义模型并暂时将其与默认模型放在一起
      2. 编写一个脚本,将实例从默认模型复制到新模型
      3. 使用自定义模型替换默认模型
      4. 后者并不像听起来那么难,但显然需要做更多的工作。

答案 7 :(得分:1)

从根本上说,问题是有些人想要使用电子邮件地址作为唯一标识符,而Django中的用户身份验证系统需要最多30个字符的唯一用户名。也许这将在未来发生变化,但正如我正在写的那样,Django 1.3也是如此。

我们知道许多电子邮件地址的30个字符太短;即使75个字符也不足以代表某些电子邮件地址,如What is the optimal length for an email address in a database?中所述。

我喜欢简单的解决方案,因此我建议将电子邮件地址散列为符合Django中用户名限制的用户名。根据{{​​3}},用户名必须最多为30个字符,由字母数字字符和_,@,+ ,.组成。和 - 。因此,如果我们使用base-64编码并仔细替换特殊字符,我们最多可以使用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('=', '')

简而言之,此功能会关联任何电子邮件地址的用户名。我知道哈希函数中存在很小的碰撞概率,但在大多数应用程序中这不应该是一个问题。

答案 8 :(得分:0)

只需在settings.py

的底部添加以下代码即可
from django.contrib.auth.models import User
User._meta.get_field("username").max_length = 75

答案 9 :(得分:0)

C:... \ venv \ Lib \ site-packages \ django \ contrib \ auth \ models.py

first_name = models.CharField(_('first'name'),max_length = 30,blank = True)

更改为

first_name = models.CharField(_('first'name'),max_length = 75,blank = True)

保存

并更改数据库

答案 10 :(得分:-1)

我正在使用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'

答案 11 :(得分:-2)

最佳解决方案是使用电子邮件字段添加电子邮件和用户名。

在输入登录表单验证中,查找数据是用户名还是电子邮件,如果是电子邮件,请查询电子邮件字段。

这只需要猴子修补contrib.auth.forms.login_form,这是相应视图中的几行。

它比尝试修改模型和数据库表要好得多。

答案 12 :(得分:-2)

如果您使用的是venv(虚拟环境),最简单的解决方案可能就是直接更新核心代码,即打开以下两个文件: - - venv / lib / python2.7 / sites-packages / django / contrib / auth / model.py - venv / lib / python2.7 / sites-packages / django / contrib / auth / forms.py 搜索所有用户名字段并将max_length从30更改为100.这是安全的,因为您已经在使用venv,因此它不会影响任何其他Django项目。