Home > Software design >  Cant upload multilple images using django
Cant upload multilple images using django

Time:02-07

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">
  •  Tags:  
  • Related