14 changed files with 256 additions and 45 deletions
@ -1,3 +1,18 @@
|
||||
# -*- coding: utf-8 -*- |
||||
from __future__ import unicode_literals |
||||
# Erik Stein <code@classlibrary.net>, 2016 |
||||
|
||||
from django.contrib import admin |
||||
from django.db import models |
||||
from django.utils.translation import ugettext_lazy as _ |
||||
|
||||
from .models import MediaAsset |
||||
|
||||
|
||||
@admin.register(MediaAsset) |
||||
class MediaAssetAdmin(admin.ModelAdmin): |
||||
list_display = ['name', 'get_original_path'] |
||||
|
||||
# Register your models here. |
||||
def get_original_path(self, obj): |
||||
return obj.original_file.name |
||||
get_original_path.short_description = _("original path") |
||||
|
@ -0,0 +1,110 @@
|
||||
# -*- coding: utf-8 -*- |
||||
from __future__ import unicode_literals |
||||
# Erik Stein <code@classlibrary.net>, 2016 |
||||
|
||||
import os |
||||
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 django.utils.html import conditional_escape |
||||
from django.utils.text import slugify |
||||
|
||||
from ..storages import ProtectedMediaAssetStorage |
||||
|
||||
|
||||
# TODO Define the central storage somewhere more central |
||||
ORIGINALS_STORAGE = ProtectedMediaAssetStorage() |
||||
# TODO Move filename max length to storage |
||||
FILENAME_MAX_LENGTH = 255 |
||||
|
||||
|
||||
# TOD Move get_upload_path to utils |
||||
def get_upload_path(instance, filename): |
||||
""" |
||||
Returns /<uuid_hex>/original/<slugified_filename.ext> |
||||
where |
||||
- uuid is taken from instance, |
||||
- filename is slugified and shortened to a max length including the extension. |
||||
""" |
||||
name, ext = os.path.splitext(filename) |
||||
name = slugify(name) |
||||
name = name[:(FILENAME_MAX_LENGTH - len(ext))] |
||||
filename = "%s%s" % (name, ext) |
||||
return os.path.join( |
||||
instance.get_uuid(), |
||||
instance.STORAGE.ORIGINAL_FILE_PREFIX, |
||||
filename |
||||
) |
||||
|
||||
|
||||
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 Add 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) |
||||
|
||||
|
||||
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['max_length'] = kwargs.get('max_length', FILENAME_MAX_LENGTH) |
||||
kwargs['upload_to'] = kwargs.get('upload_to', DEFAULT_UPLOAD_TO) |
||||
kwargs['storage'] = kwargs.get('storage', ORIGINALS_STORAGE) |
||||
super(MediaAssetField, self).__init__(verbose_name, name, **kwargs) |
||||
|
||||
def formfield(self, **kwargs): |
||||
defaults = { |
||||
'form_class': MediaAssetFormField, |
||||
'max_length': self.max_length |
||||
} |
||||
defaults.update(kwargs) |
||||
return super(MediaAssetField, self).formfield(**defaults) |
@ -0,0 +1,8 @@
|
||||
# -*- coding: utf-8 -*- |
||||
from __future__ import unicode_literals |
||||
# Erik Stein <code@classlibrary.net>, 2016 |
||||
|
||||
|
||||
class FileField(Field): |
||||
widget = ClearableFileInput |
||||
|
@ -0,0 +1,27 @@
|
||||
# -*- coding: utf-8 -*- |
||||
# Generated by Django 1.9.4 on 2016-03-24 12:34 |
||||
from __future__ import unicode_literals |
||||
|
||||
from django.db import migrations, models |
||||
import main.medialibrary.models |
||||
import main.storages |
||||
|
||||
|
||||
class Migration(migrations.Migration): |
||||
|
||||
initial = True |
||||
|
||||
dependencies = [ |
||||
] |
||||
|
||||
operations = [ |
||||
migrations.CreateModel( |
||||
name='MediaAsset', |
||||
fields=[ |
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), |
||||
('uuid_hex', models.CharField(editable=False, max_length=32)), |
||||
('original_file', models.FileField(storage=main.storages.ProtectedMediaAssetStorage(), upload_to=main.medialibrary.fields.get_upload_path)), |
||||
('name', models.CharField(max_length=50, verbose_name='name')), |
||||
], |
||||
), |
||||
] |
@ -0,0 +1,20 @@
|
||||
# -*- coding: utf-8 -*- |
||||
# Generated by Django 1.9.4 on 2016-04-24 10:33 |
||||
from __future__ import unicode_literals |
||||
|
||||
from django.db import migrations, models |
||||
|
||||
|
||||
class Migration(migrations.Migration): |
||||
|
||||
dependencies = [ |
||||
('medialibrary', '0001_initial'), |
||||
] |
||||
|
||||
operations = [ |
||||
migrations.AddField( |
||||
model_name='mediaasset', |
||||
name='simple_file', |
||||
field=models.FileField(blank=True, null=True, upload_to=b''), |
||||
), |
||||
] |
@ -0,0 +1,21 @@
|
||||
# -*- coding: utf-8 -*- |
||||
# Generated by Django 1.9.4 on 2016-04-25 08:11 |
||||
from __future__ import unicode_literals |
||||
|
||||
from django.db import migrations |
||||
import main.medialibrary.fields |
||||
|
||||
|
||||
class Migration(migrations.Migration): |
||||
|
||||
dependencies = [ |
||||
('medialibrary', '0002_mediaasset_simple_file'), |
||||
] |
||||
|
||||
operations = [ |
||||
migrations.AlterField( |
||||
model_name='mediaasset', |
||||
name='original_file', |
||||
field=main.medialibrary.fields.MediaAssetField(upload_to=b'', verbose_name='original file'), |
||||
), |
||||
] |
@ -0,0 +1,25 @@
|
||||
# # -*- coding: utf-8 -*- |
||||
# from __future__ import unicode_literals |
||||
# # Erik Stein <code@classlibrary.net>, 2016 |
||||
|
||||
# import os |
||||
# from django.utils.text import slugify |
||||
|
||||
|
||||
# def get_upload_path(instance, filename): |
||||
# """ |
||||
# Returns /<uuid_hex>/original/<slugified_filename.ext> |
||||
# where |
||||
# - uuid is taken from instance, |
||||
# - filename is slugified and shortened to a max length including the extension. |
||||
# """ |
||||
# name, ext = os.path.splitext(filename) |
||||
# name = slugify(name) |
||||
# name = name[:(FILENAME_MAX_LENGTH - len(ext))] |
||||
# filename = "%s%s" % (name, ext) |
||||
# return os.path.join( |
||||
# instance.get_uuid(), |
||||
# instance.STORAGE.ORIGINAL_FILE_PREFIX, |
||||
# filename |
||||
# ) |
||||
|
Loading…
Reference in new issue