For loop on form not functing properly - django

I have a feature that allows users to upload multiple images to their blog but it is not working correctly. When a user uploads multiple images only one of them is uploaded to the postgres db.
view
def DetailPostView(request, pk):
model = Post
post = Post.objects.get(pk=pk)
if request.method == 'POST':
test = PostImagesForm(request.POST, request.FILES)
files = request.FILES.getlist('images')
if test.is_valid():
for f in files:
instance = test.save(commit=False)
instance.post = Post.objects.get(pk=pk)
instance.save()
else:
print(instance.errors)
postgallery = PostImages.objects.filter(post_id=post)
context = {
'post':post, 'PostImagesForm':PostImagesForm, 'postgallery':postgallery
}
return render(request, 'blog/post_detail.html', context)
form
class PostImagesForm(ModelForm):
class Meta:
model = PostImages
fields = ('images',)
widgets = {
'images': forms.ClearableFileInput(attrs={'multiple': True}),
}
you can see i am getting the list of files via the files = request.FILES.getlist('images') then running a for loop on the contents.
If I break the code in the stack trace I can see that the two files are in the list so i am very confused on why it is not properly iterating though the list and uploading each file to the db.
Update
Took a look into the docs and found a section on multi image upload and the docs are doing it the same way I am. Still very confused.

I believe the issue was the because I was not passing the current image into the model so it only uploaded the first image.
Solution
if request.method == 'POST':
for f in request.FILES.getlist('images'):
test = PostImagesForm(request.POST, request.FILES)
if test.is_valid():
instance = test.save(commit=False)
instance.post = Post.objects.get(pk=pk)
instance.images = f
instance.save()

Related

How do i maintain a user cover uploaded image in fields whiles adding new images without it getting deleted in django

How do i get Django to store already uploaded cover image to a user without getting it deleted when a new image is uploaded, but simply replace it? I'm having a challenge trying to figure out how to maintain old cover images while adding new once to a user. what happens is that when i upload a new cover image it simply deletes the previous one from the database.
Here is my cover image models:
class AccountCover(models.Model):
account = models.ForeignKey(Account,on_delete=models.CASCADE)
cover_image = models.ImageField(max_length=255,upload_to=get_cover_cover_image_filepath,default=get_default_cover_image,)
Here the view to upload cover image
cover = AccountCover.objects.filter(account=account.id).first()
if request.user:
forms = CoverImageForm(request.POST, request.FILES,instance=cover,
initial = {'cover_image':cover.cover_image})
if request.method == 'POST':
f = CoverImageForm(request.POST, request.FILES,instance=cover)
if f.is_valid():
data = forms.save()
data.account = cover.account
data.save()
return redirect('account:edit', account.id)
else:
f = CoverImageForm()
context['f'] = f
I would suggest adding a field called historical which is a boolean field in your class. Then, when a new image is uploaded you have to set historical=False and historical=True for all others. You can achieve this with:
cover = AccountCover.objects.filter(account=account.id).first()
if request.user:
forms = CoverImageForm(request.POST, request.FILES,instance=cover,
initial = {'cover_image':cover.cover_image})
if request.method == 'POST':
f = CoverImageForm(request.POST, request.FILES,instance=cover)
if f.is_valid():
data = forms.save()
data.account = cover.account
cover.historical=True
data.historical= False
data.save()
cover.save()
return redirect('account:edit', account.id)
else:
f = CoverImageForm()
context['f'] = f

Limit number of images user can upload

I have a blog feature on my site, users can upload a single main image and multiple supporting images. The issue I am facing is I want to be able to limit the number of images a user can upload. I understand that I could use a for loop on it but if the user goes back later and adds more it would make the for loop useless. So I figured the best way to do this would be to add a field to the model that would count the number of images uploaded and then I can use an if statement to check if more than a said number of images have been uploaded. How would i go about getting the number of images and adding them to the post while it is being created. Or should I go about this a different way
view
#login_required
def createPostView(request):
currentUser = request.user
postForm = PostForm()
if request.method == 'POST':
postForm = PostForm(request.POST, request.FILES)
if postForm.is_valid():
PostFormID = postForm.save(commit=False)
PostFormID.author = request.user
PostFormID.save()
for f in request.FILES.getlist('images'):
test = PostImagesForm(request.POST, request.FILES)
if test.is_valid():
instance = test.save(commit=False)
instance.post_id = PostFormID.id
instance.images = f
instance.save()
return HttpResponseRedirect("/")
return render(request, 'blog/post_form.html', {'postForm': postForm, 'PostImagesForm':PostImagesForm})
You can check the total items in a list before looping by using len.
len(request.FILES.getlist('images'))
>>> 10
So something like:
if len(request.FILES.getlist('images')) > 3:
raise Exception("Only three images allowed")
else:
// process the images in the for loop

Formset populated by wrong data - Django 1.8

Basic problem: I have a list of products, and when I go to edit a single product, the image upload formset is populated with all images in the folder, but it should only be populated by related images (see left hand side of picture below).
When I try to make any changes - to the product or to the images - it is unsuccessful, and the input boxes which were populated by unrelated images now display 'this field is required' (see right hand side of picture below)
Obviously, I need to successfully edit the product object, and I want this page to be populated only by images related to that product.
The View
def EditProduct(request, pk):
instance = get_object_or_404(Product, id=pk)
ImageFormSet = modelformset_factory(ProductImage,
form=ImageForm, extra=4)
if request.method == 'POST':
product_form = AddEditProductForm(request.POST, request.FILES, instance=instance)
formset = ImageFormSet(request.POST, request.FILES,
queryset=ProductImage.objects.none())
if product_form.is_valid() and formset.is_valid():
product = product_form.save()
images = formset.save(commit=False)
for image in images:
image.product = product
image.save()
return HttpResponseRedirect('/product/')
else:
print (product_form.errors, formset.errors)
else:
product_form = AddEditProductForm(instance=instance)
formset = ImageFormSet(queryset=ProductImage.objects.all()) # possible wrong queryset
return render(request, 'product/edit.html',
{'product_form': product_form, 'formset': formset},
context_instance=RequestContext(request))
So this code is somehow returning ALL of my uploaded images - including unrelated images - to the editing form for a single product - how do I make it so only those images which are related to the instance are displayed in the form?
On a related note - how do you access an individual image in the formset - for example if i wanted to remove one, what kind of modifications am I looking at?
This depends on your model.
formset = ImageFormSet(queryset=ProductImage.objects.all()) # possible wrong queryset
This is indeed the wrong queryset. You should do something like:
queryset=ProductImage.objects.filter(product_id = pk)
if you gave the product_image field a related_name than you could do
queryset=instance.related_product_images
https://docs.djangoproject.com/en/1.8/ref/models/fields/#django.db.models.ForeignKey.related_name

Uploading images from two formsets - Django

I have a page where you can add a product, add a thumbnail, and add images for the product.
I am using to formsets, seen below. The problem is that images uploaded to the image formset are uploaded correctly, but images uploaded to the thumbnail formset are not uploading at all... what might I be doing wrong?
def AddProduct(request):
ImageFormSet = modelformset_factory(ProductImage,
form=ImageForm, extra=4)
ThumbnailFormSet = modelformset_factory(ProductvThumbnail,
form=ThumbnailForm)
if request.method == 'POST':
product_form = AddEditProductForm(request.POST)
image_formset = ImageFormSet(request.POST, request.FILES, prefix='images',
queryset=roductImage.objects.none())
thumbnail_formset = ThumbnailFormSet(request.POST, request.FILES, prefix='thumbnail',
queryset=ProductThumbnail.objects.none())
if product_form.is_valid() and image_formset.is_valid() and thumbnail_formset.is_valid():
product = product_form.save()
thumbnails = thumbnail_formset.save(commit=False)
for thumbnail in thumbnails:
thumbnail.product = product
thumbnail.save()
images = image_formset.save(commit=False)
for image in images:
image.product = product
image.save()
return HttpResponseRedirect('/product/')
else:
print (product_form.errors, image_formset.errors, thumbnail_formset.errors)
else:
product_form = AddEditProductForm()
image_formset = ImageFormSet(queryset=ProductImage.objects.none(), prefix='images')
thumbnail_formset = ThumbnailFormSet(queryset=ProductThumbnail.objects.none(), prefix='thumbnail')
return render(request, 'product/add.html',
{'product_form': product_form, 'image_formset': image_formset,
'thumbnail_formset': thumbnail_formset},
context_instance=RequestContext(request))
I have found a solution - my formsets seem to be fine, the issue was in my models.py. The ImageField in the ProductThumbnail model was called 'image = models.ImageField...' but it should have been called thumbnail - that is why no thumbnails were being uploaded - my for loop was not finding anything.

Handling Image Uploads in Django

I have this view for my form:
if request.method == 'POST':
vehicle = VehicleForm(request.POST or None)
photos = PhotosFormSet(request.POST or None)
if vehicle.is_valid() and photos.is_valid():
new = vehicle.save()
photos = PhotosFormSet(request.POST, instance=new)
photos.save()
return HttpResponseRedirect('/vehicles/')
else:
prefix = "09-"
queryset = Vehicle.objects.all().order_by("stock_number")
if queryset == None:
last_rec = queryset.reverse()[0]
a = str(last_rec.stock_number)
b = int(a[-3:])+1
next = prefix+str(b)
else:
next = prefix+"001"
vehicle = VehicleForm(initial={'stock_number': next})
photos = PhotosFormSet(instance=Vehicle())
However when I try to save the record, the image field in PhotosFormset gives an error saying This field is required.
PhotosFormset is declared as PhotosFormSet = generic_inlineformset_factory(Photo, extra=5)
What am I missing here?
You don't appear to be binding uploaded files to your formset. You need to pass in request.FILES as well as request.POST:
photos = PhotosFormSet(request.POST, request.FILES, instance=new)
More info in the Django docs