Initial commit
This commit is contained in:
commit
3f6046fed6
2
CHANGELOG.rst
Normal file
2
CHANGELOG.rst
Normal file
@ -0,0 +1,2 @@
|
||||
django-byostorage CHANGELOG
|
||||
===========================
|
||||
22
README.rst
Normal file
22
README.rst
Normal file
@ -0,0 +1,22 @@
|
||||
Installation
|
||||
============
|
||||
|
||||
Usage
|
||||
=====
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def generate_filename(instance, filename):
|
||||
return f"{instance.parent.storage}:some_folder/{filename}"
|
||||
|
||||
class SomeParentModel(models.Model):
|
||||
storage = models.ForeignKey('byostorage.UserStorage',
|
||||
on_delete=models.CASCADE)
|
||||
|
||||
class MyModel(models.Model):
|
||||
parent = models.ForeignKey('SomeParentModel',
|
||||
on_delete=models.CASCADE)
|
||||
|
||||
photo = models.FileField(
|
||||
storage=BYOStorage(),
|
||||
upload_to=generate_filename)
|
||||
1
byostorage/__init__.py
Normal file
1
byostorage/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
__VERSION__ = 0.1
|
||||
7
byostorage/admin.py
Normal file
7
byostorage/admin.py
Normal file
@ -0,0 +1,7 @@
|
||||
from django.contrib import admin
|
||||
from . import models
|
||||
|
||||
class UserStorageAdmin(admin.ModelAdmin):
|
||||
list_display = ['name', 'storage', 'owner']
|
||||
|
||||
admin.site.register(models.UserStorage, UserStorageAdmin)
|
||||
6
byostorage/apps.py
Normal file
6
byostorage/apps.py
Normal file
@ -0,0 +1,6 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class ByostorageConfig(AppConfig):
|
||||
name = 'byostorage'
|
||||
verbose_name = 'Bring your own storage'
|
||||
27
byostorage/migrations/0001_initial.py
Normal file
27
byostorage/migrations/0001_initial.py
Normal file
@ -0,0 +1,27 @@
|
||||
# Generated by Django 3.1.1 on 2021-03-11 23:11
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='UserStorage',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.SlugField(help_text='Storage tag', max_length=20)),
|
||||
('storage', models.CharField(help_text='Storage class for this instance', max_length=255)),
|
||||
('settings_data', models.TextField(help_text='JSON dict with key/value settings')),
|
||||
('owner', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
]
|
||||
0
byostorage/migrations/__init__.py
Normal file
0
byostorage/migrations/__init__.py
Normal file
18
byostorage/models.py
Normal file
18
byostorage/models.py
Normal file
@ -0,0 +1,18 @@
|
||||
from django.db import models
|
||||
from django.core.files.storage import get_storage_class
|
||||
import json
|
||||
|
||||
class UserStorage(models.Model):
|
||||
""" A user defined storage
|
||||
"""
|
||||
owner = models.ForeignKey('auth.User', on_delete=models.CASCADE, null=True, blank=True)
|
||||
name = models.SlugField(max_length=20, help_text="Storage tag")
|
||||
storage = models.CharField(max_length=255, help_text="Storage class for this instance")
|
||||
settings_data = models.TextField(help_text="JSON dict with key/value settings")
|
||||
|
||||
def instance(self):
|
||||
return get_storage_class(self.storage)(**self.settings)
|
||||
|
||||
@property
|
||||
def settings(self):
|
||||
return json.loads(self.settings_data)
|
||||
52
byostorage/storage.py
Normal file
52
byostorage/storage.py
Normal file
@ -0,0 +1,52 @@
|
||||
from django.core.files.storage import Storage
|
||||
|
||||
class MultiStorage(Storage):
|
||||
''' Django storage class that proxies multiple storage classes.
|
||||
|
||||
Uses a name prefix to determine store e.g. 'images:foo/bar.jpg'
|
||||
'''
|
||||
|
||||
def __init__(self, config=None):
|
||||
self.config = config or getattr(settings, 'BRING_YOUR_OWN_STORAGE', {})
|
||||
self._cache = {}
|
||||
|
||||
def get_storage(self, name):
|
||||
if name not in self._cache:
|
||||
config = self.config[name]
|
||||
self._cache[name] = get_storage_class(config['storage'])(**config['settings'])
|
||||
return self._cache[name]
|
||||
|
||||
def split(self, name):
|
||||
return name.split(":", 1)
|
||||
|
||||
def _open(self, name, mode='rb'):
|
||||
storage, p = self.split(name)
|
||||
return self.get_storage(storage)._open(p, mode)
|
||||
|
||||
def _proxy(self, method, name, *args, **kwargs):
|
||||
storage, p = self.split(name)
|
||||
sname = getattr(self.get_storage(storage), method)(name, *args, **kwargs)
|
||||
if sname is not None:
|
||||
return f"{storage}:{sname}"
|
||||
|
||||
|
||||
def _save(self, name, content, max_length=None):
|
||||
return self._proxy('save', name, content, max_length)
|
||||
|
||||
class BYOStorage(MultiStorage):
|
||||
''' Database driven Bring-Your-Own-Storage
|
||||
|
||||
Multiple storages can
|
||||
'''
|
||||
|
||||
def get_storage(self, name):
|
||||
if name not in self._cache:
|
||||
|
||||
# use storage from config by default
|
||||
if name in self.config:
|
||||
return super(BYOStorage, self).get_storage(name)
|
||||
|
||||
from .models import UserStorage
|
||||
obj = UserStorage.objects.get(name=name)
|
||||
self._cache[name] = obj.instance()
|
||||
return self._cache[name]
|
||||
35
setup.cfg
Normal file
35
setup.cfg
Normal file
@ -0,0 +1,35 @@
|
||||
[metadata]
|
||||
name = django-byostorage
|
||||
version = attr: byostorage.__version__
|
||||
description = Support for Bring-Your-Own-Storage
|
||||
long_description = file: README.rst, CHANGELOG.rst
|
||||
license = BSD-3-Clause
|
||||
author = Tris Forster
|
||||
author_email = tris.forster@gmail.com
|
||||
url = https://github.com/tf198/django-byostorage
|
||||
classifiers =
|
||||
Development Status :: 1 - Development
|
||||
Environment :: Web Environment
|
||||
Framework :: Django
|
||||
Framework :: Django :: 2.2
|
||||
Framework :: Django :: 3.0
|
||||
Framework :: Django :: 3.1
|
||||
Intended Audience :: Developers
|
||||
License :: OSI Approved :: BSD License
|
||||
Operating System :: OS Independent
|
||||
Programming Language :: Python
|
||||
Programming Language :: Python :: 3
|
||||
Programming Language :: Python :: 3 :: Only
|
||||
Programming Language :: Python :: 3.5
|
||||
Programming Language :: Python :: 3.6
|
||||
Programming Language :: Python :: 3.7
|
||||
Programming Language :: Python :: 3.8
|
||||
Programming Language :: Python :: 3.9
|
||||
|
||||
[options]
|
||||
python_requires = >=3.5
|
||||
install_requires =
|
||||
Django >= 2.2
|
||||
packages =
|
||||
byostorage
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user