Heyho,
I created a model Profile with a OnetoOneField to User. In account_settings view I want to either give the possibility to change the profile information or reset the password. Changing Profile-Information works fine, but when I try to change the password, my PasswordChangeForm is always invalid. Can somebody tell me where my mistake is?
Here's the view:
def account_settings(request, id):
user = Profile.objects.get(id=id)
if request.method == 'POST' and 'passwordchange' in request.POST:
user_form = PasswordChangeForm(request.user, prefix='password')
if user_form.is_valid():
user_form.save()
update_session_auth_hash(request, user)
messages.success(request, 'Your password was successfully updated!')
else:
messages.error(request, 'Please correct the error below.')
return redirect('profile', user.id)
elif request.method == 'POST' and 'profilechange' in request.POST:
profile_form = ProfileForm(request.POST, instance=request.user.profile,prefix='profil')
if profile_form.is_valid():
profile_form.save()
return redirect('account_settings',user.id)
#else:
#messages.error(request, _('Please correct the error below.'))
else:
user_form = PasswordChangeForm(user=request.user, prefix='password')
profile_form = ProfileForm(instance=request.user.profile,prefix='profil')
return render(request, 'app/accountform.html', {'profileuser': user,'user_form': user_form,'profile_form': profile_form})
the template:
<div class="col-md-9">
<div class="profile-content">
<form method="post" >
{% csrf_token %}
{{ profile_form.as_p }}
<button type="submit" name="profilechange">Ă„nderungen speichern</button>
</form>
<form method="post" >
{% csrf_token %}
{{ user_form.as_p }}
<button type="submit" name="passwordchange">Passwort ändern</button>
</form>
Abbrechen
</div>
</div>
You are not passing the POST data to the form, which is why it is failing to validate. You need to pass the POST data when initialising it:
user_form = PasswordChangeForm(request.user, data=request.POST, prefix='password')
if user_form.is_valid():
# This should work now
Related
I was trying to create a blog app by following an online Django tutorial and while I was testing the sign-up page, I ran into a Value Error saying that the view did not return a HTTP response object. i tried everything but i could not find the answer as i am not a Django expert
in the users app's views.py file was the code that threw the error
from django.shortcuts import render, redirect
from django.contrib.auth.forms import UserCreationForm
from django.contrib import messages
def register(request):
if request.method == 'POST':
form = UserCreationForm(request.POST)
if form.is_valid():
username = form.cleaned_data.get('username')
messages.success(request, f'Account Created for {username}')
return redirect('blog-home')
else:
form = UserCreationForm()
return render(request, 'users/register.html', {'form': form})
and this is the register template
{% extends "myblog/base.html" %}
{% block content %}
<div class="content-section">
<form method="POST">
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4">
Join Today!
</legend>
{{ form.as_p }}
</fieldset>
<div class="form-group">
<button class="btn btn-outline-info" type="submit">
Sign Up!
</button>
</div>
</form>
<div class="border-top pt-3">
<small class="text-muted">
Already Have an account?
Sign In!
</small>
</div>
</div>
{% endblock content%}
And this is the file structure of the project
File Structure
If we have a POST request, and the form is not valid, you do not return anything. Unindent the render call, so:
def register(request):
if request.method == 'POST':
form = UserCreationForm(request.POST, request.FILES)
if form.is_valid():
username = form.cleaned_data.get('username')
messages.success(request, f'Account Created for {username}')
return redirect('blog-home')
else:
form = UserCreationForm()
return render(request, 'users/register.html', {'form': form})
You can write function like this ...
def register(request):
form = UserCreationForm()
if request.method == 'POST':
form = UserCreationForm(request.POST)
if form.is_valid():
username = form.cleaned_data.get('username')
messages.success(request, f'Account Created for {username}')
return redirect('blog-home')
else:
form.errors
context = {'form': form}
return render(request, 'users/register.html', context)
return something for the function register also , you are returning only in if else conditions
return render(request, 'users/register.html', {'form': form}) add this at the end of the function outiside if else (now we have returned something for the function register also , you are returning only in if else conditions
I have created a page to update User profile. If I try to update a value of user with existing user, error is thrown as expected, however the variable user.username in profile.html shows the value I am trying to update. My query is why {{ user.username }} is picking up the incorrect value even though the save() method is not called.
profile.html
<div class="content p-3">
<div><img class="rounded-circle" src="{{ user.profile.image.url }}" width="100" height="100"></div>
<div>{{ user.username }}</div>
<div>{{ user.email }}</div>
</div>
<div class="w-25">
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
<fieldset>
<legend>Profile Info</legend>
{{ user_form | crispy }}
{{ profile_form | crispy }}
</fieldset>
<input class="mt-3" type="submit" value="Update">
</form>
</div>
forms.py
class UserUpdateForm(forms.ModelForm):
email = forms.EmailField()
class Meta:
model = User
fields = ['username', 'email']
class ProfileUpdateForm(forms.ModelForm):
class Meta:
model = Profile
fields = ['image']
views.py
#login_required
def profile(request):
if (request.method == "POST"):
user_form = UserUpdateForm(request.POST, instance=request.user)
profile_form = ProfileUpdateForm(request.POST,
request.FILES,
instance=request.user.profile)
if (user_form.is_valid() and profile_form.is_valid()):
user_form.save()
profile_form.save()
messages.success(request, f"Your profile is updated successfully")
return redirect("profile")
else:
messages.error(request, f"Failed to update profile")
else:
user_form = UserUpdateForm(instance=request.user)
profile_form = ProfileUpdateForm(instance=request.user.profile)
return render(request, 'User/profile.html', {'user_form': user_form, 'profile_form': profile_form}
The ModelForm updating the instance as part of validation is strange/unwanted behaviour, maybe you have found a "bug"
A work around would be to pass a copy of request.user using copy.copy into the ModelForm so that any changes made as part of validation happen on the copy
user_form = UserUpdateForm(request.POST, instance=copy.copy(request.user))
When you write user_form = UserUpdateForm(request.POST, instance=request.user),
your user_form update itself using the values received from front-end. In this case, username is 'newuser2'.
Since this username is taken, user_form.is_valid() returns false and below render function is returned:
return render(request, 'User/profile.html', {'user_form': user_form, 'profile_form': profile_form}
Please note that this instance of user_form has username as "newuser2". Thats why you see username as "newuser2" instead of your current logged in user.
Apologies for the brevity, I'm learning to post answers.
def profile(request):
Exist_Emails = User.objects.filter(is_active=True).values_list('email', flat=True)
Exist_Usernames = User.objects.filter(is_active=True).values_list('username', flat=True)
current_user = User.objects.get(username=request.user.username)
Email_Invalid = False
Username_Invalid = False
if request.method != 'POST':
u_form = UserUpdateForm(instance=request.user)
p_form = ProfileUpdateForm(instance=request.user.profile)
else:
update_username = request.POST.get('username')
u_form = UserUpdateForm(request.POST, instance=request.user)
p_form = ProfileUpdateForm(request.POST,
request.FILES,
instance=request.user.profile)
if u_form.is_valid() and p_form.is_valid():
p_form.save()
update_u_form = u_form.save(commit=False)
#Problem occurs in this if statement!
if update_u_form.username in Exist_Usernames and update_u_form.username != current_user.username:
Username_Invalid = True
u_form = UserUpdateForm(instance=current_user) ##
messages.error(request, 'The username already eixts')
#But it worked in this elif statement which is almost the same!
elif update_u_form.email in Exist_Emails and update_u_form.email != current_user.email:
Email_Invalid = True
u_form = UserUpdateForm(instance=current_user)
messages.error(request, 'The email already exits.')
else:
update_u_form.save()
return redirect('/users/profile/')
context = {
'u_form': u_form, 'p_form': p_form,'update_username':
update_username,'Email_Invalid': Email_Invalid,'current_user':
current_user, 'Username_Invalid': Username_Invalid}
return render(request, 'users/profile.html', context)
This is the html template:
{% if Email_Invalid == "True" or Username_Invalid == "True" %}
{{ current_user.username }}
</div>
<div style="font-size:16px;">
{{ current_user.email }}
</div>
<p>"Sorry, the email or username already exits."</p>
{% else %}
{{ user.username }}
</div>
<div style="font-size:16px;">
{{ user.email }}
</div>
{% endif %}
{{Username_Invalid}}
{{update_username}}
<form method="post" class="form" enctype="multipart/form-data">
{% csrf_token %}
{{ u_form.as_p }}
{{ p_form.as_p }}
<button name="sumbit" class="btn btn-primary" >Update</button>
</form>
My forms.py:
class UserUpdateForm(forms.ModelForm):
email = forms.EmailField()
class Meta:
model = User
fields = ['username', 'email']
As I type in updated username, and press submit. However The {{Username_Invalid}} returns False which is supposed to be True in if statement.
Then I checked {{update_username}} which returns NONE!! update_username here is just request.POST.get('username').
What is going on? I thought UserUpdateForm should inherit from User model. So request.POST should have a dictionary key-value pair 'username':username.
My debugging process:
What I am trying to do is to display (instance = current_user) in u_form when the user tries to edit email or username but these email or username has already been registered in database by others.
It works perfectly fine in the email field, but when I edit username to be sth that has already been registered by another user, the instance however displays whatever I typed in(It should print instance = current_user not request.user).
So I found out that when I did this , it didn't enter the first IF statement after is_valid, as Username_Invalid still prints False. Then I checked if something is wrong with 'update_u_form.username' , so I set
update_username = request.POST.get('username')
to print out the value, and it returns NONE. I think this is where the problem is but can't figure out why.
I would like to use a model form on the django.auth user, but I want to be able to pass in the PK to the model to manage other users, not the logged in user.
Is there a way to do this or do I need to create a regular form?
Django admin site is not appropriate for my use case.
Something like (which doesn't work of course...):
View
def edit_user(request,pk):
if request.method == 'POST':
user_form = UserEditForm(queryset=User.objects.get(pk=pk),
data=request.POST)
if user_form.is_valid():
user_form.save()
messages.success(request, 'User updated successfully')
else:
messages.error(request, 'Error updating your profile')
else:
user_form = UserEditForm(queryset=User.objects.get(pk=pk))
return render(request, 'edit_user.html', {'user_form': user_form })
UserEdit Form
class UserEditForm(forms.ModelForm):
class Meta:
model = User
fields = ('first_name', 'last_name', 'email')
Template:
% block content %}
<h1>Edit User:</h1>
<p> </p>
<form action="." method="post" enctype="multipart/form-data">
{{ user_form.as_p }}
{% csrf_token %}
<p><input type="submit" value="Save changes" class="btn btn-primary"> Manage</p>
</form>
{% endblock %}
Example URL: profile/edit-user/3/
I want the form populated with the PK of the user (the 3 in this case) NOT like my edit your own profile which passes in instance=request.user:
View for profile
def user_profile(request):
if request.method == 'POST':
user_form = UserEditForm(instance=request.user,
data=request.POST)
profile_form = UserProfileEditForm(instance=request.user.profile,
data=request.POST,
files=request.FILES)
if user_form.is_valid() and profile_form.is_valid():
user_form.save()
profile_form.save()
messages.success(request, 'Profile updated successfully')
else:
messages.error(request, 'Error updating your profile')
else:
user_form = UserEditForm(instance=request.user)
profile_form = UserProfileEditForm(instance=request.user.profile)
return render(request, 'profile_edit.html', {'user_form': user_form,
'profile_form': profile_form})
Still very new to django...
Thanks for your help.
BCBB
You just need to get the user you want and then pass it in to the form as the instance argument, exactly as you did with the logged in user.
def edit_user(request, pk):
user = User.objects.get(pk=pk)
if request.method == 'POST':
user_form = UserEditForm(instance=user,
data=request.POST)
...
else:
user_form = UserEditForm(instance=user)
...
I have the following form that lives on the site root at /
<form action='/play/' method='post'>
{% csrf_token %}
{{ form.player_name }}
<input id='play' type='submit' value='Play'>
</form>
then I have the view that validates this form:
def login(request):
context = {}
if request.method == 'POST':
form = LoginForm(request.POST)
if form.is_valid():
return HttpResponseRedirect('/play/')
else:
context.update(dict(form=form))
else:
context.update(dict(form=LoginForm(initial={'player_name':'Please tell us your name'})))
return render_to_response('login.html', context, context_instance=RequestContext(request))
And the actual play view:
def play(request):
p1 = briscola.Player(request.POST['player_name'])
The problem is that of course the redirect looses the POST data. But why doesn't it POST directly to the play view by itself when the form.is_valid?