Hi, I have created a Manage Account page where users can go to update details on their account, specifically, name, email, phone number, marketing consent and password. I have included the fields of username and date of birth on the page and disabled them as I want to show the user that these cannot be altered.
When clicking Save Changes on the page, it returns errors ‘User with this username already exists’, and ‘This field is required’ for both the password fields’. I believed I had mitigated this with the code I had written but apparently not and I’m confused as to how to resolve this now. I have posted all the relevant code below:
views.py:
@login_required
def manage_account(request):
if request.method == 'POST':
form = ManageAccountForm(request.POST, instance=request.user)
if form.is_valid():
user = form.save(commit=False)
user.username = request.user.username
user.dob = request.user.dob
user.save()
messages.success(request, 'Changes made successfully')
return redirect('manage_account')
else:
form = ManageAccountForm(instance=request.user)
return render(request, 'manage_account.html', {'form': form})
forms.py:
class CustomRegisterUserForm(UserCreationForm):
name = forms.CharField(
max_length=255,
required=True,
widget=forms.TextInput(attrs={'class': 'form-control'})
)
username = forms.CharField(
max_length=150,
required=True,
widget=forms.TextInput(attrs={'class': 'form-control'}),
help_text=mark_safe('Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.')
)
dob = forms.DateField(
required=True,
widget=forms.DateInput(attrs={'class': 'form-control', 'type': 'date'}),
label='Date of Birth'
)
email = forms.EmailField(
required=True,
widget=forms.EmailInput(attrs={'class': 'form-control'})
)
phone_number = forms.CharField(
max_length=15,
required=False,
widget=forms.TextInput(attrs={'class': 'form-control'})
)
marketing_consent = forms.BooleanField(
required=False,
widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}),
label='Marketing Consent'
)
password1 = forms.CharField(
max_length=100,
required=True,
label='Password',
widget=forms.PasswordInput(attrs={'class': 'form-control'}),
)
password2 = forms.CharField(
max_length=100,
required=True,
label='Password Confirmation',
widget=forms.PasswordInput(attrs={'class': 'form-control'})
)
class Meta:
model = CustomUser
fields = (
'name',
'username',
'dob',
'email',
'phone_number',
'password1',
'password2',
'marketing_consent'
)
labels = {
'dob': 'Date of Birth',
}
class ManageAccountForm(CustomRegisterUserForm):
class Meta(CustomRegisterUserForm.Meta):
fields = [
'name',
'username',
'dob',
'email',
'phone_number',
'marketing_consent',
'password1',
'password2'
]
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Disabling/greying out username and DOB fields
self.fields['username'].disabled = True
self.fields['dob'].disabled = True
self.fields['username'].widget.attrs.update({
'readonly': True,
'title': 'This field cannot be changed.'
})
self.fields['dob'].widget.attrs.update({
'readonly': True,
'title': 'This field cannot be changed.'
})
# Making password fields optional
self.fields['password1'].required = False
self.fields['password2'].required = False
self.fields['password1'].widget.attrs.update({'placeholder': 'Leave blank to keep current password.'})
self.fields['password2'].widget.attrs.update({'placeholder': 'Leave blank to keep current password.'})
def clean(self):
cleaned_data = super().clean()
password1 = cleaned_data.get('password1')
password2 = cleaned_data.get('password2')
# If passwords are provided, validate them
if password1 or password2:
if password1 != password2:
self.add_error('password2', 'Passwords must match.')
return cleaned_data
def save(self, commit=True):
instance = super().save(commit=False)
# Preserve username
instance.username = self.instance.username
# Hash the new password if provided
password1 = self.cleaned_data.get('password1')
if password1:
instance.set_password(password1)
if commit:
instance.save()
return instance
HTML:
{% block content %}
<div class="account__container">
<div class="account__content">
{% if messages %}
<ul>
{% for message in messages %}
<li class="messages">{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
<h2>Manage Your Account</h2>
<p>Update your personal details and preferences here.</p>
<form method='POST'>
{% csrf_token %}
{{ form.as_p }}
<button type='submit'>Save Changes</button>
</form>
</div>
</div>
{% endblock %}
If anymore information is needed I’m more than happy to provide it - thanks for any help.