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})
Advertisement
Answer
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.