koendewit / django-client-side-image-cropping

Widget for the Django ImageField that provides an interface for cropping the image client-side to a specific size.
BSD 3-Clause "New" or "Revised" License
17 stars 11 forks source link

Upload Multiple #13

Open michaelhjulskov opened 1 year ago

michaelhjulskov commented 1 year ago

Hi,

Are there any ways to implement this to work with multiple image upload?

In my case I need a multiple image uploader where user can add up to 10 profile images.

My thoughts... Either I add 10 more fields Or I add a Image model with foreignKey and use some kind of multiple file upload widget

Thanks

michaelhjulskov commented 1 year ago

I decided to add 10 image fields on the model in stead of using the multiple upload and saving in a separate image model.

I made this hack that allows to add one main profile image and up to 10 extra images. all cropped. javascript makes sure there is only one upload button ("+ add photo") visible.

models.py i added these

    image = models.ImageField(upload_to='datingprofile_images/', blank=True, verbose_name=_("Best photo of you"))
    photo1 = models.ImageField(upload_to='datingprofile_images/', blank=True)
    photo2 = models.ImageField(upload_to='datingprofile_images/', blank=True)
    photo3 = models.ImageField(upload_to='datingprofile_images/', blank=True)
    photo4 = models.ImageField(upload_to='datingprofile_images/', blank=True)
    photo5 = models.ImageField(upload_to='datingprofile_images/', blank=True)
    photo6 = models.ImageField(upload_to='datingprofile_images/', blank=True)
    photo7 = models.ImageField(upload_to='datingprofile_images/', blank=True)
    photo8 = models.ImageField(upload_to='datingprofile_images/', blank=True)
    photo9 = models.ImageField(upload_to='datingprofile_images/', blank=True)

    @property
    def photos(self):
        photos = []
        if self.photo1:
            photos.append(self.photo1)
        if self.photo2:
            photos.append(self.photo2)
        if self.photo3:
            photos.append(self.photo3)
        if self.photo4:
            photos.append(self.photo4)
        if self.photo5:
            photos.append(self.photo5)
        if self.photo6:
            photos.append(self.photo6)
        if self.photo7:
            photos.append(self.photo7)
        if self.photo8:
            photos.append(self.photo8)
        if self.photo9:
            photos.append(self.photo9)
        return photos

forms.py added this to my Form

    def __init__(self, *args, **kwargs):
        super(DatingProfileEditForm, self).__init__(*args, **kwargs)
        self.fields['image'].widget = ClientsideCroppingWidget(width=600, height=600, preview_width=250, preview_height=250, clearable=True, format="jpeg", quality=80)
        self.fields["image"].widget.attrs.update({'accept': 'image/*', 'capture':'camera'})
        self.fields['image'].required = True
        self.fields['photo1'].widget = ClientsideCroppingWidget(width=600, height=600, preview_width=250, preview_height=250, clearable=True, format="jpeg", quality=76)
        self.fields["photo1"].widget.attrs.update({'accept': 'image/*', 'capture':'camera'})
        self.fields['photo2'].widget = ClientsideCroppingWidget(width=600, height=600, preview_width=250, preview_height=250, clearable=True, format="jpeg", quality=76)
        self.fields["photo2"].widget.attrs.update({'accept': 'image/*', 'capture':'camera'})
        self.fields['photo3'].widget = ClientsideCroppingWidget(width=600, height=600, preview_width=250, preview_height=250, clearable=True, format="jpeg", quality=76)
        self.fields["photo3"].widget.attrs.update({'accept': 'image/*', 'capture':'camera'})
        self.fields['photo4'].widget = ClientsideCroppingWidget(width=600, height=600, preview_width=250, preview_height=250, clearable=True, format="jpeg", quality=76)
        self.fields["photo4"].widget.attrs.update({'accept': 'image/*', 'capture':'camera'})
        self.fields['photo5'].widget = ClientsideCroppingWidget(width=600, height=600, preview_width=250, preview_height=250, clearable=True, format="jpeg", quality=76)
        self.fields["photo5"].widget.attrs.update({'accept': 'image/*', 'capture':'camera'})
        self.fields['photo6'].widget = ClientsideCroppingWidget(width=600, height=600, preview_width=250, preview_height=250, clearable=True, format="jpeg", quality=76)
        self.fields["photo6"].widget.attrs.update({'accept': 'image/*', 'capture':'camera'})
        self.fields['photo7'].widget = ClientsideCroppingWidget(width=600, height=600, preview_width=250, preview_height=250, clearable=True, format="jpeg", quality=76)
        self.fields["photo7"].widget.attrs.update({'accept': 'image/*', 'capture':'camera'})
        self.fields['photo8'].widget = ClientsideCroppingWidget(width=600, height=600, preview_width=250, preview_height=250, clearable=True, format="jpeg", quality=76)
        self.fields["photo8"].widget.attrs.update({'accept': 'image/*', 'capture':'camera'})
        self.fields['photo9'].widget = ClientsideCroppingWidget(width=600, height=600, preview_width=250, preview_height=250, clearable=True, format="jpeg", quality=76)
        self.fields["photo9"].widget.attrs.update({'accept': 'image/*', 'capture':'camera'})

css

.dcsic_wrapper {
    width: 300px;
    position: relative;
    margin-bottom: 40px;
}
span.dcsic_delete_image {
    position: absolute;
    right: 5px;
    top: 47px;
}
span.dcsic_choose_img {
    background-color: #0d6efd;
    border-radius: 8px;
    padding: 10px 15px;
}
span.dcsic_choose_other_img {
    position: absolute;
    right: 5px;
    top: 5px;
}
img.dcsic_current_img {
    border-radius: 13%;
}

html added this js

$(document).ready(function() {
    $('.dcsic_ok,.dcsic_delete_image').on('click', function (e) { setTimeout(hide_extra_upload_photo, 200); });
    hide_extra_upload_photo();

    $("span.dcsic_choose_img").html('<i class="fa fa-plus"></i> {% trans "Add photo" %}').addClass('btn btn-primary');
    $("span.dcsic_choose_other_img").html('<i class="fa fa-pen fa-lg" title="{% trans "Choose other photo" %}"></i>');
    $("span.dcsic_delete_image").html('<i class="fa fa-trash fa-lg" title="{% trans "Delete photo" %}"></i>');
    $('label[for^=id_photo').hide();
    $('label[for^=id_photo').first().html('{% trans "More photos:" %}').show();

});

function hide_extra_upload_photo(){
    $('div.dcsic_wrapper:not(.has_image)').hide();
    $('div.dcsic_wrapper:not(.has_image)').first().show();
}
michaelhjulskov commented 1 year ago

I experience one issue now:

image field is required=True

reproduce issue:

add an "image" press submit/save, and image saved correctly

then press delete that image (I can see that input value is set to value="clear") i press submit and I expect to get an error message that tells me that I have to add an image.

after submit image is not deleted and I've got no error message.

How can this be fixed?

I suggest a solution could be something like: if input field is required, then always hide the delete button - and only show the "choose other image" button

Thanks