ParsaAi
ParsaAi

Reputation: 349

Django - ImageField with multiple images

I have a model that has an ImageField. I want users to be able to upload multiple images for an object of the model - not only a single image. How can this be done? Whether with and image field or another approach.

Upvotes: 2

Views: 8009

Answers (2)

Gift Jeremiah
Gift Jeremiah

Reputation: 19

You can store several images to a single field in your django product model.

The summarized logic is to create a model form field that enables multifile upload selection, then upload this images (in my case i uploaded them to cloudinary since i already set up cloudinary to handle all my file uploads in my django project) then retrieve the urls of these images and assign them to a single field in your model instance so you can always fetch that field and get the urls for your images.

Here's the code snippet of my current implementation to assist you Let's say i have a Product Model

class Product(models.Model):
    #your other fields
    multiview_images = models.TextField(blank=True,null=True) 

    #other fields

    def get_multiview_images_list(self):
        if self.multiview_images:
            try:
                urls = json.loads(self.multiview_images)
                return [ {url} for url in urls]
            except json.JSONDecodeError as e:
                print("JSON Decode Error:", e)
        return []

    def set_multiview_images(self, images):
        self.multiview_images = json.dumps(images)
 

productmodelform.py

class ProductModelForm(forms.ModelForm):
    files = MultiFileField(min_num=1, max_num=10)

    class Meta:
        model = Product
        fields = '__all__'

    def save(self, commit=True):
        instance = super().save(commit=False)
        files = self.cleaned_data['files']
        multiview_images = []

        for file in files:
            cloudinary_url = cloudinary.uploader.upload(file)['url']
            print(cloudinary_url)
            multiview_images.append(cloudinary_url)

        instance.multiview_images = json.dumps(multiview_images)

        if commit:
            instance.save()
        return instance

admin.py

class ProductAdmin(admin.ModelAdmin):
    list_display = [field.name for field in Product._meta.fields]
    form = ProductModelForm

    admin.site.register(Product, ProductAdmin)

The modelform field will create a multiple upload button that enables you to upload multiple files from your local storage, then it will upload them to cloudinary and return each of the image urls as a list to your images field in product model which will be stored as a list or array of urls in your images field.

When you make an api call to the product endpoint, the get_multiview_images_list field would look like this ( Don’t forget to add to expose this field in your serializers.py list of fields)

    [
        [url1],
        [url2],
        [url3],
        [url10]
    ]

Please note that this implementation only works when you're uploading from the django admin dashboard. You can always set a limit to the max and minimum number of uploads in your productmodelform.

Upvotes: 1

Mikhail Khromov
Mikhail Khromov

Reputation: 165

You cannot store several images in one ImageField.

One solution for this problem would be to create an additional model (I called it "Attachment" for my social network pet project, call your's whatever should suit you) and have it reference the original model in a Foreign key. That way you can upload as many images as you want and create an instance of that new model for each new image.

Example Attachment model:


class Attachment(DatetimeCreatedMixin, AuthorMixin):
    class AttachmentType(models.TextChoices):
        PHOTO = "Photo", _("Photo")
        VIDEO = "Video", _("Video")

    file = models.ImageField('Attachment', upload_to='attachments/')
    file_type = models.CharField('File type', choices=AttachmentType.choices, max_length=10)

    publication = models.ForeignKey(TheOriginalModelYouUsedImageFieldIn, on_delete=models.CASCADE, verbose_name='Model that uses the image field')

    class Meta:
        verbose_name = 'Attachment'
        verbose_name_plural = 'Attachments'

Upvotes: 4

Related Questions