Replicating Django forms request.FILES to upload multiple image files using smartfields
Asked Answered
C

1

1

I'm trying to take a single image using Django forms and upload it with resized version under 3 headers. I'm even able to do so with request.POST QueryDict but not with request.FILES MultiValueDict even after it shows filled data for respective field names.

My Views.py

def image_add(request,article_id):
    template_name = 'blogs/image_add.html'
    articles = Article.objects.get(article_id=article_id)
    form = ImageAddForm
    if request.method == 'POST':
        image = request.FILES["image_1080"]
        request.FILES['image_800'] = image
        request.FILES['image_350'] = image
        print(request.POST)
        print(request.FILES)
        form = ImageAddForm(request.POST, request.FILES)
        if form.is_valid():
            new_form = form.save(commit=False)
            new_form.dir_id = article_id
            new_form.save()
            return redirect('/')
    context = {'form':form,'articles':articles}
    return render(request, template_name,context)

My Models.py

from smartfields import fields
from smartfields.dependencies import FileDependency
from smartfields.processors import ImageProcessor

    class Images(models.Model):
        dir_id = models.CharField(max_length=10,null=True)
        image_1080 = fields.ImageField(upload_to=img_1080_dir_path, name="image_1080", dependencies=[
            FileDependency(processor=ImageProcessor(
                format='PNG', scale={'max_width': 1080, 'max_height': 1080}))
        ])
        image_800 = fields.ImageField(upload_to=img_800_dir_path, blank=True, name="image_800", dependencies=[
            FileDependency(processor=ImageProcessor(
                format='PNG', scale={'max_width': 800, 'max_height': 800}))
        ])
        image_350 = fields.ImageField(upload_to=img_350_dir_path, blank=True, name="image_350", dependencies=[
            FileDependency(processor=ImageProcessor(
                format='PNG', scale={'max_width': 350, 'max_height': 350}))
        ])

My Forms.py

class ImageAddForm(forms.ModelForm):
    class Meta:
        model = Images
        fields = ('name','alt_text','image_1080')
        widgets = {
            'name': forms.TextInput(attrs={'class': 'form-control'}),
            'alt_text': forms.TextInput(attrs={'class': 'form-control'}),
            'image_1080': forms.ClearableFileInput(attrs={'class': 'form-file-input'})
            }

This saves only one image - 'image_1080' but not the other two.

Chequerboard answered 17/3, 2021 at 20:22 Comment(0)
I
1

Your approach of overwriting POST parameters is more of a hack, because conceptually it means you are ignoring the data that suppose to come in from the user. So this is something I would recommend against in general:

    if request.method == 'POST':
        image = request.FILES["image_1080"]
        request.FILES['image_800'] = image
        request.FILES['image_350'] = image

I suspect this approach doesn't work because the same instance of the file is shared among many fields. Correct approach instead would be to simply use one form field as input and let smartfields attach other fields to the model for you. Also, I recommend keeping the original file uploaded, just in case if you ever need to resize and change the format again in the future:

from smartfields import utils

class Images(models.Model):
    image = fields.ImageField(
        upload_to=utils.UploadTo(generator=True, field_name='image'),
        dependencies=[
            FileDependency(suffix='1080', processor=ImageProcessor(
                format='PNG', scale={'max_width': 1080, 'max_height': 1080}),
            FileDependency(suffix='800', processor=ImageProcessor(
                format='PNG', scale={'max_width': 800, 'max_height': 800}),
            FileDependency(suffix='350', processor=ImageProcessor(
                format='PNG', scale={'max_width': 350, 'max_height': 350}))
        ])

When uploading an image to image field, smartfields will automatically add extra fields to you Images model, eg:

> i = Images(my_image)
> i.save()
> print(i.image)      # original
> print(i.image_1080) # resized to 1080
> print(i.image_800)
Impale answered 18/3, 2021 at 13:12 Comment(1)
This is it. The best library for such handling. There are solution via views and super save in models but they throw exceptions due to mis-handling of inheritance by people like me. Thanks a lot buddy.Chequerboard

© 2022 - 2024 — McMap. All rights reserved.