0

I am using django.contrib.auth.models User model. and I have another class called UserProfile, which essentially is an extension of the django user model.

class UserProfile(models.Model):
    user = models.OneToOneField(User, related_name='userprofile', primary_key=True)
    age = models.CharField(max_length=3, blank=True)
    shortbio = models.CharField(max_length=400, blank=True)

So I want to have a form based on UserProfile model, but also integrate the existing fields like first name and last name from User Class. And allow me to update both fields of UserProfile and User in one form. How could I approach this?

9blue
  • 4,693
  • 9
  • 29
  • 43
  • Possible duplicate of [How to create a UserProfile form in Django with first\_name, last\_name modifications?](http://stackoverflow.com/questions/1727564/how-to-create-a-userprofile-form-in-django-with-first-name-last-name-modificati) – Selcuk Feb 12 '16 at 08:03
  • If you don't need application wide logic, just this form, then you can skip the ModelForm. Define an unbound Form, with all the required fields, and then in the form's save method save the correct fields to each model separately. – Aviah Laor Feb 12 '16 at 08:34

2 Answers2

0

There are 3 steps to achieve this. I happened to do something very similar yesterday. Firstly the model, then the views, then the template.

Model:

This code makes sure when a user registers, a new profile is made too. Add this code under UserProfile with no tabs.

# This will ensure the profile is made when a user is created
@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
    if created:
        UserProfile.objects.create(user=instance)

Views:

I will assume this form is for register, like it was for mine. This (for me) took quite a lot of code because you need to do a few things. (1) Save the new user. (2) Set a new userprofile (3) Save userprofile

# This method will allow a user to register for an account
def register_user(request):
    form1 = UserForm(prefix="user")
    form2 = ProfileForm(prefix="profile")

    if request.method == "POST":
        form1 = UserForm(request.POST, prefix="user")
        form2 = ProfileForm(request.POST, prefix="profile")

        if form1.is_valid() and form2.is_valid():
            # Save form1 with no commit
            user = form1.save(commit=False) 
            # Code you may add for your website registration, example
            # user.email = form1.cleaned_data['email'] 
            user.save()
            user.userprofile.user = user
            user.userprofile.age = form2.cleaned_data['age']
            user.userprofile.bio = form2.cleaned_data['bio']
            user.userprofile.save()
            # Some return statement you choose
            return redirect('app_name:index')
    # ***
    return render(request, 'accounts/register.html', {"form1": form1, "form2": form2}) 

Note: this code should be similar even if it's not for the register. You basically need to reset everything anyways.

Template:

This is simple. Make your own userform and profile form in forms.py and then return them to your views function. Note the *** at the last line. Then in your template just add:

<h4>Register for an Account</h4>
{% if error_message %}
     <p><strong>{{ error_message }}</strong></p>
{% endif %}

<form class="form-horizontal" role="form" action="" method="post" enctype="multipart/form-data">
   {% csrf_token %}
   {{form1}}
   {{form2}}
   <br>
   <div class="form-group">
       <div class="col-sm-offset-2 col-sm-10">
             <button type="submit" class="btn btn-success">Submit</button>
       </div>
   </div>
</form>
Stephen Rauch
  • 47,830
  • 31
  • 106
  • 135
Adam LaMorre
  • 655
  • 7
  • 21
0

There are some ways to do it, here is one:

Url:

from app import views
from app import views

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^complementary/', views.complementary)
]

Model:

# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.contrib.auth.models import User
from django.db import models


# Create your models here.
class UserProfile(models.Model):
    user_p = models.OneToOneField(User, related_name='userprofile',
                                primary_key=True)
    age = models.CharField(max_length=3, blank=True)
    shortbio = models.CharField(max_length=400, blank=True)

Views:

# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.shortcuts import redirect
from django.shortcuts import render

from app.forms import UserEditForm, ProfileEditForm
from app.models import UserProfile


# Create your views here.
def complementary(request):
    profile = UserProfile.objects.get(user_p=1)
    user_form = UserEditForm(instance=request.user)
    profile_form = ProfileEditForm(instance=request.user)

    if request.method == 'POST':
        user_form = UserEditForm(instance=request.user,
                                 data=request.POST)
        profile_form = ProfileEditForm(instance=request.user.usuario,
                                       data=request.POST,
                                       files=request.FILES)

        if user_form.is_valid() and profile_form.is_valid():
            user_form.save()
            profile_form.save()
            return redirect('redirect_url')

    dic = {'profile': profile,
           'user_form': user_form,
           'profile_form': profile_form}

    return render(request, 'template.html', dic)

Forms:

# -*- coding: utf-8 -*-
from django import forms
from django.contrib.auth.models import User
from django.core.validators import RegexValidator
from app.models import UserProfile


class UserEditForm(forms.ModelForm):
    # Regex for non-digits
    name_val = [RegexValidator(r'^[a-zA-ZÀ-Ÿ_]+( [a-zA-ZÀ-Ÿ_]+)*$',
                               message='Non-digits',
                               code='invalid_name')]

    first_name = forms.CharField(
        label='Name *',
        validators=name_val,
        widget=forms.TextInput(attrs={'placeholder': 'Name: '})
    )
    last_name = forms.CharField(
        label='Last Name *',
        validators=name_val,
        widget=forms.TextInput(attrs={'placeholder': 'Last Name: '})
    )

    class Meta:
        model = User
        fields = ('first_name', 'last_name', 'email')


class ProfileEditForm(forms.ModelForm):
    class Meta:
        model = UserProfile
        exclude = 'id',

Template.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    {{ profile.shortbio }}
    <form role="form" method="post" id="custom-form">
        {% csrf_token %}
        {{ user_form.as_p }}
        {{ profile_form.as_p }}
        <button type="submit"></button>
    </form>
</body>
</html>
unixeo
  • 1,116
  • 1
  • 15
  • 28