Work in progress: django-imagekit but for all types of media files (movies, PDFs etc.). + private media
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

95 lines
3.7 KiB

# -*- coding: utf-8 -*-
from __future__ import unicode_literals
# Erik Stein <code@classlibrary.net>, 2016
from django import forms
from django.contrib.admin.widgets import AdminFileWidget
from django.db import models
from django.db.models.fields.files import FileDescriptor
from assetkit.files.storage import ProtectedMediaAssetStorage, FILENAME_MAX_LENGTH, ORIGINAL_FILE_PREFIX
from .utils import get_upload_path
# TODO Define the central storage somewhere more central
MEDIA_ASSET_STORAGE = ProtectedMediaAssetStorage()
DEFAULT_UPLOAD_TO = get_upload_path
class MediaAssetFileWidget(AdminFileWidget):
"""
Widget which understands ProtectedMediaAssetStorage
(knows that the url property is not relevant), also
does not provide a link to the original file.
# TODO Only admin access to the original file, if permissions apply
# TODO Add permission "allowed to view original file"
"""
# template_with_initial = (
# '%(initial_text)s: %(initial)s '
# '%(clear_template)s<br />%(input_text)s: %(input)s'
# )
def is_initial(self, value):
# Checks for 'name' instead of 'url' property
return bool(value and hasattr(value, 'name'))
# def get_template_substitution_values(self, value):
# # Does not use value.url
# return {
# 'initial': conditional_escape(value),
# }
class MediaAssetFileDescriptor(FileDescriptor):
# TODO Assign metadata fields like width/height
def __set__(self, instance, value):
previous_file = instance.__dict__.get(self.field.name)
super(MediaAssetFileDescriptor, self).__set__(instance, value)
# TODO Check if previous_file is actually None in our case; remove comment
# To prevent recalculating image dimensions when we are instantiating
# an object from the database (bug #11084), only update dimensions if
# the field had a value before this assignment. Since the default
# value for FileField subclasses is an instance of field.attr_class,
# previous_file will only be None when we are called from
# Model.__init__(). The ImageField.update_dimension_fields method
# hooked up to the post_init signal handles the Model.__init__() cases.
# Assignment happening outside of Model.__init__() will trigger the
# update right here.
if previous_file is not None:
pass # self.field.update_dimension_fields(instance, force=True)
# TODO MediaAssetFormField unused
class MediaAssetFormField(forms.FileField):
widget = MediaAssetFileWidget
class MediaAssetField(models.FileField):
# The descriptor to use for accessing the attribute off of the class.
description_class = MediaAssetFileDescriptor
def __init__(self, verbose_name=None, name=None, upload_to='', storage=None, *args, **kwargs):
kwargs['storage'] = kwargs.get('storage', MEDIA_ASSET_STORAGE)
kwargs['upload_to'] = kwargs.get('upload_to', DEFAULT_UPLOAD_TO)
# Field max length is the length of the file name plus the
# string ORIGINAL_FILE_PREFIX, two slashes and the uuid. The filename
# is shortened in the get_upload_path function.
field_max_length = FILENAME_MAX_LENGTH + 2 \
+ len(ORIGINAL_FILE_PREFIX) \
+ 32 # uuid_hex
kwargs['max_length'] = kwargs.get('max_length', field_max_length)
super(MediaAssetField, self).__init__(verbose_name, name, **kwargs)
def formfield(self, **kwargs):
defaults = {
# 'form_class': MediaAssetFormField,
'widget': MediaAssetFileWidget,
'max_length': FILENAME_MAX_LENGTH,
}
kwargs.update(defaults) # Force our values
return super(MediaAssetField, self).formfield(**kwargs)