When I'm trying to upload a user profile picture using form, which allowing users to edit their account information - nothing is happening.
I'm not sure what should I do, to get this upload working.
models.py:
class UserProfile(models.Model):
objects = models.Manager()
user = models.OneToOneField(User)
image = models.ImageField(upload_to='profile_image', blank=True)
def __str__(self):
return self.user.username
forms.py:
class EditProfileForm(forms.ModelForm):
class Meta:
model = UserProfile
fields = (
'image',
)
views.py:
def edit_profile(request):
if request.method == 'POST':
form = EditProfileForm(request.POST, instance=request.user.userprofile)
if form.is_valid():
form.save()
return redirect(reverse('accounts:view_profile'))
else:
form = EditProfileForm(instance=request.user.userprofile)
args = {'form': form}
return render(request, 'accounts/edit_profile.html', args)
settings.py:
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'mainapp/media')
edit-profile.html:
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Submit</button>
</form>
If you want to upload files(include images) to Django View, you should get FILES from request.FILES. so like this:
if request.method == 'POST':
form = EditProfileForm(request.POST, request.FILES, instance=request.user.userprofile)
if form.is_valid():
data = form.save(commit=False)
data.user = request.user
data.save()
return redirect(reverse('accounts:view_profile'))
Related
Good day,
I am testing some stuff with Django image Fields and the user model. The point is simply that any user can upload and update a profile picture. But when I select a picture and press upload, I get the message 'This field is required. So it's as if I haven't selected anything.
\\photo.html
<form method="POST">
{% csrf_token %}
{{ form }}
<button type="submit">Upload</button>
</form>
\\views.py
def photo_view(request):
try:
profile = request.user.userimage
except UserImage.DoesNotExist:
profile = UserImage(user=request.user)
if request.method == 'POST':
form = UserImageForm(request.POST, instance=profile)
if form.is_valid():
form.save()
return redirect('/dashboard/user/profile')
else:
form = UserImageForm(instance=profile)
return render(request, 'photo.html', {'form': form})
\models.py
class UserImage(models.Model):
user = models.OneToOneField(
settings.AUTH_USER_MODEL, default=None, null=True, on_delete=models.CASCADE)
photo = models.ImageField(
upload_to='images/', height_field=None, width_field=None, max_length=100)
def __str__(self):
return str(self.user)
\\settings.py
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'
I tried it with this one
https://www.geeksforgeeks.org/imagefield-django-models/
Do someone know a solution? Or should I even use the ImageField when working with images?
Thank you very much! :-)
There are two problems here: if you upload files, you need to specify enctype="multipart/form-data":
form method="POST" enctype="multipart/form-data">
{% csrf_token %}
{{ form }}
<button type="submit">Upload</button>
</form>
furthermore you need to pass both request.POST and request.FILES to the form:
def photo_view(request):
try:
profile = request.user.userimage
except UserImage.DoesNotExist:
profile = UserImage(user=request.user)
if request.method == 'POST':
form = UserImageForm(request.POST, request.FILES, instance=profile)
if form.is_valid():
form.save()
return redirect('/dashboard/user/profile')
else:
form = UserImageForm(instance=profile)
return render(request, 'photo.html', {'form': form})
I am able to update the image of each user's profile picture.
But not through the code. Though it doesn't give me any error.
u_form = For changing the username.
p_form = For changing the picture in their profile.
NOTE: Profile has one to one relation with the Profile model.
settings.py file section:
STATIC_URL = '/static/'
STATICFILES_DIRS = (os.path.join(BASE_DIR, 'static'),)
MEDIA_ROOT = os.path.join(BASE_DIR, 'media/')
MEDIA_URL = '/media/'
models.py for Profile model:
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
image = models.ImageField(default='default.jpeg', upload_to='profile_pics')
status = models.TextField(max_length='200')
def __str__(self):
return self.user.username
forms.py for the same:
class ProfileUpdate(forms.ModelForm):
class Meta:
model = Profile
fields = ['image',]
Main views.py file:
.
.
from django.shortcuts import render, redirect
from django.contrib.auth.forms import UserCreationForm as uc
from django.contrib.auth.forms import AuthenticationForm as af
.
.
#login_required(login_url='/login')
def update_profile(request):
user = request.user
if request.method == 'POST':
u_form = UserUpdate(request.POST, instance=user)
p_form = ProfileUpdate(request.POST, request.FILES, instance=user)
if u_form.is_valid() and p_form.is_valid():
u_form.save()
p_form.save()
messages.success(request, 'The profile has been updated.')
return redirect('/profile')
else:
#instance: to get pre-filled data of user
u_form = UserUpdate(instance=user)
p_form = ProfileUpdate(instance=user.profile)
context = {
'u_form': u_form,
'p_form': p_form
}
return render(request, 'update_profile.html', context)
HTML form "update_profile.html":
<form action="{% url 'update_profile' %}" method="POST" enctype="multipart/form-data">
{% csrf_token %}
{{ u_form }}
{{ p_form }}
<button type="submit">submit</button>
</form>
Try this:
p_form = ProfileUpdate(request.POST, request.FILES, instance=user.profile)
tl;dr How to autofill an editable form with information stored in database
Hey, Im creating a profile page for an application using Django as a framework. And Im having some annoying issues when a user is editing their page. As it is now, the user has to retype every field in the form, to edit a single field.. Cause my view has to delete the previous information in each field, or I get some annoying errors.
So my question is, is there a way to autofill these fields in profile_edit.html with the strings corresponding to each field in the form, from the database?
Any help would be greatly appreciated :D
view.py
#login_required
def profile_edit(request):
form = ProfileUpdateForm(request.POST, request.FILES)
if request.method == 'POST':
if form.is_valid():
user = request.user
if 'image' in request.FILES:
user.profile.image = request.FILES['image']
user.profile.bio = form.cleaned_data.get("bio")
user.profile.birth_date = form.cleaned_data.get("birth_date")
user.profile.location = form.cleaned_data.get("location")
user.save()
return redirect('profile')
else:
form = ProfileUpdateForm()
context = {
'form' : form
}
return render(request, 'webside/profile_edit.html', context)
models.py
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
bio = models.TextField(max_length=500, blank=True)
location = models.CharField(max_length=30, blank=True)
birth_date = models.DateField(null=True, blank=True)
email_confirmed = models.BooleanField(default=False)
image= models.FileField(upload_to='profile_image/', blank = True)
def __str__(self):
return self.user.username
profile_edit.html
'{% csrf_token %}
{% for field in form %}
<p>
{{ field.label_tag }}<br>
{{ field }}
{% for error in field.errors %}
<p style="color: red">{{ error }}</p>
{% endfor %}
</p>
{% endfor %}'
pic of profile.html
forms.py
class ProfileUpdateForm(forms.ModelForm):
YEARS= [x for x in range(1900,2021)]
birth_date = forms.DateField( initial="21-06-1995", widget=forms.SelectDateWidget(years=YEARS))
class Meta:
model = Profile
fields = ('bio','birth_date','location','image')
The way you initialise your form in your view is all wrong:
def profile_edit(request):
user = request.user
# form = ProfileUpdateForm(request.POST, request.FILES) <-- remove
if request.method == 'POST':
form = ProfileUpdateForm(request.POST, request.FILES, instance=user.profile)
if form.is_valid():
form.save() # <-- you can just save the form, it will save the profile
# user.save() <-- this doesn't help you, it doesn't save the profile and since user isn't changed you don't need to save it!
return redirect(...)
# else:
# form = ProfileUpdateForm() <-- don't clear the form!
else: # GET
form = ProfileUpdateForm(instance=user.profile) <-- initialise with instance
context = {
'form' : form
}
return render(request, 'webside/profile_edit.html', context)
You need to add the instance to the form to update an existing instance. You shouldn't initialise an empty form if the form is not valid, because that means the user loses all the data if they made a mistake. You want to display the form with all the data and the errors in that case.
# models.py
class Profile(models.Model):
name = models.CharField(max_length=255)
image = models.ImageField(upload_to=image_path, blank=True, null=True)
# forms.py
class ProfileForm(ModelForm):
class Meta:
model = Profile
fields = '__all__'
# views.py
def profile(request, id):
p = get_object_or_404(Profile, pk=id)
profile_form = ProfileForm(request.POST or None,
files=request.FILES or None,
instance=p)
if request.method == 'POST':
if profile_form.is_valid():
profile_form.save()
return render(request, 'profile.html', {'form': profile_form})
#profile.html
<form method="post" action="" enctype="multipart/form-data" >
{% csrf_token %}
{{ form }}
<input type="submit" value="Submit" />
</form>
If a user GETs /profile/1 and 1 exists, they get the form prefilled with all the values, including the image (if any)
If the user then POSTs updates to any of the fields except the image (clearing or changing), The page renders correctly after the update.
However, if the user changes the Image (clear or change), the change is not reflected in the rendered result: The image is always shown as empty. a quick GET solves the situation and displays the changed situation.
Does anyone know why the image field doesn't show the update in this situation?
Don't you have to do some sort of redirection to somewhere(obviously with a GET) when the profile form is successfully saved? You were always returning render.... and if you are having a POST request the form is going to stay with the POST data. So it should be:
# views.py
def profile(request, id):
p = get_object_or_404(Profile, pk=id)
profile_form = ProfileForm(request.POST or None, files=request.FILES or None, instance=q)
if request.method == 'POST':
if profile_form.is_valid():
profile_form.save()
# do the GET request to some page
return redirect('some-view-name', foo='bar')
return render(request, 'profile.html', {'form': profile_form})
Hello I followed steps here;Need a minimal Django file upload example I'm not sure what I did wrong. I'm trying to add a feature that user to be able to post pictures as well. Here's my try
settings.py
MEDIA_ROOT = os.path.join(os.path.dirname(BASE_DIR), "static_in_env", "media_root")
MEDIA_URL = '/media/'
models.py
class Category(models.Model):
image = models.ImageField(upload_to='images',blank=True, null=True)
forms.py
class CategoryForm(forms.ModelForm):
name = forms.CharField(max_length=128)
description = forms.CharField(max_length=300)
image = forms.ImageField()
class Meta:
model = Category
my views.py
#login_required
def add_category(request):
if not request.user.is_superuser and Category.objects.filter(author=request.user).exists():
return render(request,'main/category_already_exists.html')
if request.method == 'POST':
category = Category(author=request.user)
form = CategoryForm(request.POST, instance=category)
if form.is_valid():
form.save(commit=True)
return redirect('index')
else:
form = CategoryForm()
return render(request, 'main/add_category.html', {'form':form})
category.html
{% load staticfiles %}
{{category.image}}
I am assuming you are missing enctype form attribute in your template.
<form method="POST" enctype="multipart/form-data">
{{ form.as_p }}
<input type="submit" value="Submit" />
</form>
Also, in your views, instantiating your form should be
form = CategoryForm(request.POST, request.FILES, instance=category)