From 8496309ad73163f1b1f530c6e9e3922be1328054 Mon Sep 17 00:00:00 2001 From: Tris Date: Fri, 17 Sep 2021 14:58:07 +1000 Subject: [PATCH] Couple of changes --- byostorage/apps.py | 1 + byostorage/local_settings.py | 8 ++++- byostorage/models.py | 62 ++++++++++++++++++++++++++++++++++-- 3 files changed, 67 insertions(+), 4 deletions(-) diff --git a/byostorage/apps.py b/byostorage/apps.py index 8a67a34..26f34f0 100644 --- a/byostorage/apps.py +++ b/byostorage/apps.py @@ -4,3 +4,4 @@ from django.apps import AppConfig class BYOStorageConfig(AppConfig): name = 'byostorage' verbose_name = 'Bring your own storage' + default_auto_field = 'django.db.models.AutoField' diff --git a/byostorage/local_settings.py b/byostorage/local_settings.py index 46ff61a..e63903f 100644 --- a/byostorage/local_settings.py +++ b/byostorage/local_settings.py @@ -5,11 +5,17 @@ BASE_DIR = Path(__file__).resolve().parent.parent MEDIA_ROOT = "media" +DEBUG = True +DEFAULT_AUTO_FIELD = 'django.db.models.AutoField' + + INSTALLED_APPS = [ 'django.contrib.auth', 'django.contrib.contenttypes', - 'byostorage' + 'byostorage', + 'example' ] + SECRET_KEY = 'shh!' DATABASES = { diff --git a/byostorage/models.py b/byostorage/models.py index 651bd8c..7c91c84 100644 --- a/byostorage/models.py +++ b/byostorage/models.py @@ -1,9 +1,15 @@ from django.conf import settings from django.db import models -from django.core.files.storage import get_storage_class, FileSystemStorage +from django.db.models.fields.files import FieldFile +from django.core.exceptions import ObjectDoesNotExist +from django.core.files.storage import Storage, get_storage_class from django.core.exceptions import ValidationError import json +import logging +logger = logging.getLogger(__name__) +logger.setLevel(logging.DEBUG) + STORAGE_CLASSES = getattr(settings, 'STORAGE_CLASSES', []) STORAGE_CLASSES.extend([ @@ -11,7 +17,7 @@ STORAGE_CLASSES.extend([ ]) try: - import storages + import storages.backends STORAGE_CLASSES.append('storages.backends.s3boto3.S3Boto3Storage') except ImportError: pass @@ -24,6 +30,15 @@ def validate_json(value): except json.JSONDecodeError as e: raise ValidationError(e.msg) +def resolve_instance(obj, relation): + for p in relation.split('__'): + obj = getattr(obj, p) + + if callable(obj): + obj = obj() + + return obj + class UserStorage(models.Model): """ A user defined storage """ @@ -75,4 +90,45 @@ class UserStorage(models.Model): super(UserStorage, self).save(*args, **kwargs) def __str__(self): - return self.name \ No newline at end of file + return self.name + +class BYOFieldFile(FieldFile): + + def __init__(self, instance, field, name): + logger.debug("BYOFieldFile(%r, %r, %r)", instance, field, name) + super().__init__(instance, field, name) + try: + self.storage = field.get_storage(instance) + logger.debug("Using BYO storage: %r", self.storage) + except ObjectDoesNotExist: + logger.debug("Unable to select BYO storage") + self.storage = None # trigger error if try to save etc + +class BYOStorageField(models.FileField): + attr_class = BYOFieldFile + + def __init__(self, storage_instance, *args, **kwargs): + self.storage_instance = storage_instance + super().__init__(*args, **kwargs) + + def deconstruct(self): + name, path, args, kwargs = super().deconstruct() + args = [self.storage_instance] + args + return name, path, args, kwargs + + def get_storage(self, instance): + + if callable(self.storage_instance): + storage = self.storage_instance(instance) + else: + storage = resolve_instance(instance, self.storage_instance) + + if not isinstance(storage, Storage): + raise RuntimeError("Not a storage instance") + + return storage + + #def formfield(self, **kwargs): + # return BYOStorageFormField(**kwargs) + +