django-allauth를 사용할 때 사용자 프로필을 사용자 지정하는 방법


107

django-allauth 앱이있는 django 프로젝트가 있습니다. 가입시 사용자로부터 추가 데이터를 수집해야합니다. 여기 에서 비슷한 질문을 보았지만 불행히도 아무도 프로필 사용자 정의 부분에 대답하지 않았습니다.

을 위해 제공되는 설명서django-allauth :

ACCOUNT_SIGNUP_FORM_CLASS(= None)

‘myapp.forms.SignupForm’사용자에게 추가 입력 (예 : 뉴스 레터 가입, 생년월일)을 요청하기 위해 가입 중에 사용되는 사용자 지정 양식 클래스 (예 :)를 가리키는 문자열 입니다. 이 클래스는‘save’ 새로 가입 한 사용자를 유일한 매개 변수로 받아들이 메서드를 .

나는 django를 처음 접했고 이것으로 어려움을 겪고 있습니다. 누군가 이러한 사용자 지정 양식 클래스의 예를 제공 할 수 있습니까? 내가 좋아하는 사용자 개체에 대한 링크와 함께뿐만 아니라 모델 클래스를 추가해야합니까 ?

답변:


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 범위를 벗어납니다. 위의 예에서와 같이 이름 / 성을 요청하면 추가 모델이 필요하지 않으며 사용자 모델에 직접 배치 할 수 있습니다. 사용자의 생년월일, 좋아하는 색상 등을 묻는다면이를 위해 고유 한 프로필 모델을 설정해야합니다. 이 작업을 수행하는 방법에 대한 여기를 참조하십시오. docs.djangoproject.com/en/dev/topics/auth/…
pennersr

6
그것이 바로 제가 찾던 것입니다. 좋아하는 색상과 같은 추가 필드입니다. 내가 좋아하는 색상에 관심이있는 경우 새 UserProfile 클래스를 만든 다음 User를 일대일 필드로 사용하고 선호하는 색상을 추가 필드로 사용해야한다고 생각합니다. 이 경우에도 위에서 선언 한 SignUpForm 유형 (좋아하는 색상 포함)을 계속 사용하고 ACCOUNT_SIGNUP_FORM_CLASS를 연결할 수 있습니까? 아니면 양식을 만들고 내 코드로 데이터 저장을 처리해야합니까?
Shreyas

4
물론 ACCOUNT_SIGNUP_FORM_CLASS 메커니즘을 계속 사용할 수 있습니다. 원하는 색상이 원하는 모델에 저장되도록 save () 메서드가 제대로 구현되었는지 확인하기 만하면됩니다.
pennersr

5
@pennersr- ACCOUNT_SIGNUP_FORM_CLASS사용자 지정 사용자 모델 필드를 수집하고 저장하기 위해 첫 번째 소셜 로그인 후 어떻게이 문제를 해결할 수 있습니까? 또한 AUTH_USER_MODELgit : github.com/pennersr/django-allauth의 변경에 의한 커스텀 사용자 모델의 사용은 pypi에 업로드되지 않습니다.
Babu 2011

23

pennersr에서 제안한 솔루션을 사용하여 DeprecationWarning을 받았습니다.

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

이것은 버전 0.15부터 부터 def signup (request, user) 메소드를 위해 저장 메소드가 더 이상 사용되지 입니다.

따라서이를 해결하려면 예제 코드는 다음과 같아야합니다.

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'을 사용하는 것도 저에게
효과적이었습니다

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에서 사용자의 관리자 페이지에이 추가 필드를 어떻게 추가합니까?
Joshua

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신호가 설계 상 실패합니다. 둘째, created특히 DRY를 말할 때를 기반으로 한 신호로 줄일 수 있습니다 . 셋째, 뷰에서 user.save ()를 호출하여 프로필 저장에 영향을 준 다음 실제 데이터와 함께 프로필을 다시 저장합니다.
Melvyn

@Melvyn한다 그것은하지 fields = [...]대괄호 대신 fields = (...) 괄호?
Ahtisham

할 수 있지만 반드시 그럴 필요는 없습니다. 모델의 필드가 양식의 일부 여야하는지 확인하기 위해 읽기 전용으로 만 사용됩니다. 따라서 목록, 튜플 또는 집합 또는 그 파생물이 될 수 있습니다. 튜플은 변경 불가능하므로 튜플을 사용하고 우발적 인 변경을 방지하는 것이 더 합리적입니다. 성능 측면에서 볼 때 이러한 컬렉션은 실제로 너무 작아서 영향을 미치지 않습니다. 컬렉션이 너무 길어지면 exclude대신 전환하는 것이 좋습니다.
Melvyn

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 2015 년
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.