Як налаштувати профіль користувача при використанні django-allauth


107

У мене є проект джанго за допомогою програми django-allauth. Мені потрібно зібрати додаткові дані від користувача при реєстрації. Тут я натрапив на подібне запитання, але, на жаль, ніхто не відповів на частину налаштування профілю.

Відповідно до документації, передбаченої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 подбає про це автоматично?
Шреяс

12
Це насправді залежить від інформації, яку ви запитуєте. У будь-якому випадку, це все виходить за рамки аллаута. Якщо ви запитаєте ім’я / прізвище, як у наведеному вище прикладі, тоді вам не потрібна додаткова модель і ви можете розмістити речі безпосередньо в моделі користувача. Якщо ви попросите дати народження користувача, його улюбленого кольору чи будь-якого іншого, тоді для цього вам потрібно встановити власну модель профілю. Подивіться тут, як це зробити: docs.djangoproject.com/en/dev/topics/auth/…
pennersr

6
Саме це я шукав - додаткове поле, як улюблений колір. Якщо мені цікаво сказати, улюблений колір, я вважаю, що я повинен створити новий клас UserProfile, а потім використовувати Користувача як поле один на одне, а улюблений колір як додаткове поле. У такому випадку я можу все-таки використовувати тип SignUpForm, який ви заявили вище (з улюбленим кольором) вище, і підключити до нього ACCOUNT_SIGNUP_FORM_CLASS чи мені потрібно створити форму та обробляти збереження даних у власному коді?
Шреяс

4
Звичайно, механізм ACCOUNT_SIGNUP_FORM_CLASS все ще можна використовувати. Вам просто потрібно переконатися, що метод збереження () належним чином реалізований таким чином, щоб улюблений колір зберігався у будь-якій моделі, яку ви хочете.
pennersr

5
@pennersr - Як я можу підключити це ACCOUNT_SIGNUP_FORM_CLASSпісля першого соціального входу, щоб зібрати та зберегти користувацькі поля користувальницької моделі? Також використання користувацької моделі користувача за допомогою AUTH_USER_MODELзмін від git: github.com/pennersr/django-allauth не завантажуються в pypi.
Бабу

23

Використовуючи рішення, запропоноване pennersr, я отримував попередження про депрекацію:

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. Прочитайте загальні документи про джанго, щоб дізнатися більше про нього, але в основному:

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, здається?
Калоб Тауліен

Як я можу додати це додаткове поле на сторінку адміністратора для користувача в 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

Я пробував багато різних навчальних посібників, і всім у них щось не вистачає, повторюючи непотрібний код або роблячи дивні речі, нижче слід за моїм рішенням, яке приєднується до всіх варіантів, які я знайшов, він працює, я вже ввів його у виробництво, АЛЕ це все ще не переконує мене, тому що я би сподівався отримати ім'я та прізвище всередині функцій, які я додав до користувачів, щоб створити профіль у формі, але я не міг, тим не менше, я думаю, що це допоможе тобі.

Моделі.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 Повинно чи це бути не fields = [...]з квадратними дужками замість fields = (...) круглих дужок?
Ахтішам

Це може, але не повинно бути. Він використовується лише для читання, щоб перевірити, чи повинно поле на Моделі бути частиною форми. Таким чином, це може бути список, кортеж або набір або будь-яке його похідне. Оскільки кортежі не підлягають мутації, то має більше сенсу використовувати кортежі та запобігати випадковим мутаціям. З точки зору ефективності, ці колекції на практиці занадто малі, щоб мати будь-який вплив. Після того, як колекція буде занадто довгою, excludeзамість неї, можливо, буде сенс перейти .
Мельвін

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.
Шреяс
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.