django-cabinet - Media library for Django¶
Version 0.18.3
django-cabinet is a media library for Django implemented while trying to write as little code as possible to keep maintenance at a minimum. At the time of writing the projects consists of less than 1000 lines of code (excluding tests), but still offers hierarchical folders, downloads, images with primary point of interest (courtesy of django-imagefield) and drag-drop uploading of files directly into the folder view.
Screenshots¶
List of root folders¶
Folder view with subfolders and files¶
File details with primary point of interest¶
Installation¶
pip install django-cabinetAdd
cabinetandimagefieldto yourINSTALLED_APPSMaybe replace the file model by setting
CABINET_FILE_MODEL, but the default should be fine for most uses.
High-level overview¶
django-cabinet comes with two concrete models, cabinet.File and
cabinet.Folder.
Folders can be nested into a hierarchy.
Files by default have two file fields, one for images based on
django-imagefield and one for downloads, a standard Django
FileField. Exactly one field has to be filled in. Files can only be
added to folders; files can never exist in the root folder.
Using cabinet files in your models¶
The recommended way to use cabinet files in your models is by using
cabinet.fields.CabinetForeignKey. When using raw_id_fields for
the file foreign key you automatically get an improved widget which 1.
allows directly uploading files inline without having to open the
raw_id_fields popup and 2. also displays small thumbnails for image
files.
Using django-cabinet as a CKEditor filebrowser¶
django-cabinet has built-in support for being used as a CKEditor 4 file manager. Currently, it only supports browsing files or images. Directly uploading files isn’t supported since the file browser API does not know about cabinet’s folders and folders are required for adding files to cabinet.
The values for using django-cabinet as a file and image browser follow (assuming you’re using the default file model):
CKEDITOR.config.filebrowserBrowseUrl = "/admin/cabinet/file/?_popup=1";
CKEDITOR.config.filebrowserImageUrl = "/admin/cabinet/file/?_popup=1&file_type=image_file";
Replacing the file model¶
The file model is swappable, and should be easy to replace if you require additional or different functionality. If, for example, you’d want to move all PDFs to a different storage, build on the following example code.
First, models.py:
from django.db import models
from django.db.models import signals
from django.dispatch import receiver
from django.utils.translation import gettext_lazy as _
from cabinet.base import AbstractFile, ImageMixin, DownloadMixin
class PDFMixin(models.Model):
pdf_file = models.FileField(
_('pdf'),
upload_to=...,
storage=...,
blank=True,
)
class Meta:
abstract = True
verbose_name = _("PDF")
verbose_name_plural = _("PDFs")
# Cabinet requires a accept_file method on all mixins which
# have a file field:
def accept_file(self, value):
if value.name.lower().endswith('.pdf'):
self.pdf_file = value
return True
class File(AbstractFile, ImageMixin, PDFMixin, DownloadMixin):
FILE_FIELDS = ['image_file', 'pdf_file', 'download_file']
# Add caption and copyright, makes FileAdmin reuse easier.
caption = models.CharField(
_('caption'),
max_length=1000,
blank=True,
)
copyright = models.CharField(
_('copyright'),
max_length=1000,
blank=True,
)
# Add additional fields if you want to.
# If files should be automatically deleted (this is also the case when
# using the default file model):
@receiver(signals.post_delete, sender=File)
def delete_files(sender, instance, **kwargs):
instance.delete_files()
Next, admin.py:
# You do not have to build on top of FileAdmin, but if there's no
# good reason not to it's probably much less work. If not, you
# still should take a long look at cabinet.base_admin.FileAdminBase
from django.contrib import admin
from cabinet.admin import FileAdmin
from .models import File
# The default should probably work fine.
admin.site.register(File, FileAdmin)
Then, add CABINET_FILE_MODEL = 'yourapp.File' to your Django
settings and at last you’re ready for running ./manage.py
makemigrations and ./manage.py migrate.
Change log¶
Next version¶
Fixed a bug where passing
folder__id__exacttwice in the URL would mistakenly use the first instead of the second value. Also, tightened folder ID validation a bit.Improved the folder selection when moving files a bit: The hierarchy is now collapsed except for the path to the current folder.
0.18 (2025-08-28)¶
Updated pre-commit hooks.
Added Python 3.13, Django 5.2.
Improved the folder deletion error messages (differentiate between missing permissions and protection errors).
Clarified the “delete folder” checkbox a bit: Folders containing files will not be deleted.
0.17 (2024-09-24)¶
Pruned the CI matrix.
Dropped compatibility with Python < 3.10.
Added russian translations. Thanks @1vank1n.
0.16 (2024-07-30)¶
Dropped support for Python 3.8.
Added a management command which allows exporting a folder as a ZIP archive. Thanks @fabiangermann!
0.15 (2024-07-01)¶
Added a Turkish translation. Thanks @mcihad!
Added the
extra_contextargument to ourchangelist_view. Thanks @underdoeg!Switched from ESLint to biome.
Dropped the inline upload form in the cabinet foreign key widget. It was extremely slow when having many folders and many cabinet foreign keys.
0.14 (2024-02-02)¶
Added Django 5.0, Python 3.12.
Updated the pre-commit hooks and added ESLint again (it was inadvertently dropped).
Dropped the unique constraint on folder name per subfolder. Duplicate names are a minor issue compared to the integrity errors which happen while loading fixtures.
0.13 (2023-07-21)¶
Added Django 4.1 and 4.2 to the CI matrix.
Added Python 3.11.
Switched to ruff and hatchling.
Documented that you should add a
post_deletehandler yourself when replacing the default file model.Fixed a problem where the folder filter stopped working in the upcoming Django 5.0.
0.12 (2022-09-19)¶
Fixed a bug where mixins couldn’t be used as base classes of a custom file model.
Changed the file admin to never collapse the advanced fieldset by default.
Switched from Travis CI to GitHub actions.
Fixed a regression where the CKEditor plugin’s
forms.Mediadeclaration was missing the jQuery dependency.Specified the default
AutoFieldfor django-cabinet to avoid migrations.Added an additional safeguard against unhandleable images.
Fixed the
default_app_configdeprecation warning.Raised the minimum versions of Python to 3.8 and Django to 3.2.
0.11 (2020-09-12)¶
Verified compatibility with Django 3.1 and Python 3.8 (no changes necessary).
Removed
skipIfstatements from the testsuite still referencing Django < 1.11.Switched the testsuite to using sqlite3 instead of PostgreSQL. django-tree-queries supports different databases
Dropped Python 3.4 from the testsuite.
Updated ESLint and prettier used to format and check the CSS/JavaScript code.
Added isort.
0.10 (2019-12-19)¶
Changed files and folders to reuse more of django-tree-queries.
Made our inline upload JavaScript specify its dependency on
django.jQuery.Verified compatibility with Django 3.0.
Changed the abstract file model to protect files against cascading folder deletions.
0.9 (2019-04-15)¶
Changed
CabinetForeignKeyto reference the configured file model by default.Limited the maximum width of the inline folder select widget.
Added tests for the
CabinetForeignKey.Hardened the file upload route a bit.
Removed a leftover call to versatileimagefields’
delete_all_created_imagesfunction.Improved test coverage, mainly by actually writing more tests.
Changed
reversecall sites to explicitly specifycurrent_app.Implemented optional autoselection of the last visited folder by explicitly specifying
?folder__id__exact=last.Made
CabinetForeignKeyautomatically open the last folder for new files.Dropped compatibility with Django 1.8 again.
Made our JS files’ dependency on
django.jQueryexplicit.Raised the length of file fields from
100to1000.
0.8 (2018-12-14)¶
Fix a problem where newer Django versions would crash because of a missing
inline_admin_formsetsvariable in the admin change form context.Fixed the folder hierarchy loop detection to not enter an infinite loop itself.
Fixed the breadcrumbs parent folder links.
Also prevented root folders with same name.
Added django-tree-queries for helping manage the folder tree.
Made search only search the current folder and its descendants.
Changed
OverwriteMixinto only overwrite files once as intended.Fixed a crash when moving several files at once with newer Django versions.
Reinstated the PPOI functionality in the default file admin interface.
Added a
cabinet.fields.CabinetForeignKeydrop-in replacement which extends theraw_id_fieldsadministration interface with a direct upload facility.Added configuration to make running prettier and ESLint easy.
Added compatibility with Django 1.8 so that migrating files from prehistoric django-filer versions gets easier.
Added more visible UI to upload several files at once.
Added timestamps to folders and files.
Added support for using django-cabinet as a CKEditor filebrowser.
Changed
FileAdmin.get_fieldsetsto automatically generate fitting fieldsets using the file mixins’ verbose name and editable fields.Added a filter for only showing files of a certain type.
Improved test coverage a bit and updated the documentation after actually using a swappable file model in a project.
Fixed a crash when an invalid primary key was specified as a query parameter in the admin changelist.
Modified responses when adding or editing files to always redirect to the containing folder instead of the root folder.
Fixed a possible crash when setting
_overwriteto true but uploading no new file.
0.7 (2018-03-28)¶
Switched the image field from django-versatileimagefield to django-imagefield. The latter uses the same database layout as the former, but there are differences when it comes to image generation and generating thumbnail URLs.
0.6 (2018-03-18)¶
Changed
admin_detailsto not include superfluous<br>tags.Changed the
accept_filemethods on file mixins to return bools and not raise exceptions.Fixed the
OverwriteMixinto calldelete_filesso that e.g. theimagefieldgets a chance of removing stale thumbnails.Dropped the useless
AbstractFile, and renamedAbstractFileBasetoAbstractFile.Added a guide on how to swap out the file model.
Added a hint to the files changelist that drag-drop upload is possible.
Disabled the drag-drop upload on the root folder (which would not have worked anyway, because files cannot be added to the root folder).
Added
unifyso that only one quoting style is used in the code.Changed the order of
accept_filemethods called to the order ofFILE_FIELDSinstead of the MRO (resp. the classes where the file fields are defined initially).Fixed the double saves in
OverwriteMixin, and hopefully avoided edge case-y problems withdelete_files.
0.5 (2018-03-13)¶
Made the folder CRUD functionality preserve query parameters so that
raw_id_fieldspopups work seamlessly.Fixed the changelist to not crash when images are broken.
Changed the admin fieldsets to only show fields related to one file type when a cabinet file is filled in already.
Fixed a bug where adding subfolders would succeed, but redirect to the root folder.
Added an admin action for moving multiple files at once to a different folder.
0.4 (2017-07-04)¶
Made file model mixins determine themselves whether they can accept an upload or not.
Refactoring and code cleanups.
Tweaked the file list a bit.
0.3 (2017-06-21)¶
Added upload progress (only files, not bytes).
Implemented cleaning of storage when deleting and replacing files.
0.2 (2017-06-21)¶
Allow replacing files remotely.
Added caption, copyright and alt text fields.
Also show folder breadcrumbs when adding files.
Drag-drop upload of files directly into the folder view.
0.1 (2017-06-20)¶
Initial public version.