I have a form and every time the form is updated a message is displayed "Your profile has been updated". This message is shown even if no changes has been performed in the form.
How can i prevent the form to show message only when changes has been performed?
views.py
#login_required(login_url='login')
def profilePage(request):
if request.method == 'POST':
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():
u_form.save()
p_form.save()
messages.success(request, 'Your account {} has been updated'.format(request.user.username))
return redirect('profile')
else:
u_form = UserUpdateForm(instance=request.user)
p_form = ProfileUpdateForm(instance=request.user.profile)
context = {
'u_form': u_form,
'p_form': p_form
}
return render(request, 'members/profile.html', context)
forms.py
class ProfileUpdateForm(forms.ModelForm):
phone_number = PhoneNumberField(label=False, widget=forms.TextInput(attrs={'placeholder': 'Phone Number'}))
image = forms.ImageField(label=False)
class Meta:
model = Profile
fields = ['phone_number', 'image', ]
Message used in template
{% if messages %}
<div class="prof-sucmessages">
{% for message in messages %}
<div class="alert-profile alert-{{ message.tags }} alert-dismissible" role="alert">
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
{{ message }}
</div>
{% endfor %}
</div>
{% endif %}
Thank you for help!
You can use the form.has_changed() method to see if anything changed which you could use like this:
if not u_form.has_changed() and not p_form.has_changed():
# Don't perform the save operations and don't show a message
# Return an empty successful message instead
return HttpResponse(status=204)
In your view this could become:
def profilePage(request):
if request.method == 'POST':
u_form = UserUpdateForm(request.POST, instance=request.user)
p_form = ProfileUpdateForm(request.POST, request.FILES, instance=request.user.profile)
if not u_form.has_changed() and not p_form.has_changed():
# Don't perform the save operations and don't show a message
# Return an empty successful message instead
return HttpResponse(status=204)
if u_form.is_valid() and p_form.is_valid():
u_form.save()
p_form.save()
messages.success(request, 'Your account {} has been updated'.format(request.user.username))
return redirect('profile')
else:
u_form = UserUpdateForm(instance=request.user)
p_form = ProfileUpdateForm(instance=request.user.profile)
context = {
'u_form': u_form,
'p_form': p_form
}
return render(request, 'members/profile.html', context)
if u_form.has_changed() or p_form.has_changed():
// Don't perform the save operations and don't show a message
// Return an empty successful message instead
return HttpResponse(status=204)
Related
I am creating a website using Django. Somehow I cannot register as a user as I always get the following error message:
UnboundLocalError at /register/
local variable 'context' referenced before assignment
views.py
Register a new user
def register(request):
if request.method == 'POST':
form = UserRegisterForm(request.POST)
pform = UserProfileForm(request.POST)
if form.is_valid() and pform. is_valid():
user = form.save()
profile = pform.save(commit=False)
profile.user = user
profile.save()
username = form.cleaned_data.get('username')
messages.success(request, f'Your account has been created! You are now able to login')
return redirect('login')
else:
context = {
'form': UserRegisterForm,
'p_form': UserProfileForm
}
return render(request, 'users/register.html', context)
Creating a profile
#login_required
def profile(request):
if request.method == 'POST':
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():
u_form.save()
p_form.save()
messages.success(request, f'Your account has been updated!')
return redirect('profile')
elif request.method == 'DELETE':
return redirect('startup-home')
else:
u_form = UserUpdateForm(instance=request.user)
p_form = ProfileUpdateForm(instance=request.user.profile)
context = {
'u_form': u_form,
'p_form': p_form
}
return render(request, 'users/profile.html', context)
register.html
{% load crispy_forms_tags %}
{% 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|crispy }}
</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? <a class="ml-2" href="{% url 'login' %}">Sign In</a></small>
</div>
</div>
{% endblock content %}
Does anyone have an idea why my context is false or won't be accepted ?
UPDATE:
Because you are passing context in else statement so that's why it won't accepting.
Change this:
else:
context = {
'form': UserRegisterForm,
'p_form': UserProfileForm
}
To this:
context = {
'form': form,
'p_form': p_form
}
And your views look like this:
def register(request):
if request.method == 'POST':
form = UserRegisterForm(request.POST)
p_form = UserProfileForm(request.POST)
if form.is_valid() and p_form.is_valid():
user = form.save()
profile = pform.save(commit=False)
profile.user = user
profile.save()
username = form.cleaned_data.get('username')
messages.success(request, f'Your account has been created! You are now able to login')
return redirect('login')
else:
form = UserRegisterForm()
p_form = UserProfileForm() #Here you made mistake
context = {
'form': form,
'p_form': p_form
}
return render(request, 'users/register.html', context)
Here:
context = {
'form': UserRegisterForm,
'p_form': UserProfileForm
}
you are returning the actual classes, not an instance of the classes, which would be your forms.
Also, you are not actually setting context in the first part of the if, so that needs moving outside the conditional entirely.
You need to return what you've defined:
else:
form = UserRegisterForm()
pform = UserProfileForm()
context = {
'form': form,
'p_form': pform,
}
Note that the difference is in the brackets ...
UserProfileForm is just the class object.
UserProfileForm() calls the class to get an instance of the class.
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/'
How can I edit an User Instance information of a user(first_name, last_name, email) with extending OneToOne Relationship profile page. Below my code is not giving me any error but also not updating my given information in DB for user. The User model is not created by me but I use django.contrib.auth.models.User also I don't want to use UpdateView class from Django. Any help would be appreciated.
Django Version
asgiref==3.3.1
Django==3.1.5
django-crispy-forms==1.10.0
Pillow==8.1.0
pytz==2020.5
sqlparse==0.4.1
Code:
users/forms.py
from django import forms
from django.contrib.auth.models import User
from .models import Profile
class UserUpdateForm(forms.ModelForm):
first_name = forms.CharField(max_length=30)
last_name = forms.CharField(max_length=30)
email = forms.EmailField()
class Meta:
model = User
fields = ['first_name', 'last_name', 'email']
class ProfileUpdateForm(forms.ModelForm):
class Meta:
model = Profile
fields = ['image']
users/views.py
from django.shortcuts import render, redirect
from django.contrib.auth.decorators import login_required
from .forms import UserUpdateForm, ProfileUpdateForm
from django.contrib import messages
#login_required
def profile(request):
if request.POST == 'POST':
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():
u_form.save()
p_form.save()
messages.success(request, "Your profile has been updated !")
return redirect('profile')
else:
u_form = UserUpdateForm(instance=request.user)
p_form = ProfileUpdateForm(instance=request.user.profile)
context = {
'title': "Profile",
'act': 'profile',
'u_form': u_form,
'p_form': p_form,
}
return render(request, 'users/profile.html', context)
users/profile.html
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block title %} {{ title }} {% endblock title %}
{% block content %}
<div class="content-section align-content-center">
<div class="media py-3">
<img src="{{ user.profile.image.url }}" alt="" class="rounded-circle img-thumbnail" height="10" width="180">
<div class="media-body">
<h2 class="account-heading pl-3">{{ user.get_full_name }}</h2>
<p class="text-secondary pl-3">{{ user.email }}</p>
</div>
</div>
<form action="" method="POST" enctype="multipart/form-data">
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4">Profile Info</legend>
{{ u_form|crispy }}
{{ p_form|crispy }}
</fieldset>
<div class="form-group">
<button class="btn btn-outline-info" type="submit">Update</button>
</div>
</form>
</div>
{% endblock %}
SOLVED
Bug was in below Profile view, I was checking if request.POST == 'POST' which should be as below. As request.POST returns a QuerySet not a string.
#login_required
def profile(request):
if request.method == 'POST':
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():
u_form.save()
p_form.save()
messages.success(request, "Your profile has been updated !")
return redirect('profile')
else:
u_form = UserUpdateForm(instance=request.user)
p_form = ProfileUpdateForm(instance=request.user.profile)
context = {
'title': "Profile",
'act': 'profile',
'u_form': u_form,
'p_form': p_form,
}
return render(request, 'users/profile.html', context)
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)
...