65

运行 alter tableauth_user以使其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"))

或者在这个领域是否有其他验证需要更改或这样做会产生任何其他影响?

有关这样做的原因,请参阅下面与 bartek 的评论讨论。

编辑:几个月后回顾这一点。对于不知道前提的人:一些应用程序没有要求或不希望使用用户名,它们仅使用电子邮件进行注册和身份验证。不幸的是,在 django auth.contrib 中,用户名是必需的。您可以开始将电子邮件放在用户名字段中,但该字段只有 30 个字符,并且电子邮件在现实世界中可能很长。可能比这里建议的 75 字符更长,但 75 字符可容纳大多数正常的电子邮件地址。该问题针对的是基于电子邮件身份验证的应用程序遇到的这种情况。

4

13 回答 13

78

有一种方法可以在不触及核心模型和继承的情况下实现这一点,但这绝对是 hackish,我会格外小心地使用它。

如果您查看 Django 的有关信号的文档,您会看到一个称为的文档class_prepared,它基本上是在元类创建任何实际模型类后发送的。那一刻是您在任何魔法发生之前修改任何模型的最后机会(即: ModelFormModelAdminsyncdb等...)。

所以计划很简单,您只需将该信号注册到一个处理程序,该处理程序将检测何时为User模型调用它,然后更改该字段的max_length属性。username

现在的问题是,这段代码应该放在哪里?它必须在User模型加载之前执行,所以这通常意味着非常早。不幸的是,你不能(django 1.1.1,还没有检查另一个版本)把它放进去,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_text字段的,以反映新的最大长度
  • 如果要使用自动管理,则必须进行子类化UserChangeFormUserCreationForm并且AuthenticationForm最大长度不是从模型字段中推导出来的,而是直接在表单字段声明中。

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

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
于 2010-04-10T12:39:12.390 回答
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

于 2011-07-28T01:36:55.397 回答
21

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

创建新的 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()
于 2011-06-23T11:34:51.617 回答
5

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

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))
于 2012-10-12T20:31:56.110 回答
2

据我所知,自 Django 1.5 以来可以覆盖用户模型,这将解决一个问题。简单的例子在这里

于 2013-03-25T08:34:55.030 回答
1

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

我们知道 30 个字符对于许多电子邮件地址来说太短了;甚至 75 个字符也不足以表示某些电子邮件地址,如数据库中电子邮件地址的最佳长度是多少?.

我喜欢简单的解决方案,因此我建议将电子邮件地址散列为符合 Django 中用户名限制的用户名。根据Django中的用户身份验证,用户名最多只能包含 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('=', '')

简而言之,此函数将用户名关联到任何电子邮件地址。我知道哈希函数中发生冲突的可能性很小,但这在大多数应用程序中应该不是问题。

于 2012-03-09T19:07:31.270 回答
1

是的,这是可以做到的。至少我认为这应该可行;我最终更换了整个 auth 模型,所以如果这不起作用,我准备好进行更正......

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

  1. 删除 auth_user 表
  2. 在模型中将用户名更改为 max_length=75
  3. 同步数据库

如果您有需要保留的用户记录,那么它会更复杂,因为您需要以某种方式迁移它们。最简单的是将数据从旧表备份和恢复到新表,例如:

  1. 备份用户表数据
  2. 放下桌子
  3. 同步数据库
  4. 将用户数据重新导入新表;注意恢复原始 id 值

或者,使用您的 mad python-django Skillz,将用户模型实例从旧复制到新并替换​​:

  1. 创建您的自定义模型并将其临时放置在默认模型旁边
  2. 编写一个脚本,将实例从默认模型复制到新模型
  3. 用您的自定义模型替换默认模型

后者并不像听起来那么难,但显然需要更多的工作。

于 2010-04-10T09:04:14.260 回答
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"))

创建电子邮件身份验证并不难。这是您可以使用的超级简单的电子邮件身份验证后端。之后您需要做的就是添加一些验证以确保电子邮件地址是唯一的,然后您就完成了。就这么简单。

于 2010-04-09T19:14:32.577 回答
0

只需在 settings.py 底部添加以下代码

from django.contrib.auth.models import User
User._meta.get_field("username").max_length = 75
于 2013-05-23T03:38:57.767 回答
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)

节省

并在数据库中更改

于 2018-07-30T12:50:45.357 回答
-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'
于 2014-05-13T11:05:38.847 回答
-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 项目。

于 2013-01-07T05:09:06.730 回答
-3

最好的解决方案是使用电子邮件字段作为电子邮件,使用用户名作为用户名。

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

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

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

于 2010-04-11T07:32:04.720 回答