Simran
Simran

Reputation: 633

django: Extending user model using one-to-one: how to save() Profile model's fields

I have a basic Django application, wherein along with the User model I have extended the Profile model using One-to-one field.

Models.py

class Profile(models.Model):
  user = models.OneToOneField(User, on_delete=models.CASCADE,  null=True)
  profile_picture = models.ImageField(upload_to='customer_profile_images/%Y/%m/%d/', null=True, blank=True, verbose_name="Profile Picture")
  phone_number = models.CharField(null=True, blank=True, max_length=10)

  # no need for following two methods
  # def create_user_profile(sender, instance, created, **kwargs):
    # if created:
        # Profile.objects.get_or_create(user=instance)

  # post_save.connect(create_user_profile, sender=User)

  def __str__(self):
     return f'{self.user.first_name} {self.user.last_name}'

In admin.py I have registered the Profile model as follow:

from myapp import Profile


class ProfileAdmin(admin.ModelAdmin):
list_display = ('user', 'phone_number')

admin.site.register(Profile, ProfileAdmin)

And a Profile model is being successfully created within the User model.

And at the time of creating a new account for a user in views.py

class CustomerSignUpView(View):
def post(self, request):
    name_r = request.POST.get('customer_username')
    password_r = request.POST.get('customer_password')
    email_r = request.POST.get('customer_email')
    contact_number_r = request.POST.get('customer_contact_number')
    profile_picture_r = request.FILES['customer_profile_picture']

     # this is how i am saving contact number, profile picture for Profile model.

    if checkemail(email_r):
        c = User.objects.create_user(username=name_r, password=password_r, email=email_r)
        c.save()

        # add the following code
        p = Profile(user=c, phone_number=contact_number_r, profile_picture=profile_picture_r)
        p.save()       

        return render(request, 'catalog/customer_login.html')
    else:
        return render(request, 'catalog/customer_signup.html')

def get(self, request):
    return render(request, 'catalog/customer_signup.html')

However, while creating a new user account in sign up page, i encounter the following error:

error

I don't understand how to save those newly created fields of Profile model using save() method.

UPDATE: Solution found-

In views.py, this is how I am saving fields inside Profile model

     p = Profile(user=c, phone_number=contact_number_r, profile_picture=profile_picture_r)
     p.save()

And now, whenever I sign up a new user, the username, profile picture and phone number get added in the Profile model as well, and even during deleting/updating profile details the changes are reflected in both User and Profile Model

Following link is useful for my project requirements:

http://books.agiliq.com/projects/django-orm-cookbook/en/latest/one_to_one.html

Upvotes: 2

Views: 4044

Answers (1)

Rarblack
Rarblack

Reputation: 4664

First of all, there is none need of saving the instance of the profile after saving a User:

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

delete above code. To answer your question, if User instance is not created then you don't want to create a profile instance so no need of worrying on that part. Please, add below code to your admin.py to have admin User form merged with profile one.

class ProfileInline(admin.StackedInline):    
    model = Profile
    can_delete = False
    verbose_name_plural = 'Profile'
    fk_name = 'user'

Also, would suggest you read on this.

You should not get the values directly from the post. This is not a secure way. Either use basic form and get data from cleaned_data dictionary or use ModelForm.

I assume you are new in the Django and if you are not too obsessed with using a class-based view, would suggest you use function-based one. It will be easy for you are you will see all the steps.

Follow this one. If not this will solve your issue, so you can adjust your code to this one.

Upvotes: 1

Related Questions