Logged in user information incorrectly dispalyed - django

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.

Related

Django - Form used in editing data from extended user model doesn't show previous data as placeholder

I use following code:
models.py
class Profile(models.Model):
location = models.CharField(max_length=300, blank=True)
user = models.OneToOneField(
User,
on_delete=models.CASCADE,
)
def __str__(self):
return self.imie
views.py
def edit(request):
if request.method == 'POST':
profile = Profile.objects.get(user = request.user)
profile_form = ProfileForm(request.POST, instance = profile)
if profile_form.is_valid():
profile_form.save()
messages.success(request, ('Your profile was successfully updated!'))
return redirect('profile')
else:
messages.error(request, ('Please correct the error below.'))
else:
profile = Profile.objects.get(user = request.user)
profile_form = ProfileForm(request.POST, instance = profile)
return render(request, 'edit.html', {
'profile_form': ProfileForm
})
forms.py
class ProfileForm(forms.ModelForm):
class Meta:
model = Profile
fields = ('location')
edit.html
<div class="col-md-6 offset-md-3">
<form method="post">
{% csrf_token %}
{{ profile_form.as_p }}
<button type="submit" class="btn btn-secondary">Save changes</button>
</form>
</div>
Following code should allow the user to edit data stored in Profile model and it does exactly that, however form is loaded empty (without placeholder) and I would like it to display previous values.
Edit: where the link to edit.html is anchored
it's just a simple verions of a profile page where just plain data is displayed
{% for things in logged_in_user_data %}
<ul>
<li>Your location: {{ things.location}}</li>
</ul>
{% endfor %}
with it's views.py
def profile(request):
logged_in_user_data = Profile.objects.filter(user=request.user)
return render(request, 'profile.html', {'logged_in_user_data': logged_in_user_data})
In the case the request is not a POST request you have still written ProfileForm(request.POST, instance = profile). What does this signify? It means that this form is now a bound form and a user has submitted some data to it (which here was empty since the request was not a post request). This causes the form to be rendered empty since it is considered that the user had provided those empty values. Instead you need to not pass request.POST here:
def edit(request):
profile = Profile.objects.get(user = request.user) # Move common line here
if request.method == 'POST':
profile_form = ProfileForm(request.POST, instance = profile)
if profile_form.is_valid():
profile_form.save()
messages.success(request, ('Your profile was successfully updated!'))
return redirect('profile')
else:
messages.error(request, ('Please correct the error below.'))
else:
profile_form = ProfileForm(instance=profile) # No `request.POST` here
return render(request, 'edit.html', {
# Typo noted as per comment by #A67John
'profile_form': profile_form
})

i am unable to change profile pic in django

I created a profile form in models.py for and form.py to update it but all thing got updated except profile picture
views.py
views.py
#login_required
def update_profile(request):
if request.method == 'POST':
profile_form = ProfileForm(request.POST, request.FILES, instance=request.user.profile)
if profile_form.is_valid():
profile_form.save()
messages.success(request, "Your profile updated.")
else:
status_code = 400
message = 'Please correct the error below.'
messages.error(request, "Please use correct information")
else:
profile_form = ProfileForm(instance=request.user.profile)
return render(request, 'profile.html', {
'profile_form': profile_form
})
forms.py
models.py
First of, you need to include request.FILES where you initialize your form in the POST request like this:
profile_form = ProfileForm(request.POST, request.FILES, instance=request.user.profile)
Then in your html you need to add enctype="multipart/form-data" attribute to your form:
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ profile_form.as_p }}
<button type="submit" value="Submit"></button>
</form>
try using forward slash at the end of upload_to path like this: upload_to='profile_pics/'

Pass PK into model form (not logged in user)

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)
...

How to update an ImageField in Django

I am making a website and would like to make it possible for each user to upload and update his own profile picture.
The update-profile template loads perfectly fine. I can update all the other fields, except for the image field. It can only be updated from the /admin page, but not from the update-profile page.
This is my image field in the Profile model:
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
dob = models.DateField(default=datetime.date(1989, 12, 25))
gender = models.CharField(max_length=12, choices=GENDER_CHOICES, default='Unspecified')
city = models.CharField(max_length=100, default='Braşov')
image = models.ImageField(upload_to='profilepics', blank=True)
Here is my ProfileForm:
class ProfileForm(forms.ModelForm):
class Meta:
model = Profile
fields = ('dob', 'gender', 'city', 'image')
This is the html template:
{% block body %}
<form method="post">
<div class="container">
{% csrf_token %}
{{ user_form.as_p }}
{{ profile_form.as_p }}
<button type="submit">Update</button>
Cancel
</form>
</div>
{% endblock %}
And this is the update_profile view:
#login_required
#transaction.atomic
def update_profile(request):
if request.method == 'POST':
user_form = UserForm(request.POST, instance=request.user)
profile_form = ProfileForm(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, ('Your profile was successfully updated!'))
return redirect('myprofile')
else:
messages.error(request, ('Please correct the error below.'))
else:
user_form = UserForm(instance=request.user)
profile_form = ProfileForm(instance=request.user.profile)
return render(request, 'filter/updateprofile.html', {
'user_form': user_form,
'profile_form': profile_form
})
Thank you very much for reading!
Add the attribute enctype to your form tag in your html document enctype="multipart/form-data"
See this question
Django ModelForm Imagefield Upload
And as is documented in w3schools
https://www.w3schools.com/tags/att_form_enctype.asp

invalid PasswordChangeForm

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