Cách tùy chỉnh hồ sơ người dùng khi sử dụng django-allauth


107

Tôi có một dự án django với ứng dụng django-allauth. Tôi cần thu thập thêm dữ liệu từ người dùng khi đăng ký. Tôi đã gặp một cái tương tự câu hỏi ở đây nhưng thật không may, không ai trả lời phần tùy chỉnh hồ sơ.

Theo tài liệu được cung cấp chodjango-allauth :

ACCOUNT_SIGNUP_FORM_CLASS (=None )

Một chuỗi trỏ đến một lớp biểu mẫu tùy chỉnh (ví dụ ‘myapp.forms.SignupForm’) được sử dụng trong quá trình đăng ký để yêu cầu người dùng nhập thêm thông tin (ví dụ: đăng ký bản tin, ngày sinh). Lớp này phải triển khai một ‘save’phương thức, chấp nhận người dùng mới đăng ký làm tham số duy nhất của nó.

Tôi mới sử dụng django và đang đấu tranh với điều này. Ai đó có thể cung cấp một ví dụ về một lớp biểu mẫu tùy chỉnh như vậy không? Tôi có cần thêm một lớp mô hình cùng với một liên kết đến đối tượng người dùng như thế này không?

Câu trả lời:


170

Giả sử bạn muốn hỏi người dùng về họ / tên trong khi đăng ký. Bạn sẽ cần đặt các trường này vào biểu mẫu của riêng mình, như sau:

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

Sau đó, trong cài đặt của bạn trỏ đến biểu mẫu này:

ACCOUNT_SIGNUP_FORM_CLASS = 'yourproject.yourapp.forms.SignupForm'

Đó là tất cả.


10
Cảm ơn. Nghe từ tác giả gốc luôn là tốt rồi :). Tôi có cần tạo một lớp bổ sung để lưu trữ thông tin này không hay allauth tự động xử lý việc đó?
Shreyas

12
Điều đó thực sự phụ thuộc vào thông tin bạn đang hỏi. Trong mọi trường hợp, điều này nằm ngoài phạm vi allauth. Nếu bạn yêu cầu họ / tên như trong ví dụ trên, thì bạn không cần thêm mô hình và có thể đặt mọi thứ trực tiếp vào Mô hình người dùng. Nếu bạn muốn hỏi ngày sinh của người dùng, màu sắc yêu thích của họ hoặc bất cứ điều gì, thì bạn cần thiết lập mô hình hồ sơ của riêng mình cho điều này. Vui lòng xem tại đây về cách thực hiện việc này: docs.djangoproject.com/en/dev/topics/auth/…
pennersr

6
Đó chính xác là những gì tôi đang tìm kiếm - một trường bổ sung như màu yêu thích. Trong trường hợp tôi quan tâm đến màu sắc yêu thích, tôi tin rằng tôi nên tạo một lớp UserProfile mới và sau đó sử dụng Người dùng làm trường 1-1 và màu yêu thích làm trường bổ sung. Trong trường hợp đó, tôi vẫn có thể sử dụng loại SignUpForm mà bạn đã khai báo (với màu ưa thích) ở trên và kết nối ACCOUNT_SIGNUP_FORM_CLASS với nó hay tôi cần tạo biểu mẫu và xử lý việc lưu dữ liệu bằng mã của riêng mình?
Shreyas

4
Chắc chắn, vẫn có thể sử dụng cơ chế ACCOUNT_SIGNUP_FORM_CLASS. Bạn chỉ cần đảm bảo rằng phương thức save () được triển khai đúng cách để màu yêu thích được lưu trữ trong bất kỳ mô hình nào bạn muốn.
pennersr

5
@pennersr - Làm cách nào để tôi có thể tạo điều này ACCOUNT_SIGNUP_FORM_CLASSsau lần đăng nhập xã hội đầu tiên để thu thập và lưu các trường mô hình người dùng tùy chỉnh? Ngoài ra, việc sử dụng mô hình người dùng tùy chỉnh theo các AUTH_USER_MODELthay đổi từ git: github.com/pennersr/django-allauth không được tải lên trong pypi.
Babu

23

Sử dụng giải pháp do pennersr đề xuất, tôi nhận được lỗi không dùng nữa Cảnh báo:

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

Điều này là do kể từ phiên bản 0.15 , phương thức lưu đã không được chấp nhận thay cho phương thức đăng ký def (yêu cầu, người dùng).

Vì vậy, để giải quyết vấn đề này, mã của ví dụ sẽ như sau:

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
Câu trả lời của @ pennsesr hiện đã được chỉnh sửa để sử dụng signupthay thế save.
Flimm

18

Đây là những gì hiệu quả với tôi khi kết hợp một vài câu trả lời khác (không câu trả lời nào trong số đó là hoàn chỉnh 100% và KHÔ).

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

Và trong settings.py:

ACCOUNT_SIGNUP_FORM_CLASS = 'yourapp.forms.SignupForm'

Bằng cách này, nó sử dụng các hình thức mô hình để nó KHÔ và sử dụng cái mới def signup. Tôi đã thử đặt 'myproject.myapp.forms.SignupForm'nhưng điều đó dẫn đến lỗi bằng cách nào đó.


sử dụng 'yourapp.forms.SignupForm' thay vì 'myproject.myapp.forms.SignupForm' cũng làm việc cho tôi
alpalalpal

6

@Shreyas: Giải pháp dưới đây có thể không phải là sạch nhất, nhưng nó hoạt động. Vui lòng cho tôi biết nếu bạn có bất kỳ đề xuất nào để làm sạch nó thêm.

Để thêm thông tin không thuộc về hồ sơ người dùng mặc định, trước tiên hãy tạo một mô hình trong yourapp / models.py. Đọc tài liệu django chung để tìm hiểu thêm về nó, nhưng về cơ bản:

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)

Sau đó, tạo một biểu mẫu trong 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()

Đây chính xác là những gì tôi đã sử dụng cho một ứng dụng Django 2.0 đang chạy Wagtail CMS. Làm việc để đăng ký thường xuyên, nhưng dường như ít hơn với Social Auth?
Kalob Taulien

Làm cách nào để thêm trường bổ sung này vào trang quản trị cho người dùng trong Wagtail?
Joshua

5

Trong users/forms.pybạn đặt:

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

Trong settings.py bạn đặt:

ACCOUNT_SIGNUP_FORM_CLASS = 'users.forms.SignupForm'

Bằng cách này, bạn không phá vỡ nguyên tắc KHÔ bằng cách xác định nhiều trường Mô hình người dùng.


4

Tôi đã thử nhiều hướng dẫn khác nhau và tất cả chúng đều thiếu thứ gì đó, lặp lại mã không cần thiết hoặc làm những điều kỳ lạ, dưới đây là giải pháp của tôi kết hợp tất cả các tùy chọn mà tôi tìm thấy, nó đang hoạt động, tôi đã đưa nó vào sản xuất NHƯNG vẫn không thuyết phục được tôi vì tôi mong đợi nhận được first_name và last_name bên trong các hàm mà tôi đính kèm với Người dùng tạo để tránh tạo hồ sơ bên trong biểu mẫu nhưng tôi không thể, tôi nghĩ nó sẽ giúp ích cho bạn.

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'

Trớ trêu thay, điều này cũng thiếu một vài thứ. Các trường Hồ sơ không có giá trị mặc định, cũng như không cho phép giá trị rỗng, do đó, create_user_profiletín hiệu của bạn không thành công theo thiết kế. Thứ hai, bạn có thể giảm điều này thành một tín hiệu created, đặc biệt là khi nói KHÔ. Và thứ ba, bạn thực hiện lưu Hồ sơ bằng cách gọi user.save () trong chế độ xem của mình, sau đó lưu lại hồ sơ với dữ liệu thực tế.
Melvyn

@Melvyn Có nên fields = [...]dùng dấu ngoặc vuông thay vì fields = (...) dấu ngoặc không?
Ahtisham

Nó có thể, nhưng không nhất thiết phải như vậy. Nó chỉ được sử dụng ở chế độ chỉ đọc để kiểm tra xem trường trên Mô hình có phải là một phần của biểu mẫu hay không. Vì vậy, nó có thể là một danh sách, bộ hoặc bộ hoặc bất kỳ dẫn xuất nào của chúng. Vì các bộ giá trị không thể biến đổi, nên việc sử dụng các bộ giá trị và ngăn chặn các đột biến ngẫu nhiên sẽ có ý nghĩa hơn. Từ góc độ hiệu suất, những bộ sưu tập này trên thực tế quá nhỏ để có bất kỳ tác động nào. Một khi bộ sưu tập quá dài, bạn nên chuyển sang bộ sưu tập excludethay thế.
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'

Đó là nó. (:


-10

Tạo Mô hình hồ sơ với người dùng là 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
Cảm ơn, nhưng tôi không nghĩ rằng đây là tất cả những gì cần thiết. Câu hỏi của tôi đặc biệt đề cập đến ứng dụng allauth.
Shreyas
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.