django-allauthを使用するときにユーザープロファイルをカスタマイズする方法


107

私はdjango-allauthアプリを使ったdjangoプロジェクトを持っています。サインアップ時にユーザーから追加のデータを収集する必要があります。ここで同様の質問に出くわしました が、残念ながら、プロファイルのカスタマイズ部分には誰も答えませんでした。

提供されたドキュメントにdjango-allauthよる

ACCOUNT_SIGNUP_FORM_CLASS(= None

‘myapp.forms.SignupForm’ユーザーが追加の入力(例:ニュースレターのサインアップ、生年月日)を要求するためにサインアップ中に使用されるカスタムフォームクラス(例:)を指す文字列。このクラスは‘save’メソッドを実装し、新しくサインアップしたユーザーを唯一のパラメーターとして受け入れます。

私はジャンゴが初めてで、これに苦労しています。誰かがそのようなカスタムフォームクラスの例を提供できますか?このようなユーザーオブジェクトへのリンクを含むモデルクラスも追加する必要があり ますか?

回答:


170

サインアップ時にユーザーに姓名の入力を求めたいとします。次のように、これらのフィールドを独自のフォームに配置する必要があります。

class SignupForm(forms.Form):
    first_name = forms.CharField(max_length=30, label='Voornaam')
    last_name = forms.CharField(max_length=30, label='Achternaam')

    def signup(self, request, user):
        user.first_name = self.cleaned_data['first_name']
        user.last_name = self.cleaned_data['last_name']
        user.save()

次に、設定でこのフォームをポイントします。

ACCOUNT_SIGNUP_FORM_CLASS = 'yourproject.yourapp.forms.SignupForm'

それで全部です。


10
ありがとう。原作者からの連絡をお待ちしております:)。この情報を保存する追加のクラスを作成する必要がありますか、それともallauthが自動的に処理しますか?
Shreyas 2012

12
それは実際にあなたが尋ねている情報に依存します。いずれにせよ、これはallauthスコープを超えています。上記の例のように姓名を尋ねる場合、追加のモデルは必要なく、直接Userモデルに配置できます。ユーザーの生年月日、お気に入りの色などを尋ねる場合は、このために独自のプロファイルモデルをセットアップする必要があります。:ここでこれを行う方法について見て下さいdocs.djangoproject.com/en/dev/topics/auth/...を
pennersr

6
それがまさに私が探していたものです-お気に入りの色のような追加のフィールド。好きな色、たとえば好きな色の場合は、新しいUserProfileクラスを作成してから、ユーザーを1対1フィールドとして使用し、好きな色を追加フィールドとして使用する必要があると思います。その場合、上記で宣言した(好きな色で)タイプのSignUpFormを引き続き使用して、ACCOUNT_SIGNUP_FORM_CLASSをフックすることができますか、それともフォームを作成して自分のコードでデータの保存を処理する必要がありますか?
Shreyas 2012

4
もちろん、ACCOUNT_SIGNUP_FORM_CLASSメカニズムは引き続き使用できます。save()メソッドが適切に実装されていることを確認するだけで、好きな色が好きなモデルに保存されます。
pennersr 2012

5
@pennersr- ACCOUNT_SIGNUP_FORM_CLASS最初のソーシャルサインインの後で、カスタムユーザーモデルフィールドを収集して保存するために、これをどのように調整できますか?また、AUTH_USER_MODELgitからの変更によるカスタムユーザーモデルの使用:github.com/pennersr/django-allauthはpypiにアップロードされません。
Babu

23

pennersrによって提案されたソリューションを使用して、DeprecationWarningを取得していました:

DeprecationWarning: The custom signup form must offer a def signup(self, request, user) method DeprecationWarning)

これは、バージョン0.15以降、def signup(request、user)メソッドに代わり、saveメソッドが廃止されたためです。

したがって、これを解決するには、例のコードは次のようになります。

class SignupForm(forms.Form):
    first_name = forms.CharField(max_length=30, label='Voornaam')
    last_name = forms.CharField(max_length=30, label='Achternaam')

    def signup(self, request, user):
        user.first_name = self.cleaned_data['first_name']
        user.last_name = self.cleaned_data['last_name']
        user.save()

2
@pennsesrの回答がのsignup代わりに使用するように編集されましたsave
Flimm

18

他のいくつかの回答を組み合わせた場合の効果は次のとおりです(100%完全で、DRYはありません)

yourapp/forms.py

from django.contrib.auth import get_user_model
from django import forms

class SignupForm(forms.ModelForm):
    class Meta:
        model = get_user_model()
        fields = ['first_name', 'last_name']

    def signup(self, request, user):
        user.first_name = self.cleaned_data['first_name']
        user.last_name = self.cleaned_data['last_name']
        user.save()

そしてでsettings.py

ACCOUNT_SIGNUP_FORM_CLASS = 'yourapp.forms.SignupForm'

このように、モデルフォームを使用してDRYにし、新しいを使用しdef signupます。入れてみ'myproject.myapp.forms.SignupForm'ましたがなんとかエラーになりました。


'myproject.myapp.forms.SignupForm'の代わりに 'yourapp.forms.SignupForm'を使用することもできました
alpalalpal

6

@Shreyas:以下の解決策は最もクリーンではないかもしれませんが、機能します。さらにクリーンアップするための提案がある場合はお知らせください。

デフォルトのユーザープロファイルに属さない情報を追加するには、最初にyourapp / models.pyにモデルを作成します。詳細については、一般的なdjangoのドキュメントをご覧ください。ただし、基本的には次のとおりです。

from django.db import models

class UserProfile(models.Model):
    user = models.OneToOneField(User, related_name='profile')
    organisation = models.CharField(organisation, max_length=100, blank=True)

次に、yourapp / forms.pyにフォームを作成します。

from django import forms

class SignupForm(forms.Form):
    first_name = forms.CharField(max_length=30, label='Voornaam')
    last_name = forms.CharField(max_length=30, label='Achternaam')
    organisation = forms.CharField(max_length=20, label='organisation')

    def signup(self, request, user):
        user.first_name = self.cleaned_data['first_name']
        user.last_name = self.cleaned_data['last_name']
        # Replace 'profile' below with the related_name on the OneToOneField linking back to the User model
        up = user.profile
        up.organisation = self.cleaned_data['organisation']
        user.save()
        up.save()

これが、Wagtail CMSを実行しているDjango 2.0アプリで使用することになりました。定期的なサインアップで機能しましたが、Social Authではそれほどではないようです。
Kalob Taulien

Wagtailのユーザーの管理ページにこの追加フィールドをどのように追加しますか?
ジョシュア

5

あなたにはusers/forms.py、あなたは置きます:

from django.contrib.auth import get_user_model
class SignupForm(forms.ModelForm):
    class Meta:
        model = get_user_model()
        fields = ['first_name', 'last_name']
    def save(self, user):
        user.save()

settings.pyに次のように記述します。

ACCOUNT_SIGNUP_FORM_CLASS = 'users.forms.SignupForm'

このように、多重度のユーザーモデルフィールド定義によってDRY原則を破ることはありません。


4

私は多くの異なるチュートリアルを試しましたが、それらのすべてに何かが足りない、不要なコードを繰り返す、または奇妙なことをしている、以下は私の見つけたすべてのオプションを結合する私のソリューションに従います、それは機能していますフォーム内にプロファイルを作成しないようにするために、Usersに作成した関数内でfirst_nameとlast_nameを受け取ることを期待しているので、それでも私は納得できません。

Models.py

class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    bio = models.TextField(max_length=500, blank=True)
    nationality = models.CharField(max_length=2, choices=COUNTRIES)
    gender = models.CharField(max_length=1, choices=GENDERS)

def __str__(self):
    return self.user.first_name


@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
    if created:
        Profile.objects.create(user=instance)

@receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
    instance.profile.save()

Forms.py

class SignupForm(forms.ModelForm):
    first_name = forms.CharField(max_length=100)
    last_name = forms.CharField(max_length=100)

    class Meta:
        model = Profile
        fields = ('first_name', 'last_name', 'nationality', 'gender')

    def signup(self, request, user):
        # Save your user
        user.first_name = self.cleaned_data['first_name']
        user.last_name = self.cleaned_data['last_name']
        user.save()

        user.profile.nationality = self.cleaned_data['nationality']
        user.profile.gender = self.cleaned_data['gender']
        user.profile.save()

Settings.py

ACCOUNT_SIGNUP_FORM_CLASS = 'apps.profile.forms.SignupForm'

皮肉なことに、これにはいくつか欠けているものもあります。プロファイルフィールドにはデフォルトがなく、nullも許可されていないため、create_user_profile信号は意図的に失敗します。第2にcreated、特にDRYの場合は、これをに基づいて1つの信号に減らすことができます。3番目に、ビューでuser.save()を呼び出してプロファイルを保存し、実際のデータでプロファイルを再度保存します。
Melvyn 2017

@Melvyn万一それができないfields = [...]角括弧の代わりにfields = (...) 括弧?
Ahtisham

できますが、そうである必要はありません。これは、モデルのフィールドがフォームの一部であるかどうかを確認するために読み取り専用でのみ使用されます。したがって、リスト、タプル、セット、またはそれらの派生物にすることができます。タプルは変更できないため、タプルを使用して偶発的な変異を防ぐ方が理にかなっています。パフォーマンスの観点からは、これらのコレクションは実際には小さすぎて影響を与えられません。コレクションが長くなりすぎた場合は、exclude代わりに切り替えることは理にかなっています。
メルビン2018年

0
#models.py

from django.conf import settings

class UserProfile(models.Model):
    user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    image = models.ImageField(default='users/default.png', upload_to='users')
    fields = models.ForeignKey('Field' ,null=True ,on_delete=models.SET_NULL)
    category = models.ForeignKey('Category' ,null=True ,on_delete=models.SET_NULL)
    description = models.TextField()
    interests = models.ManyToManyField('Interests')

    ...

   def save(self, *args, **kwargs):
       super().save(*args, **kwargs)

...

def userprofile_receiver(sender, instance, created, *args, **kwargs):
    if created:
        userprofile = UserProfile.objects.create(user=instance)
    else:
        instance.userprofile.save()

post_save.connect(userprofile_receiver, sender=settings.AUTH_USER_MODEL)



 #forms.py

 class SignupForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super(SignupForm, self).__init__(*args, **kwargs)
        self.fields['first_name'].widget = forms.TextInput(attrs={'placeholder': 'Enter first name'})
        self.fields['last_name'].widget = forms.TextInput(attrs={'placeholder': 'Enter last name'})

    first_name = forms.CharField(max_length=100)
    last_name = forms.CharField(max_length=100)

    interests  = forms.ModelMultipleChoiceField(widget=forms.CheckboxSelectMultiple, help_text="Choose your interests", queryset=Interests.objects.all())

    image = forms.ImageField(help_text="Upload profile image ")
    fields = forms.ChoiceField(help_text="Choose your fields ")
    category = forms.ChoiceField(help_text="Choose your category")

    class Meta:
        model = UserProfile
        fields = ('first_name', 'last_name',  'name', 'image', 'fields', 'category', 'description', 'phone', 'facebook', 'twitter', 'skype', 'site', 'address', 'interests' ,'biography')
        widgets = {
             ...
            'description': forms.TextInput(attrs={'placeholder': 'Your description'}),
            'address': forms.TextInput(attrs={'placeholder': 'Enter address'}),
            'biography': forms.TextInput(attrs={'placeholder': 'Enter biography'}),
            ....
    }
    def signup(self, request, user):
        # Save your user
        user.first_name = self.cleaned_data['first_name']
        user.last_name = self.cleaned_data['last_name']
        user.save()

        user.userprofile.image = self.cleaned_data.get('image')
        user.userprofile.fields = self.cleaned_data['fields']
        user.userprofile.category = self.cleaned_data['category']
        user.userprofile.description = self.cleaned_data['description']
        interests = self.cleaned_data['interests']
        user.userprofile.interests.set(interests)
        user.userprofile.save()


# settings.py or base.py

ACCOUNT_SIGNUP_FORM_CLASS = 'nameApp.forms.SignupForm'

それだ。(:


-10

ユーザーをOneToOneFieldとしてプロファイルモデルを作成する

class Profile(models.Model):
    user = models.OneToOneField(User, verbose_name=_('user'), related_name='profiles')
    first_name=models.CharField(_("First Name"), max_length=150)
    last_name=models.CharField(_("Last Name"), max_length=150)
    mugshot = ImageField(_('mugshot'), upload_to = upload_to, blank=True)
    phone= models.CharField(_("Phone Number"), max_length=100)
    security_question = models.ForeignKey(SecurityQuestion, related_name='security_question')
    answer=models.CharField(_("Answer"), max_length=200)
    recovery_number= models.CharField(_("Recovery Mobile Number"), max_length=100)
    city=models.ForeignKey(City,related_name='city', blank=True, null=True, help_text=_('Select your City'))
    location=models.ForeignKey(Country,related_name='location', blank=True, null=True, help_text=_('Select your Location'))

3
ありがとう。でも、これだけで十分だとは思いません。私の質問は、特にallauthアプリに関するものです。
Shreyas 2012
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.