代码之家  ›  专栏  ›  技术社区  ›  Purrell

Django的auth.user.username可以是varchar(75)吗?怎么能做到?

  •  63
  • Purrell  · 技术社区  · 16 年前

    在上运行alter table有什么问题吗 auth_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个字符可以容纳大多数健全的电子邮件地址。这个问题针对的是这种情况,就像基于电子邮件认证的应用程序遇到的那样。

    13 回复  |  直到 7 年前
        1
  •  78
  •   Matt Miller    15 年前

    有一种方法可以实现这一点,不需要触及核心模型,也不需要继承,但它绝对是黑客式的,我会格外小心地使用它。

    如果你看姜戈的医生 on signals 你会看到有一个叫 class_prepared 它基本上是在元类创建任何实际模型类之后发送的。那一刻是你修改任何模型的最后机会 魔术 发生(即: ModelForm , ModelAdmin , syncdb 等。

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

    现在的问题是,这个代码应该住在哪里?必须在 用户 模型已加载,因此通常意味着 很早 . 不幸的是,你不能 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 以反映新的最大长度
    • 如果要使用自动管理,则必须子类 UserChangeForm , UserCreationForm 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
    
        2
  •  25
  •   Jay Taylor shabeer90    11 年前

    基于上面的cl_ement和Matt Miller的综合答案,我已经开发了一个实现它的快速应用程序。PIP安装、迁移和执行。将此作为评论,但还没有可信度!

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

    编辑2014-1208

    上述模块现已弃用,取而代之的是 https://github.com/madssj/django-longer-username-and-email

        3
  •  20
  •   Rost    15 年前

    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()
    
        4
  •  5
  •   Cerin    13 年前

    上面的解决方案似乎确实更新了模型长度。但是,为了在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))
    
        5
  •  2
  •   Dmytriy Voloshyn    13 年前

    据我所知 override user model 因为django 1.5可以解决一个问题。简单实例 here

        6
  •  1
  •   Bartek    16 年前

    如果您只是修改数据库表,那么您仍然需要处理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 你可以使用。在这之后你需要做的是添加一些验证,以确保电子邮件地址是唯一的,并且你已经完成了。那很容易。

        7
  •  1
  •   John Mee    16 年前

    是的,可以。至少我认为这是可行的;我最终替换了整个auth模型,所以如果这不可行的话,我们准备好更正…

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

    1. 删除auth_用户表
    2. 在模型中将用户名更改为max_length=75
    3. 同步CDB

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

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

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

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

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

        8
  •  1
  •   Community Mohan Dere    9 年前

    从根本上讲,问题在于,有些人希望使用电子邮件地址作为唯一标识符,而Django的用户认证系统需要一个最多30个字符的唯一用户名。也许这在将来会改变,但在我写作的时候,django 1.3就是这样。

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

    我喜欢简单的解决方案,所以我建议将电子邮件地址散列为一个用户名,以适应Django中用户名的限制。根据 User authentication in 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('=', '')
    

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

        9
  •  0
  •   xiaowl    13 年前

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

    from django.contrib.auth.models import User
    User._meta.get_field("username").max_length = 75
    
        10
  •  0
  •   Рустам Зайнуллин    7 年前

    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)

    节约

    以及数据库中的更改

        11
  •  -1
  •   Crasched    12 年前

    我使用的是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'
    
        12
  •  -2
  •   lprsd    16 年前

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

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

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

    它远比修改模型和数据库表要好。

        13
  •  -2
  •   haipt    13 年前

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