Search code examples
pythondjangodjango-modelsdjango-modeladmin

How to check image width & height in Django admin class?


I have registered a class like below to have an admin panel to upload images:

android_dashboard.register(Banner, BannerAdmin)

The banner model is as below:

class Banner(models.Model):    
    image = ImageField(
        _('Image'), upload_to=upload_path, blank=True, null=True,
        content_types=['image/jpg', 'image/jpeg', 'image/png'],
        max_size=1 * 1024 * 1024, extensions=['jpg', 'jpeg', 'png']
    )    
    type_of_banner = models.CharField(_('Type of Banner'), max_length=3, default='web')

    class Meta:
        verbose_name = _('Banner')
        verbose_name_plural = _('Banners')

    def __str__(self):
        return '%s' % str(self.id)

And the model admin is like below:

class BannerAdmin(admin.ModelAdmin):
    model = Banner
    fields = ('image', 'type_of_banner')
    list_display = ('image', 'type_of_banner')

For now when I login into admin section I can upload image directly to server. But I want to check ratio before uploading the image.

The question is how and when should I check the image width & height before uploading the image?


Solution

  • If you want to validate dimensions before you upload it to your django backend I think you would have to use a custom widget with javascript.

    Something like this could work:

    class CustomImageInput(widgets.FileInput):
    
        def __init__(self, max_width, max_height, attrs=None):
            super(CustomImageInput, self).__init__(attrs)
            self.attrs.update({
                'data-max-width': max_width,
                'data-max-height': max_height,
                'class': 'custom-image-widget'
            })
    
        class Media:
            js = ('custom_image_widget.js',)
    

    custom_image_widget.js would contain somethink like:

    window.URL = window.URL || window.webkitURL;
    
    $(document).ready(function() {
        $(".custom-image-widget").change(function(e) {
            var data = $(this).data(),
                maxWidth = data.maxWidth,
                maxHeight = data.maxHeight;
    
            if ((file = this.files[0])) {
                var img = new Image();
                img.src = window.URL.createObjectURL( file );
    
                img.onload = function() {
                    var width = img.naturalWidth,
                        height = img.naturalHeight;
    
                    window.URL.revokeObjectURL( img.src );
    
                    if( width > maxWidth || height > maxHeight ) {
                        // Show error message
                        $(this).val("");
                    }
                };
            }
        }
        $(".custom-image-widget").each(function() {
            var data = $(this).data(),
                maxWidth = data.maxWidth,
                maxHeight = data.maxHeight;
    
        });
    });
    

    And then you need to attach this widget to your admin model ImageField:

    class BannerAdminForm(forms.ModelForm):
        class Meta:
            model = Banner
            widgets = {
              'image': CustomImageInput(max_height=400, max_width=300),
            }
            fields = '__all__'
    
    class BannerAdmin(admin.ModelAdmin):
        form = BannerAdminForm
    

    I based the javascript on this answer