Reputation: 699
I am following a tutorial to do this in Django 3.1.7.
The problem I'm having here is I'm being forced to repeat my Profile Model in my Profile Form definition.
I want to use forms.ModelForm in my forms.py to inherit my Profile Model and auto-generate the forms. It seems redundant to have to spell everything out again in forms.py when it is already defined in my Models. But I'm not sure how to do that with this architecture.
I've tried this approach: https://stackoverflow.com/a/2213802/4144483 But the problem with this is that UserForm is incomplete - 'password1' and 'password2' don't exist for model User. This is not a good solution for user registration. I seem to be bound to using UserCreationForm somehow.
#models.py
from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
bio = models.TextField(max_length=500, blank=True)
location = models.CharField(max_length=30, blank=True)
birth_date = models.DateField(null=True, blank=True)
@receiver(post_save, sender=User)
def update_user_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
instance.profile.save()
#forms.py
rom django import forms
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
class SignUpForm(UserCreationForm):
birth_date = forms.DateField(help_text='Required. Format: YYYY-MM-DD')
class Meta:
model = User
fields = ('username', 'birth_date', 'password1', 'password2', )
#views.py
from django.contrib.auth import login, authenticate
from django.shortcuts import render, redirect
from mysite.core.forms import SignUpForm
def signup(request):
if request.method == 'POST':
form = SignUpForm(request.POST)
if form.is_valid():
user = form.save()
user.refresh_from_db() # load the profile instance created by the signal
user.profile.birth_date = form.cleaned_data.get('birth_date')
user.save()
raw_password = form.cleaned_data.get('password1')
user = authenticate(username=user.username, password=raw_password)
login(request, user)
return redirect('home')
else:
form = SignUpForm()
return render(request, 'signup.html', {'form': form})
Upvotes: 1
Views: 654
Reputation: 597
I generally use ModelForm instead of CreateUserForm for UserRegistration like this and add password1 and password2 fields in it. also, I check if they both are the same.:
forms.py
class UserRegistrationForm(forms.ModelForm):
password = forms.CharField(label='Password', widget=forms.PasswordInput)
password2 = forms.CharField(label='Repeat Password', widget=forms.PasswordInput)
email = forms.EmailField(label='Email')
date_of_birth = forms.DateField(widget=forms.widgets.DateInput(attrs={'type': 'date'}))
class Meta:
model = User
fields = ['username', 'first_name', 'last_name', 'email',
] #these ordering will be as follow in html form
def clean_password2(self):
cd = self.cleaned_data
if cd['password'] != cd['password2']:
raise forms.ValidationError("Passwords don't match")
return cd['password2']
Then in views, I create a user and their profile and save the password in encrypted form, and link their profile.
views.py
def register(request):
u_form = UserRegistrationForm(data=request.POST or None)
p_form = ProfileForm(data=request.POST or None, files=request.FILES or None)
if u_form.is_valid() and p_form.is_valid():
new_user = u_form.save(commit=False)
new_user.set_password(u_form.cleaned_data['password']) #this saves password in encrypted form instead of raw password
new_user.save()
profile = p_form.save(commit=False)
profile.user = new_user
profile.save()
return render(request, 'accounts/register_done.html', {'new_user': user})
return render(request, 'accounts/register.html', {'user_form': u_form, 'profile_form':p_form})
You can modify it as you like.
Upvotes: 1