i am unable to change profile pic in django - 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/'

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

Logged in user information incorrectly dispalyed

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.

django def post method isnt working in cbv

i can't figure our why i can't override the post . when i post the form i go to "/" directory and nothing post . i already know knows that the forms works fine because i have it working as a fbv
my view
class ProfileUpdateView(LoginRequiredMixin, View):
template_name = "accounts/update.html"
def get_object(self):
user = get_object_or_404(User, username=self.kwargs.get("username"))
return user
def get(self, request, *args, **kwargs):
user = get_object_or_404(User, username=self.kwargs.get("username"))
user_form = UserForm(instance=user)
if user.is_client:
print("client get is working")
profile = Client.objects.get(id=user.clients.id)
profile_form = ClientForm(instance=profile)
if user.is_artisan:
profile = Artisan.objects.get(id=user.artisans.id)
profile_form = ArtisanForm(instance=profile)
return render(
request,
self.template_name,
{"user_form": user_form, "profile_form": profile_form},
)
def post(self, request, *args, **kwargs):
print("post is working")
if user.is_client:
print("client post is working")
profile_form = ClientForm(
request.POST, request.FILES, instance=profile
)
user_form = UserForm(request.POST, request.FILES, instance=user)
if user.is_artisan:
profile_form = ArtisanForm(
request.POST, request.FILES, instance=profile
)
user_form = UserForm(request.POST, request.FILES, instance=user)
if profile_form.is_valid() and user_form.is_valid():
print("form validation is working")
created_profile = profile_form.save(commit=False)
user_form.save()
created_profile.save()
reverse("accounts:profile", kwargs={"username": self.user.username})
return render(
request,
self.template_name,
{"user_form": user_form, "profile_form": profile_form},
)
template
<form action="." method="POST" enctype="multipart/form-data">
{% csrf_token %}
{{ user_form.as_p }}
<p> client form</p>
------------------------------------------------
{{ profile_form.as_p }}
<button class="btn btn-primary btn-round" type="submit">update</button>
</form>
Your form action is set to ".", i.e. "this directory".
Instead just leave it out to POST to the current URL.
<form method="POST" enctype="multipart/form-data">

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

Does not display form.errors when not valid

I use UserCreationForm to render registration form in Django.
class RegisterForm(UserCreationForm):
class Meta(UserCreationForm.Meta):
model = User
fields = UserCreationForm.Meta.fields
The registration view is defined as follows:
def register(request):
form = RegisterForm()
if request.method == 'POST':
form = RegisterForm(request.POST or None, request.FILES or None)
if form.is_valid():
form.save()
username = form.cleaned_data['username']
password = form.cleaned_data['password1']
user = authenticate(username=username, password=password)
login(request, user)
return redirect('/')
else:
context = {'form': form}
return render(request, 'registration/register.html', context)
And the template for this:
{% if form.errors %}
<p>Some Errors occured</p>
{% endif %}
<form action="{% url 'register' %}" method="POST">
{% csrf_token %} {{ form.as_p }}
<input type="submit" value="Register">
</form>
When I submit invalid data, it does not show <p>Some Errors occured</p>, but throws
Exception Type: ValueError
Exception Value:
The view myapp.views.register didn't return an HttpResponse object. It returned None instead.
which means I have to return HttpResponsein the 2nd if/else statement. The other forms work fine and show form.error messages, except this one. What is the problem? Thanks.
form = RegisterForm(request.POST or None, request.FILES or None)
first of all you dont wanna an empty field in your register form so you dont wanna user or None . second you are using request.FILES while you have no FileField in your form . i fixed your form
def register(request):
if request.method == 'POST':
form = RegisterForm(request.POST)
if form.is_valid():
form.save()
username = form.cleaned_data['username']
password = form.cleaned_data['password1']
user = authenticate(username=username, password=password)
login(request, user)
return redirect('/')
else:
form = RegisterForm()
return render(request, 'registration/register.html',{'form': form})
You need to move the last line back one indent, so it is run both in the case that the request is not a POST and also when it is a POST but the form is not valid.