0

When I submit a sign up form which contains information for the user (username, email, password) and the user profile (first name and last name) and call save like form.save() and profileform.save() in my views.py then all seems to be fine and I get no errors.

However, when I go into the Django Admin then I see that the user profile and the profile have saved separately.

enter image description here

So there's two different profiles, one containing the username I entered into the form, and the other with first and last name (as the image displays).

Here's my views.py:

def signup(request):
    if request.method == 'POST':
        form = UserRegistrationForm(data=request.POST)
        profileform = UserRegistrationProfileForm(data=request.POST)
        if form.is_valid() and profileform.is_valid():
            user = form.save()
            profileform.save()
            if user is not None:
                if user.is_active:
                    user_login(request, user, backend='django.contrib.auth.backends.ModelBackend')
                    return redirect('/dashboard/')
    else:
        form = UserRegistrationForm()
        profileform = UserRegistrationProfileForm()
    return render(request, 'signup-user.html', {'form': form, 'profileform': profileform})

Forms.py (for the profile part of the form):

class UserRegistrationProfileForm(forms.ModelForm):
    user_fname = forms.CharField(#)
    user_lname = forms.CharField(#)

    class Meta:
        model = UserProfileModel
        fields = ['user_fname', 'user_lname']

    def clean(self):
        #...

    def save(self, commit=True):
        profile = super(UserRegistrationProfileForm, self).save(commit=False)
        if commit:
            profile.save()
        return profile

Models.py (for the profile, which includes the receiver signal):

class UserProfileModel(models.Model): # For the Company Employees
    user = models.OneToOneField(UserModel, related_name='userprofilemodel', on_delete=models.CASCADE, blank=True, null=True)
    user_fname = models.CharField(max_length=30, verbose_name='First Names')
    user_lname = models.CharField(max_length=30, verbose_name='Last Name')

    class Meta:
        verbose_name = 'Profile'

    def __unicode__(self):
        #...

    def save(self, *args, **kwargs):
        super(UserProfileModel, self).save(*args, **kwargs)

    @receiver(post_save, sender=UserModel)
    def create_user_profile(sender, instance, created, **kwargs):
        if created:
            UserProfileModel.objects.create(user=instance)

    @receiver(post_save, sender=UserModel)
    def save_user_profile(sender, instance, **kwargs):
        instance.userprofilemodel.save()

Am not sure what I'm doing wrong? I want the form to create ONE user profile that has the user instance as user, as well as the first and last name.

Any ideas on where i'm going wrong?

Update

Here's the UserRegistrationForm class:

class UserRegistrationForm(forms.ModelForm):
    #

    class Meta:
        model = UserModel
        fields = ['related_company_slug', 'username', 'user_email', 'password', 'passwordrepeat']

    def clean(self):
        #

    def save(self, commit=True):
        self.check_company
        user = super(UserRegistrationForm, self).save(commit=False)
        user.set_password(self.cleaned_data.get('password'))
        user.is_active = True
        if commit:
            user.save()
        return user
jayt
  • 758
  • 1
  • 14
  • 32

2 Answers2

1

You should get rid of those signals. They are doing nothing useful, and are probably the cause of the duplication.

Instead, you need to do something to tell the form that the profile you are creating belongs to the user you just created:

user = form.save()
profile = profileform.save(commit=False)
profile.user = user
profile.save()

You should also get rid of the save methods on both the form and the model - there's no point in defining an overridden method whose sole action is to call the super method.

Similarly, you can get rid of the checks for user is not None and user.is_active; you know the user exists and is active, because you just created it.

Daniel Roseman
  • 588,541
  • 66
  • 880
  • 895
-1

In practice, imo, better always have profile for each user. To achieve this post/pre-save signals that you use make sense. For example when user just registered in system, Profile for new user will be autocreated Code will be very simple:

class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    # your fields

@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
    if created:
        Profile.objects.create(user=instance)

Also, if you already have pool of users without profiles, and want to create profiles for them you can use data-migration, if you need code for such data migration, please see post in my blog.

Make Tips
  • 180
  • 2
  • 6
  • 1
    Please disclose any affiliation you have with that site –  Apr 19 '17 at 14:01
  • @Riker I am owner of this site as Indicated in my profile – Make Tips Apr 19 '17 at 14:10
  • 2
    While links are tolerated here as long as they are useful, they are frowned apon, especially if all your posts include links to the same site. I suggest you read [How not to be a spammer](http://stackoverflow.com/help/promotion) to find out more about what the community thinks – CalvT Apr 19 '17 at 14:10
  • 1
    Please note if you want to promote your own product/blog you **must disclose your affiliation in the answer**, otherwise your answer may be flagged as spam. Please read [How to not be a spammer](https://stackoverflow.com/help/promotion) – DavidPostill Apr 19 '17 at 14:11
  • @CalvT, thanks for explanation, I'll take it into account! Despite this I sincerely believe my answer may help with root cause of question, and in details answer to question "Am not sure what I'm doing wrong? ", this is my best practice and I want to share it, links also help to point to the information that should not overload answer. Thanks – Make Tips Apr 19 '17 at 14:15
  • @MakeTips I don't understand django, but your answer looks ok! Just make sure your answers are always helpful, and I'm sure they will be appreciated :) – CalvT Apr 19 '17 at 14:17