Adding Extra Fields to a Register Form

I followed a YouTube tutorial about creating a blog website, but I don’t like how the Profile creation form is set up. (I’m trying to create a website similar to the tutorial’s blog website, allowing users to create album reviews.)
The tutor in the YT video creates a UserRegisterForm from the UserCreationForm:

from django import forms
from django.contrib.auth.models import User 
from django.contrib.auth.forms import UserCreationForm
from .models import Profile

class UserRegisterForm(UserCreationForm):
    email = forms.EmailField()

    class Meta:
        model = User 
        fields = ['username', 'email', 'password1', 'password2']

Then a UserUpdateForm and a ProfileUpdateForm (which I tweaked for the information I would like from users):

class UserUpdateForm(forms.ModelForm):
    email = forms.EmailField()

    class Meta:
        model = User 
        fields = ['username', 'email']

class ProfileUpdateForm(forms.ModelForm):
    city = forms.CharField(label='City', max_length=100)
    state = forms.CharField(label='State', required=False, max_length=50)
    country = forms.CharField(label='Country (if outside U.S.)', required=False, max_length=100)
    favorite_artists = forms.CharField(label='Your favorite artists (use commas)', required=False, max_length=200)
    about_user = forms.CharField(widget=forms.Textarea(attrs={"rows": 7}), label='A small description of yourself', required=False)

class Meta:
        model = Profile
        fields = ['city', 'state', 'country', 'favorite_artists', 'about_user']

Then he adds a “profile” method in views.py:

@login_required
def profile(request):
    if request.method == 'POST':
        u_form = UserUpdateForm(request.POST, instance=request.user)
        p_form = ProfileUpdateForm(request.POST, instance=request.user.profile)
        
        if u_form.is_valid() and p_form.is_valid():
            u_form.save()
            p_form.save()
            messages.success(request, f'Your profile has been updated')
            return redirect('profile')
    else:
        u_form = UserUpdateForm(instance=request.user)
        p_form = ProfileUpdateForm(instance=request.user.profile)

    context = {
        'u_form': u_form,
        'p_form': p_form
    }

    return render(request, 'users/profile.html', context)

Then this form (using the CrispyForms extension):

<form method="POST" enctype="multipart/form-data">
   {% csrf_token %} 
      <fieldset class="form-group">
         <legend class="border-bottom mb-4">Update Profile</legend>
            {{ u_form|crispy }}
            {{ p_form|crispy }}
       </fieldset>
      <div class="form-group pt-3">
         <button class="btn btn-outline-info" type="submit">Update</button>
      </div>
</form>

I don’t like the resulting page:


Is there a way to add the fields in the profile form into the register user form? Or are register form fields restricted to 'username', 'password', 'email', 'first_name', and 'last_name'?

A model form is a form. It is a form that Django can create for you based on a model. But it’s still a form.

You still have all other facilities of forms available to you. Anything you can do in a form can also be done in a model form.

Is it possible to create a profile using the UserCreationForm? As my program now stands, a User can register an account with the usual parameters (username, email, and password1 and password2). Then when a User has registered, they are directed to a Login page, then they are directed to the “home” page.
I want each User to register with the usual parameters, but also with their city and state info, and some bio info. Can that be added to the UserCreationForm? Or do I have to create a separate form/page for a User to be directed to?
Can you provide a link to any DjangoProject documentation for me?

Yes.

Yes

There’s nothing special to point you to.

You have a form. It’s a Model Form with some additonal fields. You’re going to use those additional fields to create an instance of a different Model, and save it.

This is all standard forms processing.

I’m sorry to drag this on but every time I do an internet search for “adding fields to a UserCreationForm”, the return on that search is always someone just adding an “email” field to the UserCreationForm.
But you’re saying I can add all of this:

city = forms.CharField(label='City', max_length=100)
state = forms.CharField(label='State', required=False, max_length=50)
country = forms.CharField(label='Country (if outside U.S.)', required=False, max_length=100)
favorite_artists = forms.CharField(label='Your favorite artists (use commas)', required=False, max_length=200)
about_user = forms.CharField(widget=forms.Textarea(attrs={"rows": 7}), label='A small description of yourself', required=False)

…to a UserCreationForm?

1 Like

Yes.

Do not limit your searches to “UserCreationForm” or any usage-specific context.

This is a form. It doesn’t matter what you’re using it for.

It’s just a form.

It’s a form like every other form you will create in Django.

1 Like

When you get it working, will you share the code? :pray:

Yes, once I figure this out.
@KenWhitesell, if I have a UserRegisterForm with these fields in it:

class UserRegisterForm(UserCreationForm):
    email = forms.EmailField()
    city = forms.CharField(max_length=100)
    state = forms.CharField(required=False, max_length=50)
    country = forms.CharField(label='Country (if outside U.S.)', required=False, max_length=100)
    favorite_artists = forms.CharField(label='Your favorite artists (use commas)', required=False, max_length=200)
    about_user = forms.CharField(widget=forms.Textarea(attrs={"rows": 7}), label='A small description of yourself', required=False)

    class Meta:
        model = User
        fields = ['username', 'email', 'password1', 'password2', 'city', 'state', 'country', 'favorite_artists', 'about_user']

…do I still need a Profile model?

class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    city = models.CharField(blank=True, max_length=100)
    state = models.CharField(blank=True, max_length=50)
    country = models.CharField(blank=True, max_length=100)
    favorite_artists = models.TextField(max_length=200)
    about_user = models.TextField()

    def __str__(self):
        return f'{self.user.username} Profile'

Or will everything in the UserRegisterForm get saved to the django.contrib.auth.models provided User?

1 Like

Absolutely.

All you have done by this is to add fields to a form. You have not done anything to associate those fields with a model.

It’s now up to you to use those fields to populate a model as desired.

Absolutely not. Those fields aren’t defined and don’t exist in the User model.

A Django Model is a Python representation of a database table.

A Django Form is a Python representation of an HTML form.

A Django ModelForm is a Django Form, where the contents of the form can be automatically generated from the model - not the reverse. The form does not generate the model.

1 Like

I can’t figure it out. Is there anywhere you can lead me where I might be able to figure this out? I feel like I’m going around in a loop.

What is it that you can’t figure out?

From a Django tutorial I followed on YouTube (Python Django Tutorial: Full-Featured Web App Part 6 - User Registration - YouTube), the tutor created a UserRegisterForm, added an ‘email’ field to the form, and I followed all of that, and I have Users in my Admin page with a ‘username’, ‘email’, ‘password1’, and ‘password2’ fields.
Unfortunately, the tutor only created Users in that way. Then from the Register form, he made it so the registered user is redirected to a Login page. Then a User is redirected to the “home” page.
The only way a User – by the tutor’s instructions – can create a Profile is by clicking a “Profile” link in a nav bar.
The tutor has a Profile page set up, with an “Edit Profile” form ON the Profile page.
I want a User to be able to create both a User and a Profile on the Register page. But when I add fields to the Register page, those fields don’t get saved anywhere. Not in the User model nor the Profile model.
I’ve scoured the internet for the answer and I can’t find it.

1 Like

Ok, couple different points.

First, that tutorial is from 2018, making it sadly obsolete. I wouldn’t rely upon it for anything - and that’s without having watched it. Its age is enough for me to question its value.

My recommendations are to always start with either the Official Django Tutorial or the Django Girls Tutorial. The step beyond either of them is to read Working with forms | Django documentation | Django closely, until you understand everything being shown in every example.

I think you need to spend some time working on the fundamentals to get you past this point, and stop looking at this as being in any way specifically related to User and Profile models. You’re working with a very general issue - you have a form with fields, and you want to save those fields to a model.

1 Like

Thank you. I now have to start my users app, register, login, etc., all from scratch. So I can’t thank you enough. And I’m being diplomatic.

I don’t understand how you come to that conclusion. There’s nothing you’ve done that is “wrong” in any sense of the term. Everything you’re asking about is quite doable - you just need to gain the knowledge of how the parts fit together to make things work.

I seriously want to be able to understand this because I just went through another tutorial which showed a “UserRegisterForm” (['first_name', 'last_name', 'username', 'email', 'password1', 'password2']) on register.html, and then a “UserUpdateForm” (all the fields above plus ['description']) on a separate profile.html.
I’m seriously asking if it’s not possible to add all of those fields together on a registration form or not. Do the two have to be separated? Because I would like all of the fields to be asked on a “UserRegisterForm” on register.html. Please tell me if that is not possible so I can stop wasting my time.

Yes, it’s possible.

No, they do not need to be separated.

This was answered above at Adding Extra Fields to a Register Form - #4 by KenWhitesell

You need to break the mindset that there’s something special about a ModelForm, or that it’s somehow fundamentally different than a regular form. You also need to stop being focused on this being a User model and a User Profile model. You’re working with forms, using fields from the forms to populate two models.

You actually have at least four different ways you can accomplish this - each with their own advantages and disadvantages.

  • Don’t use a ModelForm at all. Create a standard form with all the fields needed for both models and create the models from the appropriate fields.

  • Use one model form and add additional fields. Create the second model in your view from those additional fields

  • Use two model forms, with a prefix on each to avoid field conflicts. (This tends to be more awkward if you use the Django-provided CBVs. It’s less an issue if you use your own designed CBV or an FBV.)

  • Use a model form with a 1-row formset for the second model. (Note: I don’t seriously recommend this. To me, this has no real benefits over the previous options and seems like it would be more work and more confusing than any of those options.)