3

I have a registration form which generates in view. Now I need to add some fields from other model. How should I change view to add fields from another model?

Here is my view code:

def register(request):
    """ User registration """
    if auth.get_user(request).username:
        return redirect('/')

    context = {}
    context.update(csrf(request))
    context['form'] = UserCreationForm()
    if request.POST:
        newuser_form = UserCreationForm(request.POST)
        if newuser_form.is_valid():
            newuser_form.save()
            newuser = auth.authenticate(username=newuser_form.cleaned_data['username'],
                                    password=newuser_form.cleaned_data['password2'])
        auth.login(request, newuser)
        return redirect('/')
        else:
            context['form'] = newuser_form

    return render(request, 'user_auth/user_auth_register.html', context)
Raman
  • 107
  • 1
  • 3
  • 12
  • 2
    Try subclassing `UserCreationForm` – bakatrouble Aug 16 '17 at 08:00
  • Possibly it'll be helpful for somebody https://simpleisbetterthancomplex.com/tutorial/2017/02/18/how-to-create-user-sign-up-view.html – Raman Nov 02 '17 at 08:49
  • Similar Question here [link](https://stackoverflow.com/questions/569468/django-multiple-models-in-one-template-using-forms/575133#575133) – Pek Feb 28 '20 at 05:00

2 Answers2

7

Something like this should help you:

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

class UserCreateForm(UserCreationForm):
    extra_field = forms.CharField(required=True)

    class Meta:
        model = User
        fields = ("username", "extra_field", "password1", "password2")

    def save(self, commit=True):
        user = super(UserCreateForm, self).save(commit=False)
        user.extra_field = self.cleaned_data["extra_field"]
        if commit:
            user.save()
        return user

Basically, extending UserCreationForm and adding an extra field. Also, save it in the save() method.

Hope it helps.

Jahongir Rahmonov
  • 13,083
  • 10
  • 47
  • 91
  • Maybe it's stupid question, I'm new to python and django but will it work if I need to save data from my custom extra field to my own model like 'UserInfo' for example? It stay not clear for me Thanks! – Raman Aug 16 '17 at 08:23
  • @RomanKozinets if you need a custom behavior, you should customize the `save()` model. You can do whatever you want with your `extra_field` there. – Jahongir Rahmonov Aug 16 '17 at 08:36
  • What about backend model of user table ? Do we need to update auth_user table to include new fields? – user4906240 May 12 '21 at 00:24
6

By default the UserCreationForm comes with username, password, first_name, last_name, email.

I wanted to add additional fields of information (easily accomplished after the fact using the ProfileUpdateForm) but I wanted it included in the initial registration form so the user would only have to submit once.

Solution is to use two forms and combine them. The magic trick is to initiate a manual database refresh to access the newly created profile

Reference: https://simpleisbetterthancomplex.com/tutorial/2016/07/22/how-to-extend-django-user-model.html

views.py

def register(request):
if request.method == 'POST':
    form = UserRegisterForm(request.POST)
    p_reg_form = ProfileRegisterForm(request.POST)
    if form.is_valid() and p_reg_form.is_valid():
        user = form.save()
        user.refresh_from_db()  # load the profile instance created by the signal
        p_reg_form = ProfileRegisterForm(request.POST, instance=user.profile)
        p_reg_form.full_clean()
        p_reg_form.save()
        messages.success(request, f'Your account has been sent for approval!')
        return redirect('login')
else:
    form = UserRegisterForm()
    p_reg_form = ProfileRegisterForm()
context = {
    'form': form,
    'p_reg_form': p_reg_form
}
return render(request, 'users/register.html', context)

forms.py

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

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

class ProfileRegisterForm(forms.ModelForm):
    class Meta:
        model = Profile
        fields = ['city', 'state', 'country', 'referral']

models.py

class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    image = models.ImageField(default='default.jpg', upload_to='profile_pics')
    confirmed = models.BooleanField("Confirmed", default=False)

    city = models.CharField("City", max_length=50, blank=True)
    state = models.CharField("State", max_length=50, blank=True)
    country = models.CharField("Country", max_length=50, blank=True)
    referral = models.CharField("Referral", max_length=50, blank=True)

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

def save(self, *args, **kwargs):
    super().save(*args, **kwargs)
mascai
  • 1,373
  • 1
  • 9
  • 30
TechBrad
  • 87
  • 1
  • 3