Come personalizzare il profilo utente quando si utilizza django-allauth


107

Ho un progetto django con l'app django-allauth. Ho bisogno di raccogliere dati aggiuntivi dall'utente al momento della registrazione. Mi sono imbattuto in una domanda simile qui ma sfortunatamente nessuno ha risposto alla parte di personalizzazione del profilo.

Secondo la documentazione fornita perdjango-allauth :

ACCOUNT_SIGNUP_FORM_CLASS(= None)

Una stringa che punta a una classe di modulo personalizzato (ad es. ‘myapp.forms.SignupForm’) Che viene utilizzata durante la registrazione per chiedere all'utente un input aggiuntivo (ad es. Iscrizione alla newsletter, data di nascita). Questa classe dovrebbe implementare un ‘save’metodo, accettando l'utente appena registrato come unico parametro.

Sono nuovo a django e sto lottando con questo. Qualcuno può fornire un esempio di tale classe di modulo personalizzato? Devo aggiungere anche una classe modello con un collegamento all'oggetto utente come questo ?

Risposte:


170

Supponi di voler chiedere all'utente il suo nome / cognome durante la registrazione. Dovrai inserire questi campi nel tuo modulo, in questo modo:

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

Quindi, nelle tue impostazioni, punta a questo modulo:

ACCOUNT_SIGNUP_FORM_CLASS = 'yourproject.yourapp.forms.SignupForm'

È tutto.


10
Grazie. È sempre bello ascoltare l'autore originale :). Devo creare una classe aggiuntiva per memorizzare queste informazioni o allauth se ne occupa automaticamente?
Shreyas

12
In realtà dipende dalle informazioni che chiedi. In ogni caso, tutto questo va oltre lo scopo. Se chiedi il nome / cognome come nell'esempio sopra, non hai bisogno di un modello aggiuntivo e puoi posizionare le cose direttamente nel modello Utente. Se desideri chiedere la data di nascita dell'utente, il suo colore preferito o qualsiasi altra cosa, devi impostare il tuo modello di profilo per questo. Dai
pennersr

6
È esattamente quello che stavo cercando: un campo aggiuntivo come il colore preferito. Nel caso in cui fossi interessato, ad esempio, il colore preferito, credo che dovrei creare una nuova classe UserProfile e quindi utilizzare l'Utente come campo uno a uno e il colore preferito come campo aggiuntivo. In tal caso, posso comunque utilizzare un tipo di SignUpForm che avete dichiarato (con colore preferito) sopra e collegarvi l'ACCOUNT_SIGNUP_FORM_CLASS o devo creare il form e gestire il salvataggio dei dati nel mio codice?
Shreyas

4
Certo, il meccanismo ACCOUNT_SIGNUP_FORM_CLASS può ancora essere utilizzato. Devi solo assicurarti che il metodo save () sia implementato correttamente in modo che il colore preferito sia memorizzato in qualsiasi modello tu voglia.
pennersr

5
@pennersr - Come posso raggruppare questo ACCOUNT_SIGNUP_FORM_CLASSdopo il primo accesso social per raccogliere e salvare i campi del modello utente personalizzato? Anche l'utilizzo del modello utente personalizzato tramite AUTH_USER_MODELmodifiche da git: github.com/pennersr/django-allauth non viene caricato in pypi.
Babu

23

Utilizzando la soluzione suggerita da pennersr stavo ottenendo un ritiroAvvertenza:

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

Questo perché dalla versione 0.15 il metodo di salvataggio è stato deprecato a favore di un metodo di registrazione (richiesta, utente).

Quindi, per risolvere questo problema, il codice dell'esempio dovrebbe essere così:

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
La risposta di @ pennsesr è stata ora modificata per essere utilizzata al signupposto di save.
Flimm

18

Ecco cosa ha funzionato per me combinando alcune delle altre risposte (nessuna di esse è completa al 100% e ASCIUTTA).

In 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()

E in settings.py:

ACCOUNT_SIGNUP_FORM_CLASS = 'yourapp.forms.SignupForm'

In questo modo utilizza i moduli del modello in modo che sia ASCIUTTO e utilizza il nuovo def signup. Ho provato a metterlo 'myproject.myapp.forms.SignupForm'ma in qualche modo si è verificato un errore.


utilizzando "yourapp.forms.SignupForm" invece di "myproject.myapp.forms.SignupForm" ha funzionato anche per me
alpalalpal

6

@ Shreyas: la soluzione di seguito potrebbe non essere la più pulita, ma funziona. Per favore fatemi sapere se avete suggerimenti per ripulirlo ulteriormente.

Per aggiungere informazioni che non appartengono al profilo utente predefinito, creare prima un modello in yourapp / models.py. Leggi i documenti generali di django per saperne di più, ma fondamentalmente:

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)

Quindi crea un modulo in 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()

Questo è esattamente quello che ho finito per usare per un'app Django 2.0 che esegue Wagtail CMS. Ha funzionato per la registrazione regolare, ma meno con l'autenticazione sociale a quanto pare?
Kalob Taulien

Come aggiungerei questo campo extra alla pagina di amministrazione per l'utente in Wagtail?
Joshua

5

Nel tuo users/forms.pymetti:

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

In settings.py metti:

ACCOUNT_SIGNUP_FORM_CLASS = 'users.forms.SignupForm'

In questo modo non si rompe il principio DRY per molteplicità Definizione dei campi dei modelli utente.


4

Ho provato molti tutorial diversi e a tutti manca qualcosa, ripetendo codice non necessario o facendo cose strane, qui sotto segue la mia soluzione che unisce tutte le opzioni che ho trovato, funziona, l'ho già messo in produzione MA Non mi convince ancora perché mi aspetterei di ricevere first_name e last_name all'interno delle funzioni che ho allegato a Users create per evitare di creare un profilo all'interno del form ma non ci sono riuscito, peraltro penso che ti aiuterà.

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'

Ironia della sorte, anche a questo mancano alcune cose. I campi Profilo non hanno valori predefiniti, né consentono il valore nullo, quindi il create_user_profilesegnale non riesce per impostazione predefinita . In secondo luogo, puoi ridurlo a un segnale, basato su created, soprattutto quando si parla di SECCO. E terzo, effettui un salvataggio del profilo chiamando user.save () nella tua vista, quindi salvando di nuovo il profilo con i dati effettivi.
Melvyn

@ Melvyn Non dovrebbe essere fields = [...]con le parentesi quadre invece delle fields = (...) parentesi?
Ahtisham

Può, ma non deve esserlo. Viene utilizzato solo in sola lettura per verificare se il campo del Modello deve far parte del modulo. Quindi può essere una lista, una tupla o un insieme o qualsiasi suo derivato. Poiché le tuple non sono modificabili, ha più senso usare le tuple e prevenire mutazioni accidentali. Dal punto di vista delle prestazioni, queste raccolte sono in pratica troppo piccole per avere un impatto. Una volta che la raccolta diventa troppo lunga, potrebbe avere senso passare a 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'

Questo è tutto. (:


-10

Crea un modello di profilo con l'utente come 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
Grazie, ma non credo che questo sia tutto ciò che serve. La mia domanda si riferisce specificamente all'app allauth.
Shreyas
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.