So I've got a model with several fields, two of them being a photo and a video field. They are both of type FileField. I've already made a form before using the FileField type and everything worked correctly, but for some reason this time it is not. The settings.py is configured correctly, because I can upload a file through another form.
I can go into the Django admin and from there add an image and video for the photo and video field and the new directory is made and the image and video is stored and can be accessed with no problem. I'm a little stumped on this one. Thanks in advance.
Here is my model:
def get_image_path(instance, filename):
return os.path.join('images', str(instance.id), filename)
def get_video_path(instance, filename):
return os.path.join('videos', str(instance.id), filename)
class User(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
email = models.EmailField()
photo = models.FileField(upload_to=get_image_path, blank=True)
video = models.FileField(upload_to=get_video_path, blank=True)
def __unicode__(self):
return self.first_name + ' ' + self.last_name + ' - ' + self.email
Here is my form, which is a ModelForm:
class UserForm(forms.ModelForm):
class Meta:
model = User
And here is the view:
def index(request):
latest_poll_list = Poll.objects.order_by('-pub_date')[:5]
pollform = PollForm()
choiceform = ChoiceForm()
userform = UserForm()
all_users = User.objects.all()
if request.method == 'POST':
pollform = PollForm(request.POST, request.FILES)
choiceform = ChoiceForm(request.POST)
userform = UserForm(request.POST)
if pollform.is_valid():
pollform.comments = pollform.cleaned_data['comments']
pollform.save()
else:
pollform = PollForm()
if choiceform.is_valid():
choiceform.save()
else:
choiceform = ChoiceForm()
if userform.is_valid():
userform.save()
else:
userform = UserForm()
context = {'latest_poll_list': latest_poll_list, 'pollform': pollform,
'choiceform': choiceform, 'userform': userform, 'all_users': all_users}
return render(request, 'polls/index.html', context)
Here is the form associated with the ModelForm:
<form action="{% url 'polls:index' %}" method="POST" enctype="multipart/form-data">
{% csrf_token %}
{{ userform.as_p }}
<input type="submit" value="Submit">
</form>
Make sure you have enctype="multipart/form-data" as an attribute in your form tag.
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
<your form code>
</form>
Some other answers (i.e. this one) indicate you need to pass request.FILES to your Form if you're using a FileField. Is this your problem?
I.e. change this line:
userform = UserForm(request.POST)
to:
userform = UserForm(request.POST, request.FILES)
EDIT:
Django docs here.
Related
i am new in Django. i am having issue in updating ImageField.i have following code
in models.py
class ImageModel(models.Model):
image_name = models.CharField(max_length=50)
image_color = models.CharField(max_length=50)
image_document = models.ImageField(upload_to='product/')
-This is My forms.py
class ImageForm(forms.ModelForm):
class Meta:
model = ImageModel
fields = ['image_name', 'image_color' , 'image_document']
in Html file (editproduct.html)
<form method="POST" action="/myapp/updateimage/{{ singleimagedata.id }}">
{% csrf_token %}
<input class="form-control" type="text" name="image_name" value="{{ singleimagedata.image_name}}">
<input class="form-control" type="file" name="image_document">
<button type="submit" class="btn btn-primary">UPDATE PRODUCT</button>
</form>
-myapp is my application name. {{singleimagedata}} is a Variable Containing all fetched Data
-urls.py
urlpatterns = [
path('productlist', views.productlist, name='productlist'),
path('addproduct', views.addproduct, name='addproduct'),
path('editimage/<int:id>', views.editimage, name='editimage'),
path('updateimage/<int:id>', views.updateimage, name='updateimage'),
]
and Here is My views.py
def productlist(request):
if request.method == 'GET':
imagedata = ImageModel.objects.all()
return render(request,"product/productlist.html",{'imagedata':imagedata})
def addproduct(request):
if request.method == 'POST':
form = ImageForm(request.POST, request.FILES)
if form.is_valid():
form.save()
messages.add_message(request, messages.SUCCESS, 'Image Uploaded')
return redirect('/myapp/productlist')
else:
imageform = ImageForm()
return render(request, "product/addproduct.html", {'imageform': imageform})
def editimage(request, id):
singleimagedata = ImageModel.objects.get(id=id)
return render(request, 'product/editproduct.html', {'singleimagedata': singleimagedata})
def updateimage(request, id): #this function is called when update data
data = ImageModel.objects.get(id=id)
form = ImageForm(request.POST,request.FILES,instance = data)
if form.is_valid():
form.save()
return redirect("/myapp/productlist")
else:
return render(request, 'demo/editproduct.html', {'singleimagedata': data})
My image Upload is working fine.i can not Update image while updating data.rest of the data are updated.i don't know how to update image and how to remove old image and put new image into directory.
I think you missed the enctype="multipart/form-data", try to change:
<form method="POST" action="/myapp/updateimage/{{ singleimagedata.id }}">
into;
<form method="POST" enctype="multipart/form-data" action="{% url 'updateimage' id=singleimagedata.id %}">
Don't miss also to add the image_color field to your html input.
Because, in your case the image_color field model is designed as required field.
To remove & update the old image file from directory;
import os
from django.conf import settings
# your imported module...
def updateimage(request, id): #this function is called when update data
old_image = ImageModel.objects.get(id=id)
form = ImageForm(request.POST, request.FILES, instance=old_image)
if form.is_valid():
# deleting old uploaded image.
image_path = old_image.image_document.path
if os.path.exists(image_path):
os.remove(image_path)
# the `form.save` will also update your newest image & path.
form.save()
return redirect("/myapp/productlist")
else:
context = {'singleimagedata': old_image, 'form': form}
return render(request, 'demo/editproduct.html', context)
I had a similar issue while updating the profile_pic of user. I solved this with the following code I think this might help:
Models.py
class Profile(models.Model):
# setting o2o field of user with User model
user_name = models.OneToOneField(User, on_delete=models.CASCADE, blank=True, null=True)
first_name = models.CharField(max_length=70, null=True, blank=True)
last_name = models.CharField(max_length=70, null=True, blank=True)
profile_pic = models.ImageField(upload_to="images", blank=True, null=True,)
def __str__(self):
return str(self.user_name)
forms.py
class ProfileEditForm(ModelForm):
class Meta:
model = Profile
fields = '__all__'
# excluding user_name as it is a one_to_one relationship with User model
exclude = ['user_name']
views.py
#login_required(login_url='login')
def edit_profile(request, id):
username = get_object_or_404(Profile, id=id)
extended_pro_edit_form = ProfileEditForm(instance=username)
if request.method == "POST":
extended_pro_edit_form = ProfileEditForm(request.POST, request.FILES, instance=username)
if extended_pro_edit_form.is_valid():
extended_pro_edit_form.save()
next_ = request.POST.get('next', '/')
return HttpResponseRedirect(next_)
context = {'extended_pro_edit_form': extended_pro_edit_form}
return render(request, 'edit_profile.html', context)
edit-profile.html
<form action="" method="post"
enctype="multipart/form-data">
{% csrf_token %}
{{ extended_pro_edit_form.as_p }}
{{ extended_pro_edit_form.errors }}
<!--To redirect user to prvious page after post req-->
<input type="hidden" name="next" value="{{ request.GET.next }}">
<button type="submit">UPDATE</button>
</form>
Answer from #binpy should solve your problem. In addition to your second answer, you could do:
def updateimage(request, id): #this function is called when update data
data = ImageModel.objects.get(id=id)
form = ImageForm(request.POST,request.FILES,instance = data)
if form.is_valid():
data.image_document.delete() # This will delete your old image
form.save()
return redirect("/myapp/productlist")
else:
return render(request, 'demo/editproduct.html', {'singleimagedata': data})
Check delete() method on django docs.
some times something like cached old image is not replaced in the front-end so you might just need to forces refresh by pressing CTRL + F5 or clear your browsing history.
the answer given by #binpy is a needed update so that the files are passed to the back-end.
I am trying to make a matchmaking project on python django such as snapchat's hoop, but first I am trying to do the easiest part(what I know) which is just making the user create a profile to find a mate and then show that created profile to the other users, currently I am not using any matchmaking based on questions, I need to first show the created user to other users. The error comes when I pass the variables to the html via for loops, and now the mates.html file doesnt show anything. Please if you need more explanation let me know in the comments.
models.py (Profile model show the profile of the user which is created by default wen the user is created and Mates model shows the profile that the user has to create which provide an image and a description)
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
bio = models.CharField(max_length=400, default=1, null=True)
class Mates(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="user")
users_requests = models.ManyToManyField(User, related_name="users_requests")
req_bio = models.CharField(max_length=400)
req_image = models.ImageField(upload_to='requestmates_pics', null=True, blank=True, default=False)
views.py
def matesmain(request):
contents = Mates.objects.all()
args123 = {
'contents': contents,
}
return render(request, 'mates.html', args123)
def mates(request):
if request.method == 'POST':
form_mates = MatesForm(request.POST, request.FILES)
if form_mates.is_valid():
instance = form_mates.save(commit=False)
instance.user = request.user
instance.save()
return redirect('mates-main')
print('succesfully uploded')
else:
form_mates = MatesForm()
print('didnt upload')
return render(request, 'mates.html', {'form_mates': form_mates})
forms.py
class MatesForm(forms.ModelForm):
class Meta:
model = Mates
fields = ('req_bio', 'req_image',)
urls.py
urlpatterns = [
path('mates', views.mates, name='mates'),
path('mates-main', views.matesmain, name='mates-main'),
]
mates.html
<div class="mates">
<div class="mates-container">
{% for content in contents %}
<div class="mates-item">{{ content.user }}
</div>
{% endfor %}
<div class="mates-item">content(picture)
<form action="{% url 'mates' %}" method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form_mates.as_p }}
</form>
</div>
</div>
</div>
If you are displaying the form with the second function (mates), then you aren't sending any context for your fields to iterate over. Try like so:
def mates(request):
if request.method == 'POST':
form_mates = MatesForm(request.POST, request.FILES)
if form_mates.is_valid():
instance = form_mates.save(commit=False)
instance.user = request.user
instance.save()
return redirect('mates-main')
print('succesfully uploded')
else:
form_mates = MatesForm()
print('didnt upload')
context = {
'form_mates': form_mates,
'contents': Mates.objects.all()
}
return render(request, 'mates.html', context)
and in your other view (matesmain):
contents = Mates.objects.all()
args123 = {
'contents': contents,
'form_mates': MatesForm()
}
return render(request, 'mates.html', args123)
I'm not sure I understand, however, why you have two separate views for this.
I have a form that involves uploading a profile picture. I have it working so that I can upload images in the /admin/ interface and display them correctly, but I cannot get my Modelform to save the image.
Here is what I have:
models.py
class Candidate(models.Model):
UserID = models.ForeignKey(User, on_delete=models.CASCADE)
ElectionID = models.ForeignKey(Election, on_delete=models.CASCADE)
Bio = models.CharField(max_length=500, blank=True)
ProfilePicture = models.ImageField(upload_to="profilepics/", null=True, blank=True)
forms.py
class AddCandidateForm(forms.ModelForm):
class Meta:
model = Candidate
fields = ['ElectionID', 'Bio', 'ProfilePicture']
cand_reg.html (Template)
{% block content %}
<h1>Register as a candidate</h1>
<form method="POST" class="post-form">
{% csrf_token %}
<h2>Select an election:</h2><br>
{{form.ElectionID}}<br>
<h2>Enter your bio:</h2><br>
{{form.Bio}}<br>
<h2>Upload a profile picture:</h2><br>
{{form.ProfilePicture}}<br>
<button type="submit">Register</button>
</form>
{% endblock %}
When I try the view function like so I get the error:
MultiValueDictKeyError at /register/
"'ProfilePicture'"
views.py
def add_candidate(request):
if request.method == 'POST':
form = AddCandidateForm(request.POST, request.FILES)
if form.is_valid():
candidate = form.save(commit=False)
candidate = request.FILES['ProfilePicture']
candidate.UserID = request.user
candidate.save()
return redirect('/home/')
else:
form = AddCandidateForm()
return render(request, 'cand_reg.html', {
"form": form
})
views.py
When I remove the offending line, the error goes away.
def add_candidate(request):
if request.method == 'POST':
form = AddCandidateForm(request.POST, request.FILES)
if form.is_valid():
candidate = form.save(commit=False)
# candidate = request.FILES['ProfilePicture']
candidate.UserID = request.user
candidate.save()
return redirect('/home/')
else:
form = AddCandidateForm()
return render(request, 'cand_reg.html', {
"form": form
})
However, this doesn't actually save the image, so when I try to render it in a separate template, I get an error then.
Can anyone help me understand why the image isn't uploading?
Thanks in advance :)
You must set the ProfilePicture attribute of the model and not the instance itself (candidate = request.FILES['ProfilePicture']).
Change to:
candidate = form.save(commit=False)
candidate.ProfilePicture = request.FILES['ProfilePicture']
candidate.UserID = request.user
candidate.save()
Change your HTML form to accept files as well. Change to: <form method="POST" enctype="multipart/form-data" class="post-form">. When a form includes file inputs (<input type="file" />), then it must be encoded differently than it used when it includes only text. More here. If you right-click and inspect the {{form.ProfilePicture}} you'll see that this is actually a file input.
Extra one:
Please, do not name your class attributes (ProfilePicture, UserID etc) in PascalCase. Use snake_case instead (profile_picture, user_id etc).
Can anyone help me find my mistake.I am new to django.I want to upload a image using form.
#forms.py
class ProfileFormSt(forms.Form):
image_url = forms.FileField(required=False)
#views.py
class UpdateProfileStView(FormView):
template_name = "home/member_st_form.html"
def get(self, request, id):
user = User.objects.get(id=self.kwargs['id'])
profile = StudentProfile.objects.get(user=user)
form = ProfileFormSt(initial={
'image_url': profile.propic,
})
return render(request, self.template_name, {'form': form})
def post(self, request, id):
user = User.objects.get(id=self.kwargs['id'])
form = ProfileFormSt(request.POST, request.FILES)
profile = StudentProfile.objects.get(user=user)
if request.POST.get('image_url'):
profile.propic = request.POST.get('image_url')
profile.save()
return redirect('home:member-profile-st', id)
#member_st_form.html
<form action="" method="post" enctype="multipart/form-data">{% csrf_token %} {{ form.as_p }}
<button type="submit">update</button>
</form>
#models.py
class StudentProfile(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
propic = models.FileField(default="profile-icon.png")
request.POST.get('image_url') always returns empty...cant find what I did wrong...
Your image_url is a file field, so it should be present in request.FILES
if request.FILES['image_url']:
profile.propic = request.FILES['image_url']
Starting to beat my head against the wall...perhaps I am missing something simple.
models.py
class GFImage(models.Model):
image = models.ImageField(upload_to = 'uploads', null=True, blank=True)
views.py
def addImage(request):
errors = []
if request.method == 'POST':
form = ImageForm(request.POST, request.FILES)
if form.is_valid():
form.save()
urlRedirect = "/home"
return redirect(urlRedirect)
else:
form = ImageForm()
return render(request, "/add_image.html", {'form': form})
forms.py
class ImageForm(ModelForm):
class Meta:
model = GFImage
add_image.html
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
<table>
{{ form.as_table }}
</table>
<input type = "submit" value = "Submit">
</form>
Whatever I do, my form will not use the ClearableFileInput widget. It should default automatically, but even assigning it in the form's META will not work. What else could be blocking Django from using the clearable widget?
The ClearableFileInput will only display the clear checkbox when there's an initial file selected. Looking at your form, it looks like a a new form without initial data, so the checkbox won't be displayed.
def render(self, name, value, attrs=None):
.. snip ..
if value and hasattr(value, "url"):
template = self.template_with_initial
substitutions['initial'] = format_html(self.url_markup_template,
https://github.com/django/django/blob/5fda9c9810dfdf36b557e10d0d76775a72b0e0c6/django/forms/widgets.py#L372