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

发布于 2024-08-28 11:33:59 字数 759 浏览 8 评论 0原文

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 的评论讨论。

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

Is there anything wrong with running alter table on auth_user to make username be varchar(75) so it can fit an email? What does that break if anything?

If you were to change auth_user.username to be varchar(75) where would you need to modify django? Is it simply a matter of changing 30 to 75 in the source code?

username = models.CharField(_('username'), max_length=30, unique=True, help_text=_("Required. 30 characters or fewer. Letters, numbers and @/./+/-/_ characters"))

Or is there other validation on this field that would have to be changed or any other repercussions to doing so?

See comment discussion with bartek below regarding the reason for doing it.

Edit: Looking back on this after many months. For anyone who doesn't know the premise: Some apps don't have a requirement or desire to use a username, they use only email for registration & auth. Unfortunately in django auth.contrib, username is required. You could start putting emails in the username field, but the field is only 30 char and emails may be long in the real world. Potentially even longer than the 75 char suggested here, but 75 char accommodates most sane email addresses. The question is aimed at this situation, as encountered by email-auth-based applications.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(13

愛上了 2024-09-04 11:33:59

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

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

因此计划很简单,您只需向处理程序注册该信号,该处理程序将检测何时为 User 模型调用该信号,然后更改 max_length 属性>用户名字段。

现在的问题是,这段代码应该放在哪里?它必须在加载 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,以反映新的最大长度
  • 如果您想使用自动管理,则必须子类化 UserChangeForm、UserCreationFormAuthenticationForm 的最大长度不是从模型字段推导出来的,而是直接在表单字段声明中推导出来的。

如果您使用 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

There's a way to achieve that without touching the core model, and without inheritance, but it's definitely hackish and I would use it with extra care.

If you look at Django's doc on signals, you'll see there's one called class_prepared, which is basically sent once any actual model class has been created by the metaclass. That moment is your last chance of modifying any model before any magic takes place (ie: ModelForm, ModelAdmin, syncdb, etc...).

So the plan is simple, you just register that signal with a handler that will detect when it is called for the User model, and then change the max_length property of the username field.

Now the question is, where should this code lives? It has to be executed before the User model is loaded, so that often means very early. Unfortunately, you can't (django 1.1.1, haven't check with another version) put that in settings because importing signals there will break things.

A better choice would be to put it in a dummy app's models module, and to put that app on top of the INSTALLED_APPS list/tuple (so it gets imported before anything else). Here is an example of what you can have in 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)

That will do the trick.

A few notes though:

  • You might want to change also the help_text of the field, to reflect the new maximum length
  • If you want to use the automatic admin, you will have to subclass UserChangeForm, UserCreationForm and AuthenticationForm as the maximum length is not deduced from the model field, but directly in the form field declaration.

If you're using South, you can create the following migration to change the column in the underlying database:

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
风和你 2024-09-04 11:33:59

根据上面克莱门特和马特·米勒的出色综合答案,我整理了一个实现它的快速应用程序。 Pip 安装、迁移并运行。会将其作为评论,但还没有信誉!

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

编辑2014-12-08

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

Based on Clément and Matt Miller's great combined answer above, I've pulled together a quick app that implements it. Pip install, migrate, and go. Would put this as a comment, but don't have the cred yet!

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

EDIT 2014-12-08

The above module is now deprecated in favor of https://github.com/madssj/django-longer-username-and-email

述情 2024-09-04 11:33:59

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

Updated solution for the Django 1.3 version (without modifying manage.py):

Create new django-app:

monkey_patch/
    __init__.py
    models.py

Install it as first: (settings.py)

INSTALLED_APPS = (
    'monkey_patch', 
    #...
)

Here is 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()
网名女生简单气质 2024-09-04 11:33:59

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

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

The solutions above do seem to update the model length. However, to reflect your custom length in admin, you also need to override the admin forms (frustratingly, they don't simply inherit the length from the model).

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))
一个人的旅程 2024-09-04 11:33:59

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

As far as I know one can override user model since Django 1.5 which will solve a problem. Simple example here

朮生 2024-09-04 11:33:59

如果你只是修改数据库表,你仍然需要处理 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"))

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

If you simply modify the database table, you'll still have to deal with Django's validation, so it won't let you make one over 30 characters anyways. Additionally, the username validates so that it can't have special characters like @ so simply modifying the length of the field wouldn't work anyways. My bad, looks like it handles that. Here's the username field from models.py in django.contrib.auth:

username = models.CharField(_('username'), max_length=30, unique=True, help_text=_("Required. 30 characters or fewer. Letters, numbers and @/./+/-/_ characters"))

Creating email auth is not hard. Here's a super simple email auth backend you can use. Al l you need to do after that is add some validation to ensure the email address is unique and you're done. That easy.

一花一树开 2024-09-04 11:33:59

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

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

  1. 删除 auth_user 表
  2. ,将模型
  3. 同步数据库

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

  1. 备份用户表数据,
  2. 删除表
  3. syncdb
  4. ,重新导入用户数据到新表;小心恢复原始 id 值

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

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

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

Yes, it can be done. At least I think this should work; I wound up replacing the whole auth model, so am ready to be corrected if this doesn't work out...

If you have no user records you care about:

  1. drop the auth_user table
  2. change username to max_length=75 in the model
  3. syncdb

If you have user records you need to retain then it's more complicated as you need to migrate them somehow. Easiest is backup and restore of the data from old to new table, something like:

  1. backup the user table data
  2. drop the table
  3. syncdb
  4. reimport user data to the new table; taking care to restore the original id values

Alternatively, using your mad python-django skillz, copy the user model instances from old to new and replace:

  1. create your custom model and temporarily stand it alongside the default model
  2. write a script which copies the instances from the default model to the new model
  3. replace the default model with your custom one

The latter is not as hard as it sounds, but obviously involves a bit more work.

花落人断肠 2024-09-04 11:33:59

从根本上来说,问题在于有些人想要使用电子邮件地址作为唯一标识符,而 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('=', '')

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

Fundamentally, the problem is that some people want to use an email address as the unique identifier, while the user authentication system in Django requires a unique username of at most 30 characters. Perhaps that will change in the future, but that's the case with Django 1.3 as I'm writing.

We know that 30 characters is too short for many email addresses; even 75 characters is not enough to represent some email addresses, as explained in What is the optimal length for an email address in a database?.

I like simple solutions, so I recommend hashing the email address into a username that fits the restrictions for usernames in Django. According to User authentication in Django, a username must be at most 30 characters, consisting of alphanumeric characters and _, @, +, . and -. Thus, if we use base-64 encoding with careful substitution of the special characters, we have up to 180 bits. So we can use a 160-bit hash function like SHA-1 as follows:

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('=', '')

In short, this function associates a username for any email address. I'm aware that there is a tiny probability of a collision in the hash function, but this should not be an issue in most applications.

尛丟丟 2024-09-04 11:33:59

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

from django.contrib.auth.models import User
User._meta.get_field("username").max_length = 75

Just adding the below code at the bottom of settings.py

from django.contrib.auth.models import User
User._meta.get_field("username").max_length = 75
风柔一江水 2024-09-04 11:33:59

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)

保存并更改

在数据库中

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

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

change to

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

save

and change in the database

无人问我粥可暖 2024-09-04 11:33:59

我使用的是 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'

I am using django 1.4.3 which makes it pretty easy and I did not have to change anything else in my code after realising I wanted to use long email addresses as usernames.

If you have direct access to the database, change it there to the amount of characters you would like to, in my case 100 characters.

In your app model (myapp/models.py) add the following

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)

Then in your settings.py you specify the model:

AUTH_USER_MODEL = 'myapp.UserProfile'
鹿! 2024-09-04 11:33:59

如果您使用的是 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 项目。

If you are using venv (virtual environment), the simplest solution probably is just update the core code directly, i.e. opening the following two files:
- - venv/lib/python2.7/sites-packages/django/contrib/auth/model.py
- venv/lib/python2.7/sites-packages/django/contrib/auth/forms.py
Search for all username field and change max_length from 30 to 100. It is safe since you are already using venv so it won't affect any other Django project.

初相遇 2024-09-04 11:33:59

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

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

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

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

The best solution is to use email field for email and the username for username.

In the input login form validation, find whether the data is username or the email and if email, query the email field.

This only requires monkey patching the contrib.auth.forms.login_form which is a few lines in the corresponding view.

And it is far better than trying to modify the models and the database tables.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文