web-dev-qa-db-ja.com

Djangoのauth_user.usernameをvarchar(75)にすることはできますか?どうすればそれができますか?

_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文字でほとんどの健全なメールアドレスに対応できます。

65
Purrell

コアモデルに触れたり継承したりせずにそれを実現する方法はありますが、それは間違いなくハックであり、細心の注意を払って使用します。

Djangoのドキュメント 信号 を見ると、class_preparedと呼ばれるものがあり、これは基本的に、メタクラスによって実際のモデルクラスが作成されると送信されます。その瞬間は、magicが発生する前にモデルを変更する最後のチャンスです(つまり、ModelFormModelAdminsyncdbなど...)。

そのため、計画は単純です。Userモデルに対して呼び出されたときにそれを検出するハンドラーにその信号を登録し、usernameフィールドのmax_lengthプロパティを変更するだけです。

さて、問題は、このコードはどこにあるのでしょうか?これは、Userモデルがロードされる前に実行する必要があるため、多くの場合、非常に早いを意味します。残念ながら、(Django1.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 __and __module__
    if sender.__== "User" and sender.__module__ == "Django.contrib.auth.models":
        sender._meta.get_field("username").max_length = 75

class_prepared.connect(longer_username)

これでうまくいきます。

ただし、いくつかのメモ:

  • 新しい最大長を反映するために、フィールドのhelp_textも変更することができます
  • 自動管理を使用する場合、最大長はモデルフィールドからではなく、フォームフィールド宣言で直接推定されるため、UserChangeFormUserCreationFormAuthenticationFormをサブクラス化する必要があります。

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
78
Clément

上記のクレメントとマットミラーの素晴らしい組み合わせの回答に基づいて、それを実装する簡単なアプリをまとめました。 Pipインストール、移行、そして実行。これをコメントとして入れますが、まだ信用がありません!

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

EDIT 2014-12-08

上記のモジュールは https://github.com/madssj/Django-longer-username-and-email のために廃止されました

25
skoczen

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

上記のソリューションは、モデルの長さを更新するようです。ただし、カスタムの長さを管理者に反映するには、管理者フォームもオーバーライドする必要があります(イライラすることに、モデルから単に長さを継承するわけではありません)。

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
Cerin

私が知る限り、 ユーザーモデルを上書き Django 1.5なので問題を解決します。簡単な例 ここ

2

データベーステーブルを単に変更する場合でも、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 です。その後、メールアドレスが一意であることを確認するための検証を追加する必要があります。簡単です。

1
Bartek

はい、できます。少なくともこれでうまくいくと思います。私は認証モデル全体を交換するので、これがうまくいかない場合は修正する準備ができています...

気になるユーザーレコードがない場合:

  1. auth_userテーブルを削除する
  2. モデルのユーザー名をmax_length = 75に変更します
  3. syncdb

保持する必要があるユーザーレコードがある場合、何らかの方法でそれらを移行する必要があるため、さらに複雑になります。最も簡単なのは、次のような古いテーブルから新しいテーブルへのデータのバックアップと復元です。

  1. ユーザーテーブルデータのバックアップ
  2. テーブルを落とす
  3. syncdb
  4. ユーザーデータを新しいテーブルに再インポートします。元のID値を復元するように注意する

または、mad python-Django skillzを使用して、ユーザーモデルインスタンスを古いものから新しいものにコピーして置き換えます。

  1. カスタムモデルを作成し、一時的にデフォルトモデルのそばに置きます
  2. デフォルトのモデルから新しいモデルにインスタンスをコピーするスクリプトを記述します
  3. デフォルトモデルをカスタムモデルに置き換える

後者は思ったほど難しくはありませんが、明らかにもう少し作業が必要です。

1
John Mee

基本的に、問題は、一意の識別子として電子メールアドレスを使用したいという人がいる一方で、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('=', '')

つまり、この関数は任意のメールアドレスにユーザー名を関連付けます。ハッシュ関数での衝突の可能性はわずかであることは承知していますが、これはほとんどのアプリケーションで問題にはなりません。

1
Greg Glockner

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)

セーブ

データベースの変更

Settings.pyの下部に以下のコードを追加するだけです

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