_auth_user
_でalter tableを実行して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文字でほとんどの健全なメールアドレスに対応できます。
コアモデルに触れたり継承したりせずにそれを実現する方法はありますが、それは間違いなくハックであり、細心の注意を払って使用します。
Djangoのドキュメント 信号 を見ると、class_prepared
と呼ばれるものがあり、これは基本的に、メタクラスによって実際のモデルクラスが作成されると送信されます。その瞬間は、magicが発生する前にモデルを変更する最後のチャンスです(つまり、ModelForm
、ModelAdmin
、syncdb
など...)。
そのため、計画は単純です。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
も変更することができます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
上記のクレメントとマットミラーの素晴らしい組み合わせの回答に基づいて、それを実装する簡単なアプリをまとめました。 Pipインストール、移行、そして実行。これをコメントとして入れますが、まだ信用がありません!
https://github.com/GoodCloud/Django-longer-username
EDIT 2014-12-08
上記のモジュールは https://github.com/madssj/Django-longer-username-and-email のために廃止されました
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()
上記のソリューションは、モデルの長さを更新するようです。ただし、カスタムの長さを管理者に反映するには、管理者フォームもオーバーライドする必要があります(イライラすることに、モデルから単に長さを継承するわけではありません)。
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))
私が知る限り、 ユーザーモデルを上書き Django 1.5なので問題を解決します。簡単な例 ここ
データベーステーブルを単に変更する場合でも、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 です。その後、メールアドレスが一意であることを確認するための検証を追加する必要があります。簡単です。
はい、できます。少なくともこれでうまくいくと思います。私は認証モデル全体を交換するので、これがうまくいかない場合は修正する準備ができています...
気になるユーザーレコードがない場合:
保持する必要があるユーザーレコードがある場合、何らかの方法でそれらを移行する必要があるため、さらに複雑になります。最も簡単なのは、次のような古いテーブルから新しいテーブルへのデータのバックアップと復元です。
または、mad python-Django skillzを使用して、ユーザーモデルインスタンスを古いものから新しいものにコピーして置き換えます。
後者は思ったほど難しくはありませんが、明らかにもう少し作業が必要です。
基本的に、問題は、一意の識別子として電子メールアドレスを使用したいという人がいる一方で、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('=', '')
つまり、この関数は任意のメールアドレスにユーザー名を関連付けます。ハッシュ関数での衝突の可能性はわずかであることは承知していますが、これはほとんどのアプリケーションで問題にはなりません。
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