0

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.

2 Answers 2

2

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

Sign up to request clarification or add additional context in comments.

1 Comment

ah I see, thank you for the explanation. Do you know why the request.user info is not staying current?
1

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.

2 Comments

I don't quite follow. Could you please post the part of code that you mean?
Something like this: if request.POST.has_key('change_password'): change_password_form = PasswordChangeForm(data=request.POST, user=request.user) elif request.POST.has_key('change_name'): change_name_form = ChangeNameForm(data=request.POST, user=request.user) ... Ugh, sorry for the formatting. Not sure how to format comments properly.

Your Answer

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.