วิธีปรับแต่งโปรไฟล์ผู้ใช้เมื่อใช้ django-allauth


108

ฉันมีโปรเจ็กต์ django พร้อมแอพ django-allauth ฉันต้องการรวบรวมข้อมูลเพิ่มเติมจากผู้ใช้เมื่อสมัคร ฉันเจอคำถามที่คล้ายกันที่นี่ แต่น่าเสียดายที่ไม่มีใครตอบส่วนการปรับแต่งโปรไฟล์

ตามเอกสารที่ให้ไว้สำหรับ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

12
ขึ้นอยู่กับข้อมูลที่คุณกำลังถาม ไม่ว่าในกรณีใดทั้งหมดนี้อยู่นอกเหนือขอบเขตทั้งหมด หากคุณถามชื่อ / นามสกุลตามตัวอย่างด้านบนแสดงว่าคุณไม่จำเป็นต้องมีโมเดลเพิ่มเติมและสามารถวางสิ่งต่างๆลงในโมเดลผู้ใช้ได้โดยตรง หากคุณต้องการขอวันเกิดของผู้ใช้สีที่เขาชอบหรืออะไรก็ตามคุณต้องตั้งค่ารูปแบบโปรไฟล์ของคุณเองสำหรับสิ่งนี้ โปรดดูวิธีการทำที่นี่: docs.djangoproject.com/th/dev/topics/auth/…
pennersr

6
นั่นคือสิ่งที่ฉันกำลังมองหา - ช่องเพิ่มเติมเช่นสีโปรด ในกรณีที่ฉันสนใจที่จะพูดว่าเป็นสีที่ชอบฉันเชื่อว่าฉันควรสร้างคลาส UserProfile ใหม่จากนั้นใช้ User เป็นฟิลด์หนึ่งต่อหนึ่งและสีที่ชอบเป็นฟิลด์เพิ่มเติม ในกรณีนี้ฉันยังสามารถใช้ประเภทของ SignUpForm ที่คุณประกาศไว้ (ด้วยสีที่ชอบ) ด้านบนและเชื่อมต่อ ACCOUNT_SIGNUP_FORM_CLASS เข้ากับมันได้หรือไม่หรือฉันต้องสร้างแบบฟอร์มและจัดการการบันทึกข้อมูลในรหัสของฉันเอง
Shreyas

4
แน่นอนว่ากลไก ACCOUNT_SIGNUP_FORM_CLASS ยังสามารถใช้งานได้ คุณเพียงแค่ต้องตรวจสอบให้แน่ใจว่าวิธีการบันทึก () ถูกนำไปใช้อย่างเหมาะสมเพื่อให้สีที่ชื่นชอบถูกเก็บไว้ในรุ่นที่คุณต้องการ
เพนเนอร์

5
@pennersr - ฉันจะทำสิ่งนี้ได้อย่างไรACCOUNT_SIGNUP_FORM_CLASSหลังจากลงชื่อเข้าใช้โซเชียลครั้งแรกเพื่อรวบรวมและบันทึกฟิลด์โมเดลผู้ใช้ที่กำหนดเอง นอกจากนี้การใช้รูปแบบผู้ใช้ที่กำหนดเองโดยAUTH_USER_MODELการเปลี่ยนแปลงจาก git: 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 (คำขอผู้ใช้)

ดังนั้นเพื่อแก้ปัญหานี้โค้ดของตัวอย่างควรเป็นดังนี้:

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% และแห้ง)

ใน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'

def signupวิธีนี้จะใช้รูปแบบรูปแบบเพื่อที่จะแห้งและใช้ใหม่ ฉันลองใส่แล้ว'myproject.myapp.forms.SignupForm'แต่ก็ทำให้เกิดข้อผิดพลาดขึ้น


การใช้ 'yourapp.forms.SignupForm' แทน 'myproject.myapp.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 / form.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()

นี่คือสิ่งที่ฉันใช้กับแอพ Django 2.0 ที่ใช้งาน Wagtail CMS ทำงานสำหรับการสมัครเป็นประจำ แต่น้อยกว่าด้วย 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

ฉันได้ลองใช้แบบฝึกหัดต่างๆมากมายและทุกอย่างขาดหายไปการทำซ้ำรหัสที่ไม่จำเป็นหรือทำสิ่งแปลก ๆ ร้องตามวิธีแก้ปัญหาของฉันที่รวมตัวเลือกทั้งหมดที่ฉันพบมันใช้งานได้ฉันได้นำไปใช้งานจริงแล้ว แต่มัน ยังไม่เชื่อฉันเพราะฉันคาดหวังว่าจะได้รับ 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'

แดกดันสิ่งนี้ขาดหายไปเล็กน้อยเช่นกัน ฟิลด์โปรไฟล์ไม่มีค่าเริ่มต้นและไม่อนุญาตให้มีค่าว่างดังนั้นcreate_user_profileสัญญาณของคุณจึงล้มเหลวเนื่องจากการออกแบบ ประการที่สองคุณสามารถลดสัญญาณนี้ให้เหลือเพียงสัญญาณเดียวcreatedโดยเฉพาะเมื่อพูดถึง DRY และประการที่สามคุณมีผลต่อการบันทึกโปรไฟล์โดยการเรียก user.save () ในมุมมองของคุณจากนั้นบันทึกโปรไฟล์อีกครั้งด้วยข้อมูลจริง
Melvyn

@Melvyn ไม่ควรจะเป็นfields = [...]ด้วยวงเล็บเหลี่ยมแทนfields = (...) วงเล็บ?
Ahtisham

สามารถทำได้ แต่ไม่จำเป็นต้องเป็น ใช้เฉพาะอ่านอย่างเดียวเพื่อตรวจสอบว่าฟิลด์บนโมเดลควรเป็นส่วนหนึ่งของฟอร์มหรือไม่ จึงอาจเป็นรายการทูเพิลหรือเซตหรืออนุพันธ์ใด ๆ ก็ได้ เนื่องจาก tuples ไม่สามารถเปลี่ยนแปลงได้จึงควรใช้ tuples มากกว่าและป้องกันการกลายพันธุ์โดยไม่ได้ตั้งใจ จากมุมมองด้านประสิทธิภาพคอลเลกชันเหล่านี้มีขนาดเล็กเกินกว่าที่จะส่งผลกระทบใด ๆ เมื่อคอลเล็กชันมีความยาวเกินไปก็ควรเปลี่ยนมา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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.