Package: django-dragndrop-related
django-dragndrop-relatedAdd drag-and-drop multiple uploading to any Django model where arelated modelis used to store images or files, using the awesomeDropzone.js.The example project shown usesdjango-admin-thumbnailsto showImageFieldpreview thumbnails.RationaleOne of the most common requests I get from clients when working on Django projects is to support some kind of drag-and-drop upload to save them the tedium of working with multiple file upload fields. I finally put some effort into solving this problem and came up with this library, which essentially provides for the creation of related models via AJAX POST request.It assumes some simplicity on the part of the related model – e.g. that a valid instance only requires a singleImageFieldorFileFieldto be populated – and usesDropzone.jsto accept uploads and fire off POST requests to an endpoint which creates new child models using the related manager of the parent model.I decided not to try to support drag-and-drop uploads whencreatingparent model instances, since the uploads would need to be stashed somewhere temporarily then associated with the new model when it was saved. Instead this library operates only on existing model instances and requires the user to reload the page once they're done dropping files, so that Django's admin/inline UI can display the newly created child models for editing. This is acceptable in my use-cases but may not be in yours.CompatibilityThis library has been tested on Django 3.2 and 4.0 on Python 3.8, though I expect it to be fairly compatible with other versions. For now, the package is marked as requiring Python 3.6 or higher.Please note that this library is an early beta release, mostly published so that I can share code between my own projects. It works well for my specific use-case but your mileage may vary. If you have issues with the library please open a ticket and I'll review it, but be aware it's not being developed intensively at this stage.Installation$ pip install django-dragndrop-relatedUsageAdddragndrop_relatedto yourINSTALLED_APPSsetting:INSTALLED_APPS=[# ...'dragndrop_related',]Import the mixin and apply it to your "parent" class'sModelAdmin:fromdjango.contribimportadminfromdragndrop_related.viewsimportDragAndDropRelatedImageMixinfrom.modelsimportAlbum,Image''' Assuming a 'parent' model of Album and a 'child' model of Image, relatedto Album by a `ForeignKey` field (see examples below)'''classImageInline(admin.StackedInline):extra=0model=Image@admin.register(Album)classAlbumAdmin(DragAndDropRelatedImageMixin,admin.ModelAdmin):inlines=[ImageInline]Usage in combination withdjango-soloThedjango-sololibrary provides its own adminchange_formtemplate with some minimal UI changes to assist with singleton models. When usingdjango-dragndrop-relatedwith adjango-solosingleton model, there is a different mixin which will preserve the proper template inheritance:fromdragndrop_related.viewsimportDragAndDropSingletonRelatedImageMixinfromsolo.adminimportSingletonModelAdmin@admin.register(models.Homepage)classHomepageAdmin(DragAndDropSingletonRelatedImageMixin,SingletonModelAdmin):# ...ConfigurationThe library makes a few assumptions about your models and their relationship. Consider the following example models:classAlbum(models.Model):# ...classImage(models.Model):# ...album=models.ForeignKey('gallery.Album',related_name='images')image=models.ImageField()When adding related child instances to a parent model instance,the library will attempt to use a related manager calledimages. This can be overridden by specifying therelated_manager_field_nameproperty on the class that inherits fromDragAndDropRelatedImageMixin, e.g.classImage(models.Model):# ...album=models.ForeignKey('gallery.Album',related_name='album_images')classAlbumAdmin(DragAndDropRelatedImageMixin,admin.ModelAdmin):# ...related_manager_field_name='album_images'The library assumes the field on the related child model where the uploaded images/files should be saved is calledimage.This can be overridden by specifying therelated_model_field_nameproperty on the class that inherits fromDragAndDropRelatedImageMixin, e.g.classImage(models.Model):# ...album=models.ForeignKey('gallery.Album',related_name='images')my_image=models.ImageField()classAlbumAdmin(DragAndDropRelatedImageMixin,admin.ModelAdmin):# ...related_model_field_name='my_image'If you use anordering fieldon your related child model, e.g. to implementdjango-admin-sortable2, you can specify it in yourModelAdminusing therelated_model_order_field_nameproperty anddjango-dragndrop-relatedwill set a useful value for the field when creating new related model instances. E.g.classImage(models.Model):# ...order=models.PositiveIntegerField()classMeta:ordering=['order']classAlbumAdmin(DragAndDropRelatedImageMixin,admin.ModelAdmin):# ...related_model_order_field_name='order'The Dropzone.js library supports anacceptFilesconfiguration option which restricts the types of files that can be selected or dropped in. If the field on your related child model is anImageField, anacceptFilesvalue ofimage/*will be passed to Dropzone.js. For aFileFieldno restriction is specified by default. You can override the value ofacceptFilespassed to Dropzone.js by specifying thedropzone_accepted_filesproperty on the class that inherits fromDragAndDropRelatedImageMixin, e.g.classAlbumAdmin(DragAndDropRelatedImageMixin,admin.ModelAdmin):# ...dropzone_accepted_files='application/pdf'See Mozilla'sdocumentation for thefileinput typefor more information about how these types can be specified.DevelopmentIf working locally on the package you can install the development tools viapip:$pipinstall-e.[dev]Run the bundled Django example project:$cdexample_project
$pythonmanage.pymigrate
$pythonmanage.pycreatesuperuser
$pythonmanage.pyrunserver0.0.0.0:8000
$openhttp://localhost:8000/admin/Navigate to the exampleAlbummodel in theGalleryapp to see the widget in action.To lint withflake8:$flake8Issues, Suggestions, Contributions...are welcome on GitHub. Thanks for your interest indjango-dragndrop-related!