使用django-allauth时如何自定义用户配置文件


107

我有一个django-allauth应用程序的django项目。我需要在注册时从用户那里收集其他数据。我在这里遇到了类似的问题, 但不幸的是,没有人回答个人资料定制部分。

根据提供的文档django-allauth

ACCOUNT_SIGNUP_FORM_CLASS(= None

指向自定义表单类(例如‘myapp.forms.SignupForm’)的字符串,在注册过程中使用该字符串来询问用户其他输入(例如,简报注册,生日)。此类应实现一个‘save’方法,接受新注册的用户作为其唯一参数。

我是django的新手,正在为此而苦苦挣扎。有人可以提供这种自定义表单类的示例吗?我是否还需要添加模型类以及指向用户对象的链接,就像这样

Answers:


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 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)2012年

23

使用pennersr建议的解决方案,我得到了DeprecationWarning:

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

这是因为从0.15版本开始,不赞成使用save方法,而推荐使用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's

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'

这样,它使用了模型形式,使其为DRY,并使用了new 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 / 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 '18

如何在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,以避免在表单中创建配置文件,但我不能,但是我认为这将对您有所帮助。

型号

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 = (...) 括号吗?
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 2012年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.