4
\$\begingroup\$

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?

rzickler
1311 gold badge1 silver badge5 bronze badges
asked Jun 7, 2011 at 19:20
\$\endgroup\$

1 Answer 1

5
\$\begingroup\$

Somewhere on "Stack Overflow" was question like your.

Main idea was remove None from form initialization.

if "change_name" in request.POST:
 change_name_form = ChangeNameForm(data=request.POST, instance=request.user)
 if change_name_form.is_valid():
 change_name_form.save()
 name_message = 'Your name has been changed.'
else:
 change_name_form = ChangeNameForm(instance=request.user)
if "change_password" in request.POST:
 change_password_form = PasswordChangeForm(user=request.user)
 if change_password_form.is_valid():
 change_password_form.save() 
 password_message = 'Your password has been changed.'
else:
 change_password_form = PasswordChangeForm(user=request.user)
if "change_email" in request.POST:
 change_email_form = ChangeEmailForm(request.POST, instance=request.user)
 if change_email_form.is_valid():
 ...
 email_message = 'Please click the link in your email to confirm changes.'
else:
 change_email_form = ChangeEmailForm(instance=request.user)

This is my solution. I hope it's help you.

answered Jun 8, 2011 at 14:29
\$\endgroup\$
3
  • \$\begingroup\$ Thank you for the answer. Could you please elaborate on why you'd remove None. What is the advantage of doing so? \$\endgroup\$ Commented Jun 8, 2011 at 22:18
  • \$\begingroup\$ For your case, when you commit any form request.POST isn't empty and you put it into all your forms. Then form got any POST data it become bound form, and fields already have error attribute after this form become bound. docs.djangoproject.com/en/1.3/ref/forms/api/… \$\endgroup\$ Commented Jun 9, 2011 at 5:21
  • 1
    \$\begingroup\$ I think there is one more solution, form prefixes. docs.djangoproject.com/en/1.3/ref/forms/api/#prefixes-for-forms \$\endgroup\$ Commented Jun 9, 2011 at 10:36

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.