電子メールフィールドエントリが一意であることを確認して、contrib.auth
の標準ユーザーモデルにパッチを適用する必要があります。
User._meta.fields[4].unique = True
それを行うのに最適なコードの場所はどこですか?
数字fields [4]の使用を避けたい。 fields ['email']を使用する方が適切ですが、fieldsは辞書ではなく、リストのみです。
別のアイデアは、新しいチケットを開き、settings.py
内に新しいパラメーターを含むパッチをアップロードすることです。
AUTH_USER_EMAIL_UNIQUE = True
Djangoユーザーモデルで電子メールアドレスの一意性を実現する最も正しい方法に関する提案はありますか?
驚くべきことですが、私にとって最適なソリューションを見つけました!
Django-registrationには、メールフィールドの一意性をチェックするフォームがあります:RegistrationFormUniqueEmail
使用例 here
注意:以下のコードは、古いバージョンのDjango(before Custom User Models が導入されました。これには競合状態が含まれており、
SERIALIZABLE
のトランザクション分離レベルと要求スコープのトランザクションでのみ使用する必要があります。
フィールドインスタンスの属性は読み取り専用であるため、コードは機能しません。あなたが思っているよりもちょっと複雑かもしれないと思う。
フォームを使用してUserインスタンスのみを作成する場合、この動作を強制するカスタムModelFormを定義できます。
_from Django import forms
from Django.contrib.auth.models import User
class UserForm(forms.ModelForm):
class Meta:
model = User
def clean_email(self):
email = self.cleaned_data.get('email')
username = self.cleaned_data.get('username')
if email and User.objects.filter(email=email).exclude(username=username).exists():
raise forms.ValidationError(u'Email addresses must be unique.')
return email
_
次に、新しいユーザーを作成する必要がある場所でこのフォームを使用します。
ところで、Model._meta.get_field('field_name')
を使用して、位置ではなく名前でフィールドを取得できます。たとえば、次のとおりです。
_# The following lines are equivalent
User._meta.fields[4]
User._meta.get_field('email')
_
Django=ドキュメントでは、すべての_<FIELD>.clean
_および_<FIELD>_clean
_メソッドの後に呼び出されるため、複数のフォームフィールドにまたがるすべての検証にclean
メソッドを使用することを推奨しています。これは、clean
内から_cleaned_data
_に存在するフィールドの値に(ほとんど)依存できることを意味します。
フォームフィールドは宣言された順序で検証されるため、問題のフィールドが依存する他のすべてのフィールドの後に表示される限り、ときどき_<FIELD>_clean
_メソッドにマルチフィールド検証を配置しても問題ないと思います。これを行うので、検証エラーはフォームではなくフィールド自体に関連付けられます。
unique_together
「異なる」方法で?これまでのところ、それは私のために動作します。
class User(AbstractUser):
...
class Meta(object):
unique_together = ('email',)
設定モジュールで:
# Fix: username length is too small,email must be unique
from Django.contrib.auth.models import User, models
User._meta.local_fields[1].__dict__['max_length'] = 75
User._meta.local_fields[4].__dict__['_unique'] = True
フォームは次のようになります。
def clean_email(self):
email = self.cleaned_data.get('email')
username = self.cleaned_data.get('username')
print User.objects.filter(email=email).count()
if email and User.objects.filter(email=email).count() > 0:
raise forms.ValidationError(u'This email address is already registered.')
return email
任意のアプリのmodels.pyで以下のコードを使用するだけです
from Django.contrib.auth.models import User
User._meta.get_field('email')._unique = True
ユーザーがどこにいても一意のメールで保存されるようにするには、これをモデルに追加します。
@receiver(pre_save, sender=User)
def User_pre_save(sender, **kwargs):
email = kwargs['instance'].email
username = kwargs['instance'].username
if not email: raise ValidationError("email required")
if sender.objects.filter(email=email).exclude(username=username).count(): raise ValidationError("email needs to be unique")
これにより、非空白の電子メールも保証されることに注意してください。ただし、これは適切なフォーム検証を行わず、例外を発生させます。
Djangoには、カスタムユーザーモデルを置換して使用する方法に関するドキュメントに 完全な例 があります。したがって、フィールドを追加し、ユーザー名としてメールを使用できます。
バージョン1.2(2015年5月11日)以降、設定オプションREGISTRATION_FORM
を使用して、選択した登録フォームを動的にインポートする方法があります。
したがって、次のようなものを使用できます。
REGISTRATION_FORM = 'registration.forms.RegistrationFormUniqueEmail'
これは文書化されています here 。
そして、ここに changelog entry へのリンクがあります。
正解は、一意性チェックがデータベース内に置かれている(Django側ではなく)ことを保証すると思います。たとえばpre_save
適切なチェックを行います。
これが本当に必要な場合は、次のアプローチを試してみてください。
Django.contrib.auth.admin
)Models.pyファイルのいずれかに以下の関数を追加します。次に、makemigrationsを実行して移行します。 Django1.7でテスト済み
def set_email_as_unique():
"""
Sets the email field as unique=True in auth.User Model
"""
email_field = dict([(field.name, field) for field in MyUser._meta.fields])["email"]
setattr(email_field, '_unique', True)
#this is called here so that attribute can be set at the application load time
set_email_as_unique()
Djangoでは、ユーザーオブジェクトを直接編集することはできませんが、pre_saveシグナルを追加して、一意の電子メールを取得できます。信号を作成するために、uは https://docs.djangoproject.com/en/2.0/ref/signals/ に従うことができます。次に、以下をsignals.pyに追加します
@receiver(pre_save, sender=User)
def check_email(sender,instance,**kwargs):
try:
usr = User.objects.get(email=instance.email)
if usr.username == instance.username:
pass
else:
raise Exception('EmailExists')
except User.DoesNotExist:
pass
この方法では、データベースレベルで電子メールフィールドを一意にすることはできませんが、試してみる価値はあります。
カスタム validator を使用します。
from Django.core.exceptions import ValidationError
from Django.contrib.auth.models import User
def validate_email_unique(value):
exists = User.objects.filter(email=value)
if exists:
raise ValidationError("Email address %s already exists, must be unique" % value)
次に、forms.pyで:
from Django.contrib.auth.models import User
from Django.forms import ModelForm
from main.validators import validate_email_unique
class UserForm(ModelForm):
#....
email = forms.CharField(required=True, validators=[validate_email_unique])
#....
これを実行する1つの方法は、Userオブジェクトに事前保存フックを設定し、テーブルに既に存在する電子メールの保存を拒否することです。
これをどこかに追加してください:
User._meta.get_field_by_name('email')[0]._unique = True
次に、次のようなSQLを実行します。
ALTER TABLE auth_user ADD UNIQUE (email);
この目的のために、独自のカスタムユーザーモデルを使用できます。ユーザー名として電子メールを使用するか、ユーザー名として電話を使用できます。複数の属性を持つことができます。
Settings.pyで、以下の設定を指定する必要がありますAUTH_USER_MODEL = 'myapp.MyUser'。
ここにあなたを助けることができるリンクがあります。 https://docs.djangoproject.com/en/1.8/topics/auth/customizing/#auth-custom-user