Reputation: 110382
I have an account page where I have three forms. A user can change his name, his email address, and his password.
There are two difficulties I am having from trying to do this:
1) the request.user information is not updating accordingly (e.g., it will lag behind by one change or it will update if the form is not validated)
2) I have three separate forms, however, when I submit one form, I will get validation messages from another form. For example, if I submit the "Change Name" form, I will get 'This field is required
from the password fields in the password form. Here is what I currently have --
in forms:
# in forms.py
from django.contrib.auth.models import User
class ChangeNameForm(ModelForm):
first_name = forms.CharField(required=True)
last_name = forms.CharField(required=True)
class Meta:
model = User
fields = ('first_name', 'last_name' )
class ChangeEmailForm(ModelForm):
email = forms.EmailField(required=True)
class Meta:
model = User
fields = ('email',)
in views:
@login_required
def account(request):
name_message = password_message = email_message = ''
change_name_form = ChangeNameForm(data=request.POST or None, instance=request.user)
change_password_form = PasswordChangeForm(data=request.POST or None, user = request.user)
change_email_form = ChangeEmailForm(data=request.POST or None, instance=request.user)
if request.method == "POST":
if "change_name" in request.POST and change_name_form.is_valid():
change_name_form.save()
name_message = 'Your name has been changed.'
if "change_password" in request.POST and change_password_form.is_valid():
change_password_form.save()
password_message = 'Your password has been changed.'
if "change_email" in request.POST and change_email_form.is_valid():
...
email_message = 'Please click the link in your email to confirm changes.'
return render_to_response('userprofile/account.html',
{'change_name_form': change_name_form,
'change_email_form': change_email_form,
'change_password_form': change_password_form,
'password_message': password_message,
'name_message': name_message,
'email_message': email_message,},
context_instance=RequestContext(request))
in template:
<h3>Change Name</h3>
<form method="post" action="/account/change/" name='name'> {% csrf_token %}
<h4>Change name: {{user.first_name}} {{user.last_name}}</h4>
<table>{{change_name_form.as_table}}</table>
<p>{{name_message}}</p>
<p><input type="submit" value="Save Changes" name="change_name"/></p>
</form>
<h3>Change Email</h3>
<form method="post" action="/account/change/" name='email'> {% csrf_token %}
<h4>Change email: {{user.email}}</h4>
<table>{{change_email_form.as_table}}</table>
<p>{{email_message}}</p>
<p><input type="submit" value="Save Changes" name="change_email" /></p>
</form>
<h3>Change Password</h3>
<form method="post" action="/account/change/" name='password'> {% csrf_token %}
<h4>Change password</h4>
<table>{{change_password_form.as_table}}</table>
<p>{{password_message}}</p>
<p><input type="submit" value="Save Changes" name="change_password"/></p>
</form>
What do I need to do to solve the two issues of making sure the request.user information is current and making sure validation only runs for the current form? Also, would it be possible to run a for loop
to reduce redundancy in the template code? If so, how would I do this given the fact that the two name
fields?. Thank you.
Upvotes: 0
Views: 1484
Reputation: 53999
I think martin means:
@login_required
def account(request):
name_message = password_message = email_message = ''
if request.method == "POST":
change_name_form = ChangeNameForm(data=request.POST or None, instance=request.user)
change_password_form = PasswordChangeForm(data=request.POST or None, user = request.user)
change_email_form = ChangeEmailForm(data=request.POST or None, instance=request.user)
...
else:
change_name_form = ChangeNameForm(instance=request.user)
change_password_form = PasswordChangeForm(instance = request.user)
change_email_form = ChangeEmailForm(instance=request.user)
...
return render_to_response('userprofile/account.html',
{'change_name_form': change_name_form,
'change_email_form': change_email_form,
'change_password_form': change_password_form,
'password_message': password_message,
'name_message': name_message,
'email_message': email_message,},
context_instance=RequestContext(request))
If the request to this view is a POST (i.e. the user is trying to edit a their account) you instantiate the form with the request POST attributes. If they are just arriving at the edit page, but haven't performed an edit (i.e. they haven't POST'ed any forms yet) then just instantiate the forms with the data from the database
Upvotes: 2
Reputation: 86
To answer your second question, you're instantiating all 3 forms with POSTd data, even when that particular form wasn't the one triggered. This will trigger validation on all 3 forms. I would move the form instantiation down into the if
statements you have below where you check for presence of the appropriate submit
button.
Upvotes: 1