I'm trying to create page to add new product with it's images in other model on my website using Djnago. The length of the list of images I get is always 0 and i'm getting IndexError: list index out of range. I guess that i'm getting files from request not properly using images = request.FILES.getlist('images')
models.py
class Products(models.Model):
product_name = models.CharField(
max_length=255, verbose_name='Product name')
product_slug = models.UUIDField(default=uuid.uuid4, editable=False, unique=True)
product_image = models.ImageField(
default='image-placeholder.png', verbose_name='Image')
creaton_date = models.DateTimeField(auto_now_add=True)
brand = models.ForeignKey(
Brands, verbose_name='Brand', on_delete=models.PROTECT)
price = models.FloatField(verbose_name='Price')
description = models.TextField(null=True, verbose_name='Description')
category = models.ForeignKey(
Categories, on_delete=models.CASCADE, verbose_name='Category')
bought_count = models.IntegerField(null=True, default=0)
class ProductImage(models.Model):
product = models.ForeignKey(Products, on_delete=models.CASCADE)
image = models.ImageField()
default = models.BooleanField(default=False)
def __str__(self):
return str(self.product)
template.html
<form id="checkoutform" action="" method="post">
{% csrf_token %}
<div >
<div >
<input type="text" name="product-name" placeholder="Product name">
</div>
<div >
<input type="text" name="brand" placeholder="Brand">
</div>
<div >
<input type="number" name="price" placeholder="Price">
</div>
<div >
<input type="file" multiple name="images" placeholder="Images">
</div>
<div >
<input type="text" name="desc" placeholder="Description">
</div>
<div >
<input type="text" name="category" placeholder="Category">
</div>
<input type="submit" value="Submit">
</form>
views.py
def create_product(request):
if request.user.is_superuser:
if request.method == 'POST':
data = request.POST
images = request.FILES.getlist('images')
brand = Brands.objects.get(name=data['brand'])
category = Categories.objects.get(name=data['category'])
product = Products.objects.create(
product_name = data['product-name'],
brand=brand,
price = data['price'],
description = data['desc'],
category = category,
image = images[0],
)
for i in range (1, len(images)):
image = ProductImage.objects.create(
product = product,
image = images[i]
)
return render(request, 'store/create_product.html')
else:
return HttpResponse("You are not allowed here")
CodePudding user response:
Well if you don't mind am going to suggest a another way to upload multiple images, by first creating separate model to handle images and also a form to handle multiple images upload.
Models.py
class Products(models.Model):
product_name = models.CharField(
max_length=255, verbose_name='Product name')
product_slug = models.UUIDField(default=uuid.uuid4, editable=False, unique=True)
product_image = models.ImageField(
default='image-placeholder.png', verbose_name='Image')
creaton_date = models.DateTimeField(auto_now_add=True)
brand = models.ForeignKey(
Brands, verbose_name='Brand', on_delete=models.PROTECT)
price = models.FloatField(verbose_name='Price')
description = models.TextField(null=True, verbose_name='Description')
category = models.ForeignKey(
Categories, on_delete=models.CASCADE, verbose_name='Category')
bought_count = models.IntegerField(null=True, default=0)
class productImage(models.Model):
product = models.ForeignKey(Product,on_delete=models.CASCADE)
image = models.ImageField(default='image-placeholder.png', verbose_name='Image')
Your would have to link the two models together in the admin by using StackedInine Like so:
Admin.py
from .models import Products,ProductImage
class ProductAdminImage(Admin.StackedInline)
model = ProductImage
@Admin.register(Products)
class ProductAdmin(Admin.ModelAdmin):
list_display = [] # fields that you want to display
inlines = [ProductAdminImage] # Here we are linking both models with an inline
Now We are going to work on the forms.py to handle multiple images upload
from .models import ProductImage
class ProductImageForm(forms.ModelForm):
class Meta:
model = ProductImage
fields = ['image']
widgets ={'image' :forms.ClearableFileInput(attrs={'multiple':True})}
Finally we focus on the view to manipulate uploads for our images, what you have done so far is good and but there's another way of uploading multiple images, this has worked for me in many cases!
from .forms import ProductImageForm
def create_product(request):
if request.user.is_superuser:
if request.method == 'POST':
data = request.POST
images = request.FILES.getlist('images')
brand = Brands.objects.get(name=data['brand'])
category = Categories.objects.get(name=data['category'])
form = ProductImageForm(request.POST, request.FILES)
product = Products(product_name = data['product-name'],brand=brand,
price = data['price'],
description = data['desc'],
category = category,
product_image = images[0],)
product.save()
if form.is_valid():
data = form.save(commit=False)
for files in images:
data =ProductImage(product = product, image = files)
data.save()
return render(request, 'store/create_product.html')
else:
return HttpResponse("You are not allowed here")
CodePudding user response:
For those who may have encountered a similar problem, the solution was incredibly obvious. I just forgot to add enctype="multipart/form-data" to my form (for uploading media files)
<form id="checkoutform" action="" method="post" enctype="multipart/form-data">
