web-dev-qa-db-ja.com

Django=

電子メールフィールドエントリが一意であることを確認して、contrib.authの標準ユーザーモデルにパッチを適用する必要があります。

User._meta.fields[4].unique = True

それを行うのに最適なコードの場所はどこですか?

数字fields [4]の使用を避けたい。 fields ['email']を使用する方が適切ですが、fieldsは辞書ではなく、リストのみです。

別のアイデアは、新しいチケットを開き、settings.py内に新しいパラメーターを含むパッチをアップロードすることです。

AUTH_USER_EMAIL_UNIQUE = True

Djangoユーザーモデルで電子メールアドレスの一意性を実現する最も正しい方法に関する提案はありますか?

61
ramusus

驚くべきことですが、私にとって最適なソリューションを見つけました!

Django-registrationには、メールフィールドの一意性をチェックするフォームがあります:RegistrationFormUniqueEmail

使用例 here

15
ramusus

注意:以下のコードは、古いバージョンの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_メソッドにマルチフィールド検証を配置しても問題ないと思います。これを行うので、検証エラーはフォームではなくフィールド自体に関連付けられます。

50
elo80ka

unique_together 「異なる」方法で?これまでのところ、それは私のために動作します。

class User(AbstractUser):
    ...
    class Meta(object):
        unique_together = ('email',)
35
eillarra

設定モジュールで:

# 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
16
jdavidls

フォームは次のようになります。

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
8
Alan Viars

任意のアプリのmodels.pyで以下のコードを使用するだけです

from Django.contrib.auth.models import User
User._meta.get_field('email')._unique = True
6
Nids Barthwal

ユーザーがどこにいても一意のメールで保存されるようにするには、これをモデルに追加します。

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

これにより、非空白の電子メールも保証されることに注意してください。ただし、これは適切なフォーム検証を行わず、例外を発生させます。

6
zVictor

Djangoには、カスタムユーザーモデルを置換して使用する方法に関するドキュメントに 完全な例 があります。したがって、フィールドを追加し、ユーザー名としてメールを使用できます。

バージョン1.2(2015年5月11日)以降、設定オプションREGISTRATION_FORMを使用して、選択した登録フォームを動的にインポートする方法があります。

したがって、次のようなものを使用できます。

REGISTRATION_FORM = 'registration.forms.RegistrationFormUniqueEmail'

これは文書化されています here

そして、ここに changelog entry へのリンクがあります。

2
bonidjukic

正解は、一意性チェックがデータベース内に置かれている(Django側ではなく)ことを保証すると思います。たとえばpre_save適切なチェックを行います。

これが本当に必要な場合は、次のアプローチを試してみてください。

  1. ユーザーモデルを独自のアプリにコピーし、フィールドメールを一意に変更します。
  2. このユーザーモデルを管理アプリに登録します(Django.contrib.auth.admin
  3. Django one。の代わりにモデルを使用する独自の認証バックエンドを作成します。
2
jb.

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

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
2
nikhil patil

この方法では、データベースレベルで電子メールフィールドを一意にすることはできませんが、試してみる価値はあります。

カスタム 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])
    #....
2
user476955

これを実行する1つの方法は、Userオブジェクトに事前保存フックを設定し、テーブルに既に存在する電子メールの保存を拒否することです。

2
Parag

これをどこかに追加してください:

User._meta.get_field_by_name('email')[0]._unique = True     

次に、次のようなSQLを実行します。

ALTER TABLE auth_user ADD UNIQUE (email);
1

この目的のために、独自のカスタムユーザーモデルを使用できます。ユーザー名として電子メールを使用するか、ユーザー名として電話を使用できます。複数の属性を持つことができます。

Settings.pyで、以下の設定を指定する必要がありますAUTH_USER_MODEL = 'myapp.MyUser'。

ここにあなたを助けることができるリンクがあります。 https://docs.djangoproject.com/en/1.8/topics/auth/customizing/#auth-custom-user

0
user2772346