django-custom-storage 0.3.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- custom_storage/__init__.py +22 -0
- custom_storage/apps.py +11 -0
- custom_storage/settings.py +201 -0
- custom_storage/storage.py +104 -0
- django_custom_storage-0.3.2.data/data/share/django-custom-storage/requirements/py310-django32.txt +123 -0
- django_custom_storage-0.3.2.data/data/share/django-custom-storage/requirements/py310-django42.txt +216 -0
- django_custom_storage-0.3.2.data/data/share/django-custom-storage/requirements/py310-django52.txt +216 -0
- django_custom_storage-0.3.2.data/data/share/django-custom-storage/requirements/py311-django42.txt +212 -0
- django_custom_storage-0.3.2.data/data/share/django-custom-storage/requirements/py311-django52.txt +212 -0
- django_custom_storage-0.3.2.data/data/share/django-custom-storage/requirements/py312-django42.txt +212 -0
- django_custom_storage-0.3.2.data/data/share/django-custom-storage/requirements/py312-django52.txt +212 -0
- django_custom_storage-0.3.2.data/data/share/django-custom-storage/requirements/py313-django52.txt +212 -0
- django_custom_storage-0.3.2.data/data/share/django-custom-storage/requirements/py314-django52.txt +212 -0
- django_custom_storage-0.3.2.data/data/share/django-custom-storage/requirements/py39-django42.txt +168 -0
- django_custom_storage-0.3.2.dist-info/METADATA +188 -0
- django_custom_storage-0.3.2.dist-info/RECORD +19 -0
- django_custom_storage-0.3.2.dist-info/WHEEL +5 -0
- django_custom_storage-0.3.2.dist-info/licenses/LICENSE +21 -0
- django_custom_storage-0.3.2.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""
|
|
2
|
+
See PEP 386 (https://peps.python.org/pep-0386/)
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
__version__ = "0.3.2"
|
|
6
|
+
__version_info__ = tuple(
|
|
7
|
+
int(i) if i.isdigit() else i for i in __version__.split(".")
|
|
8
|
+
)
|
|
9
|
+
__license__ = "MIT"
|
|
10
|
+
__title__ = "custom_storage"
|
|
11
|
+
|
|
12
|
+
__author__ = "DLRSP"
|
|
13
|
+
__copyright__ = "Copyright 2010-present DLRSP"
|
|
14
|
+
|
|
15
|
+
# Version synonym
|
|
16
|
+
VERSION = __version_info__
|
|
17
|
+
|
|
18
|
+
# Header encoding (see RFC5987)
|
|
19
|
+
HTTP_HEADER_ENCODING = "iso-8859-1"
|
|
20
|
+
|
|
21
|
+
# Default datetime input and output formats
|
|
22
|
+
ISO_8601 = "iso-8601"
|
custom_storage/apps.py
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
from django.apps import AppConfig
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class CustomStorageConfig(AppConfig):
|
|
6
|
+
default_auto_field = "django.db.models.AutoField"
|
|
7
|
+
name = "custom_storage"
|
|
8
|
+
verbose_name = "Custom Storage"
|
|
9
|
+
|
|
10
|
+
def ready(self):
|
|
11
|
+
from . import settings # noqa: F401
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import datetime
|
|
2
|
+
import logging
|
|
3
|
+
import os
|
|
4
|
+
import sys
|
|
5
|
+
|
|
6
|
+
import django
|
|
7
|
+
from django.conf import settings
|
|
8
|
+
from django.core.exceptions import ImproperlyConfigured
|
|
9
|
+
|
|
10
|
+
logger = logging.getLogger(__name__)
|
|
11
|
+
|
|
12
|
+
# todo: https://overtag.dk/v2/blog/a-settings-pattern-for-reusable-django-apps/
|
|
13
|
+
# todo: https://docs.djangoproject.com/en/5.1/topics/settings/
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def setting(name, default=None):
|
|
17
|
+
"""
|
|
18
|
+
Helper function to get a Django setting by name. If setting doesn't exists
|
|
19
|
+
it will return a default.
|
|
20
|
+
|
|
21
|
+
:param name: Name of setting
|
|
22
|
+
:type name: str
|
|
23
|
+
:param default: Value if setting is unfound
|
|
24
|
+
:returns: Setting's value
|
|
25
|
+
"""
|
|
26
|
+
return getattr(settings, name, default)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
# overwrite settings for local DEBUG mode
|
|
30
|
+
if settings.DEBUG:
|
|
31
|
+
settings.configure(COMPRESS_ENABLED=False)
|
|
32
|
+
settings.configure(COMPRESS_OFFLINE=False)
|
|
33
|
+
settings.configure(STATIC_URL="/static/")
|
|
34
|
+
settings.configure(COMPRESS_ROOT=settings.STATIC_ROOT)
|
|
35
|
+
settings.configure(COMPRESS_URL=settings.STATIC_URL)
|
|
36
|
+
|
|
37
|
+
# todo: check how tow
|
|
38
|
+
# settings.configure(STORAGES=settings.STORAGES["default"]["BACKEND"]("django.contrib.staticfiles.storage.StaticFilesStorage"))
|
|
39
|
+
settings.STORAGES["default"][
|
|
40
|
+
"BACKEND"
|
|
41
|
+
] = "django.contrib.staticfiles.storage.StaticFilesStorage"
|
|
42
|
+
settings.STATICFILES_FINDERS = (
|
|
43
|
+
"django.contrib.staticfiles.finders.FileSystemFinder",
|
|
44
|
+
"django.contrib.staticfiles.finders.AppDirectoriesFinder",
|
|
45
|
+
)
|
|
46
|
+
if os.name == "nt":
|
|
47
|
+
MEDIA_ROOT = os.path.join(settings.WORK_DIR, "mediaroot")
|
|
48
|
+
STATIC_ROOT = os.path.join(settings.WORK_DIR, "staticroot")
|
|
49
|
+
|
|
50
|
+
# STORAGE Configurations
|
|
51
|
+
AWS_S3_STATIC_URL = getattr(settings, "AWS_S3_STATIC_URL", settings.STATIC_URL)
|
|
52
|
+
if not AWS_S3_STATIC_URL.endswith("/"):
|
|
53
|
+
raise ImproperlyConfigured(
|
|
54
|
+
"The STATIC_URL and AWS_S3_STATIC_URL settings must have a trailing slash."
|
|
55
|
+
)
|
|
56
|
+
AWS_S3_STATIC_ROOT = getattr(
|
|
57
|
+
settings, "AWS_S3_STATIC_ROOT", settings.STATIC_ROOT
|
|
58
|
+
)
|
|
59
|
+
AWS_S3_STATIC_LOCATION = getattr(settings, "AWS_S3_STATIC_LOCATION", "static")
|
|
60
|
+
|
|
61
|
+
AWS_S3_MEDIA_URL = getattr(settings, "AWS_S3_MEDIA_URL", settings.MEDIA_URL)
|
|
62
|
+
if not AWS_S3_MEDIA_URL.endswith("/"):
|
|
63
|
+
raise ImproperlyConfigured(
|
|
64
|
+
"The MEDIA_URL and AWS_S3_MEDIA_URL settings must have a trailing slash."
|
|
65
|
+
)
|
|
66
|
+
AWS_S3_MEDIA_ROOT = getattr(settings, "AWS_S3_MEDIA_ROOT", settings.MEDIA_ROOT)
|
|
67
|
+
AWS_S3_MEDIA_LOCATION = getattr(settings, "AWS_S3_MEDIA_LOCATION", "media")
|
|
68
|
+
|
|
69
|
+
AWS_S3_COMPRESS_ROOT = getattr(
|
|
70
|
+
settings, "AWS_S3_COMPRESS_ROOT", AWS_S3_STATIC_ROOT
|
|
71
|
+
)
|
|
72
|
+
settings.COMPRESS_ROOT = AWS_S3_COMPRESS_ROOT
|
|
73
|
+
|
|
74
|
+
# Add option to FORCE_LOCAL_STORAGE
|
|
75
|
+
# https://www.mslinn.com/django/1300-django-aws-control.html
|
|
76
|
+
if "--force-local-storage" in sys.argv:
|
|
77
|
+
# print("AWS datastore disabled; using local storage for assets instead.")
|
|
78
|
+
settings.FORCE_LOCAL_STORAGE = True
|
|
79
|
+
sys.argv.remove("--force-local-storage")
|
|
80
|
+
else:
|
|
81
|
+
# print("Using AWS datastore for assets.")
|
|
82
|
+
settings.FORCE_LOCAL_STORAGE = False
|
|
83
|
+
|
|
84
|
+
# settings.STORAGES = {
|
|
85
|
+
# "default": {
|
|
86
|
+
# "BACKEND": "custom_storage.storage.MediaRootCachedS3Storage",
|
|
87
|
+
# "OPTIONS": {},
|
|
88
|
+
# },
|
|
89
|
+
# "staticfiles": {
|
|
90
|
+
# "BACKEND": "custom_storage.storage.StaticRootCachedS3Storage",
|
|
91
|
+
# "OPTIONS": {},
|
|
92
|
+
# },
|
|
93
|
+
# "compressor": {
|
|
94
|
+
# "BACKEND": "compressor.storage.CompressorFileStorage",
|
|
95
|
+
# "OPTIONS": {},
|
|
96
|
+
# },
|
|
97
|
+
# "local": {
|
|
98
|
+
# "BACKEND": "django.core.files.storage.FileSystemStorage",
|
|
99
|
+
# "OPTIONS": {},
|
|
100
|
+
# },
|
|
101
|
+
# }
|
|
102
|
+
|
|
103
|
+
# DEFAULT_FILE_STORAGE was deprecated in Django 4.2 and removed in 5.1; reading
|
|
104
|
+
# or assigning it raises under -W error::DeprecationWarning. Derive the default
|
|
105
|
+
# backend from the modern STORAGES setting instead (honoring a legacy override
|
|
106
|
+
# only on Django < 4.2, where the alias is still the source of truth).
|
|
107
|
+
if django.VERSION < (4, 2):
|
|
108
|
+
_default_backend = setting(
|
|
109
|
+
"DEFAULT_FILE_STORAGE", settings.STORAGES["default"]["BACKEND"]
|
|
110
|
+
)
|
|
111
|
+
else:
|
|
112
|
+
_default_backend = settings.STORAGES["default"]["BACKEND"]
|
|
113
|
+
settings.THUMBNAIL_DEFAULT_STORAGE = setting(
|
|
114
|
+
"THUMBNAIL_DEFAULT_STORAGE", _default_backend
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
if settings.FORCE_LOCAL_STORAGE:
|
|
118
|
+
settings.STORAGES["default"][
|
|
119
|
+
"BACKEND"
|
|
120
|
+
] = "django.core.files.storage.FileSystemStorage"
|
|
121
|
+
else:
|
|
122
|
+
if os.getenv("RUN_COMPRESS", True):
|
|
123
|
+
settings.STORAGES["staticfiles"][
|
|
124
|
+
"BACKEND"
|
|
125
|
+
] = "custom_storage.storage.StaticRootCachedS3Storage"
|
|
126
|
+
|
|
127
|
+
settings.COMPRESS_OUTPUT_DIR = setting(
|
|
128
|
+
"COMPRESS_OUTPUT_DIR", "compressed_static"
|
|
129
|
+
)
|
|
130
|
+
settings.COMPRESS_STORAGE = setting(
|
|
131
|
+
"COMPRESS_STORAGE", settings.STORAGES["staticfiles"]["BACKEND"]
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
# AWS S3 Configurations
|
|
135
|
+
settings.AWS_S3_FILE_OVERWRITE = setting("AWS_S3_FILE_OVERWRITE", False)
|
|
136
|
+
settings.AWS_DEFAULT_ACL = setting("AWS_DEFAULT_ACL", "public-read")
|
|
137
|
+
settings.AWS_QUERYSTRING_AUTH = setting("AWS_QUERYSTRING_AUTH", False)
|
|
138
|
+
settings.AWS_FILE_EXPIRE = setting("AWS_FILE_EXPIRE", 61)
|
|
139
|
+
settings.AWS_PRELOAD_METADATA = setting("AWS_PRELOAD_METADATA", True)
|
|
140
|
+
|
|
141
|
+
two_months = datetime.timedelta(days=settings.AWS_FILE_EXPIRE)
|
|
142
|
+
date_two_months_later = datetime.date.today() + two_months
|
|
143
|
+
expires = date_two_months_later.strftime("%A, %d %B %Y 20:00:00 GMT")
|
|
144
|
+
settings.AWS_S3_OBJECT_PARAMETERS = setting(
|
|
145
|
+
"AWS_S3_OBJECT_PARAMETERS",
|
|
146
|
+
{
|
|
147
|
+
"Expires": expires,
|
|
148
|
+
"CacheControl": "max-age=%d" % (int(two_months.total_seconds()),),
|
|
149
|
+
},
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
# Compress Configurations
|
|
153
|
+
settings.COMPRESS_ENABLED = setting("COMPRESS_ENABLED", True)
|
|
154
|
+
settings.COMPRESS_OFFLINE = setting("COMPRESS_OFFLINE", True)
|
|
155
|
+
settings.STATICFILES_FINDERS = setting(
|
|
156
|
+
"STATICFILES_FINDERS",
|
|
157
|
+
(
|
|
158
|
+
"django.contrib.staticfiles.finders.FileSystemFinder",
|
|
159
|
+
"django.contrib.staticfiles.finders.AppDirectoriesFinder",
|
|
160
|
+
"compressor.finders.CompressorFinder",
|
|
161
|
+
),
|
|
162
|
+
)
|
|
163
|
+
settings.COMPRESS_CSS_HASHING_METHOD = setting(
|
|
164
|
+
"COMPRESS_CSS_HASHING_METHOD", None
|
|
165
|
+
)
|
|
166
|
+
settings.COMPRESS_CSS_FILTERS = setting(
|
|
167
|
+
"COMPRESS_CSS_FILTERS",
|
|
168
|
+
[
|
|
169
|
+
"compressor.filters.css_default.CssAbsoluteFilter",
|
|
170
|
+
# 'compressor.filters.css_default.CssRelativeFilter',
|
|
171
|
+
"compressor.filters.cssmin.CSSMinFilter",
|
|
172
|
+
],
|
|
173
|
+
)
|
|
174
|
+
settings.COMPRESS_JS_FILTERS = setting(
|
|
175
|
+
"COMPRESS_JS_FILTERS",
|
|
176
|
+
[
|
|
177
|
+
"compressor.filters.jsmin.JSMinFilter",
|
|
178
|
+
],
|
|
179
|
+
)
|
|
180
|
+
settings.KEEP_COMMENTS_ON_MINIFYING = setting(
|
|
181
|
+
"KEEP_COMMENTS_ON_MINIFYING", False
|
|
182
|
+
)
|
|
183
|
+
settings.HTML_MINIFY = setting("HTML_MINIFY", True)
|
|
184
|
+
|
|
185
|
+
# # overwrite settings for local DEBUG mode
|
|
186
|
+
# if settings.DEBUG:
|
|
187
|
+
# settings.COMPRESS_ENABLED = False
|
|
188
|
+
# settings.COMPRESS_OFFLINE = False
|
|
189
|
+
# settings.STATIC_URL = "/static/"
|
|
190
|
+
# settings.COMPRESS_ROOT = settings.STATIC_ROOT
|
|
191
|
+
# settings.COMPRESS_URL = settings.STATIC_URL
|
|
192
|
+
# settings.STORAGES["default"][
|
|
193
|
+
# "BACKEND"
|
|
194
|
+
# ] = "django.contrib.staticfiles.storage.StaticFilesStorage"
|
|
195
|
+
# settings.STATICFILES_FINDERS = (
|
|
196
|
+
# "django.contrib.staticfiles.finders.FileSystemFinder",
|
|
197
|
+
# "django.contrib.staticfiles.finders.AppDirectoriesFinder",
|
|
198
|
+
# )
|
|
199
|
+
# if os.name == "nt":
|
|
200
|
+
# MEDIA_ROOT = os.path.join(settings.WORK_DIR, "mediaroot")
|
|
201
|
+
# STATIC_ROOT = os.path.join(settings.WORK_DIR, "staticroot")
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
from django.conf import settings
|
|
2
|
+
from django.utils.module_loading import import_string
|
|
3
|
+
from storages.backends.s3 import S3Storage
|
|
4
|
+
|
|
5
|
+
from .settings import (
|
|
6
|
+
AWS_S3_MEDIA_LOCATION,
|
|
7
|
+
AWS_S3_MEDIA_URL,
|
|
8
|
+
AWS_S3_STATIC_LOCATION,
|
|
9
|
+
AWS_S3_STATIC_URL,
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
# Django deprecated django.core.files.storage.get_storage_class in 4.2 and
|
|
13
|
+
# removed it in 5.1. Always resolve via import_string so we never trigger
|
|
14
|
+
# RemovedInDjango51Warning (which is fatal under -W error::DeprecationWarning)
|
|
15
|
+
# nor break on Django 5.1+. Kept as a module-level name for backward compat.
|
|
16
|
+
def get_storage_class(import_path):
|
|
17
|
+
return import_string(import_path)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class StaticRootCachedS3Storage(S3Storage):
|
|
21
|
+
"""
|
|
22
|
+
S3 storage backend that saves the files locally, too.
|
|
23
|
+
|
|
24
|
+
The defaults for ``location`` and ``base_url`` are ``AWS_S3_STATIC_LOCATION`` and
|
|
25
|
+
``AWS_S3_STATIC_URL``.
|
|
26
|
+
|
|
27
|
+
The defaults for ``local_storage`` is ``STORAGE['compressor']['BACKENDS']``
|
|
28
|
+
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
def __init__(
|
|
32
|
+
self, location=None, base_url=None, local_storage=None, *args, **kwargs
|
|
33
|
+
):
|
|
34
|
+
super().__init__(*args, **kwargs)
|
|
35
|
+
if location is None:
|
|
36
|
+
self.location = AWS_S3_STATIC_LOCATION
|
|
37
|
+
if base_url is None:
|
|
38
|
+
self.base_url = AWS_S3_STATIC_URL
|
|
39
|
+
if local_storage is None:
|
|
40
|
+
self.local_storage = get_storage_class(
|
|
41
|
+
settings.STORAGES["compressor"]["BACKEND"]
|
|
42
|
+
)()
|
|
43
|
+
# self.location = "static"
|
|
44
|
+
# self.local_storage = get_storage_class("compressor.storage.CompressorFileStorage")()
|
|
45
|
+
|
|
46
|
+
def save(self, name, content, max_length=None):
|
|
47
|
+
self.local_storage._save(name, content)
|
|
48
|
+
super().save(name, self.local_storage._open(name))
|
|
49
|
+
return name
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class MediaRootCachedS3Storage(S3Storage):
|
|
53
|
+
"""
|
|
54
|
+
S3 storage backend that saves the files locally, too.
|
|
55
|
+
|
|
56
|
+
The defaults for ``location`` and ``base_url`` are ``AWS_S3_MEDIA_LOCATION`` and
|
|
57
|
+
``AWS_S3_MEDIA_URL``.
|
|
58
|
+
|
|
59
|
+
The defaults for ``local_storage`` is ``STORAGE['local']['BACKENDS']``
|
|
60
|
+
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
def __init__(
|
|
64
|
+
self, location=None, base_url=None, local_storage=None, *args, **kwargs
|
|
65
|
+
):
|
|
66
|
+
super().__init__(*args, **kwargs)
|
|
67
|
+
if location is None:
|
|
68
|
+
self.location = AWS_S3_MEDIA_LOCATION
|
|
69
|
+
if base_url is None:
|
|
70
|
+
self.base_url = AWS_S3_MEDIA_URL
|
|
71
|
+
if local_storage is None:
|
|
72
|
+
self.local_storage = get_storage_class(
|
|
73
|
+
settings.STORAGES["local"]["BACKEND"]
|
|
74
|
+
)()
|
|
75
|
+
# self.location = "media"
|
|
76
|
+
# self.local_storage = get_storage_class("django.core.files.storage.FileSystemStorage")()
|
|
77
|
+
|
|
78
|
+
def save(self, name, content, max_length=None):
|
|
79
|
+
self.local_storage._save(name, content)
|
|
80
|
+
super().save(name, self.local_storage._open(name))
|
|
81
|
+
return name
|
|
82
|
+
|
|
83
|
+
def delete(self, name):
|
|
84
|
+
self.local_storage.delete(name)
|
|
85
|
+
super().delete(name)
|
|
86
|
+
|
|
87
|
+
# Delete optimized image if exist
|
|
88
|
+
for extension in ("webp", "avif"):
|
|
89
|
+
print(f"{name}.{extension}")
|
|
90
|
+
self.local_storage.delete(f"{name}.{extension}")
|
|
91
|
+
super().delete(f"{name}.{extension}")
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
class PublicMediaS3Boto3Storage(S3Storage):
|
|
95
|
+
location = "media"
|
|
96
|
+
default_acl = "public-read"
|
|
97
|
+
file_overwrite = False
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
class PrivateMediaS3Boto3Storage(S3Storage):
|
|
101
|
+
location = "private"
|
|
102
|
+
default_acl = "private"
|
|
103
|
+
file_overwrite = False
|
|
104
|
+
custom_domain = False
|
django_custom_storage-0.3.2.data/data/share/django-custom-storage/requirements/py310-django32.txt
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
#
|
|
2
|
+
# This file is autogenerated by pip-compile with Python 3.10
|
|
3
|
+
# by the following command:
|
|
4
|
+
#
|
|
5
|
+
# pip-compile --allow-unsafe --generate-hashes --output-file=requirements/py310-django32.txt requirements/runtime.in
|
|
6
|
+
#
|
|
7
|
+
asgiref==3.11.1 \
|
|
8
|
+
--hash=sha256:5f184dc43b7e763efe848065441eac62229c9f7b0475f41f80e207a114eda4ce \
|
|
9
|
+
--hash=sha256:e8667a091e69529631969fd45dc268fa79b99c92c5fcdda727757e52146ec133
|
|
10
|
+
# via django
|
|
11
|
+
boto3==1.43.36 \
|
|
12
|
+
--hash=sha256:42942dde254673abcbc9e6e60017c88341a4f49d99d24e1f2e290fb38138c26f \
|
|
13
|
+
--hash=sha256:587d7ee92a12e440ad12b0e7f11f3358f0c4d65b19f64726efc94aaf194aff28
|
|
14
|
+
# via django-storages
|
|
15
|
+
botocore==1.43.36 \
|
|
16
|
+
--hash=sha256:3c65fdc39ed01d8dfde1e961b34038aed03c459f8ddf80717a12ac006475e49d \
|
|
17
|
+
--hash=sha256:4cae47d1b2d426316b85a0087d9e69e048f13bc003b5177d74639fe9dfd28205
|
|
18
|
+
# via
|
|
19
|
+
# boto3
|
|
20
|
+
# s3transfer
|
|
21
|
+
django==3.2.25 \
|
|
22
|
+
--hash=sha256:7ca38a78654aee72378594d63e51636c04b8e28574f5505dff630895b5472777 \
|
|
23
|
+
--hash=sha256:a52ea7fcf280b16f7b739cec38fa6d3f8953a5456986944c3ca97e79882b4e38
|
|
24
|
+
# via
|
|
25
|
+
# -r requirements/runtime.in
|
|
26
|
+
# django-appconf
|
|
27
|
+
# django-storages
|
|
28
|
+
django-appconf==1.2.0 \
|
|
29
|
+
--hash=sha256:15a88d60dd942d6059f467412fe4581db632ef03018a3c183fb415d6fc9e5cec \
|
|
30
|
+
--hash=sha256:b81bce5ef0ceb9d84df48dfb623a32235d941c78cc5e45dbb6947f154ea277f4
|
|
31
|
+
# via django-compressor
|
|
32
|
+
django-compressor==4.4 \
|
|
33
|
+
--hash=sha256:1b0acc9cfba9f69bc38e7c41da9b0d70a20bc95587b643ffef9609cf46064f67 \
|
|
34
|
+
--hash=sha256:6e2b0c0becb9607f5099c2546a824c5b84a6918a34bc37a8a622ffa250313596
|
|
35
|
+
# via -r requirements/runtime.in
|
|
36
|
+
django-storages[s3]==1.14.6 \
|
|
37
|
+
--hash=sha256:11b7b6200e1cb5ffcd9962bd3673a39c7d6a6109e8096f0e03d46fab3d3aabd9 \
|
|
38
|
+
--hash=sha256:7a25ce8f4214f69ac9c7ce87e2603887f7ae99326c316bc8d2d75375e09341c9
|
|
39
|
+
# via -r requirements/runtime.in
|
|
40
|
+
jmespath==1.1.0 \
|
|
41
|
+
--hash=sha256:472c87d80f36026ae83c6ddd0f1d05d4e510134ed462851fd5f754c8c3cbb88d \
|
|
42
|
+
--hash=sha256:a5663118de4908c91729bea0acadca56526eb2698e83de10cd116ae0f4e97c64
|
|
43
|
+
# via
|
|
44
|
+
# boto3
|
|
45
|
+
# botocore
|
|
46
|
+
python-dateutil==2.9.0.post0 \
|
|
47
|
+
--hash=sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3 \
|
|
48
|
+
--hash=sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427
|
|
49
|
+
# via botocore
|
|
50
|
+
pytz==2026.2 \
|
|
51
|
+
--hash=sha256:04156e608bee23d3792fd45c94ae47fae1036688e75032eea2e3bf0323d1f126 \
|
|
52
|
+
--hash=sha256:0e60b47b29f21574376f218fe21abc009894a2321ea16c6754f3cad6eb7cdd6a
|
|
53
|
+
# via django
|
|
54
|
+
rcssmin==1.1.1 \
|
|
55
|
+
--hash=sha256:271e3d2f8614a6d4637ed8fff3d90007f03e2a654cd9444f37d888797662ba72 \
|
|
56
|
+
--hash=sha256:35da6a6999e9e2c5b0e691b42ed56cc479373e0ecab33ef5277dfecce625e44a \
|
|
57
|
+
--hash=sha256:42576d95dfad53d77df2e68dfdec95b89b10fad320f241f1af3ca1438578254a \
|
|
58
|
+
--hash=sha256:4f9400b4366d29f5f5446f58e78549afa8338e6a59740c73115e9f6ac413dc64 \
|
|
59
|
+
--hash=sha256:705c9112d0ed54ea40aecf97e7fd29bdf0f1c46d278a32d8f957f31dde90778a \
|
|
60
|
+
--hash=sha256:79421230dd67c37ec61ed9892813d2b839b68f2f48ef55c75f976e81701d60b4 \
|
|
61
|
+
--hash=sha256:868215e1fd0e92a6122e0ed5973dfc7bb8330fe1e92274d05b2585253b38c0ca \
|
|
62
|
+
--hash=sha256:8a26fec3c1e6b7a3765ccbaccc20fbb5c0ed3422cc381e01a2607f08d7621c44 \
|
|
63
|
+
--hash=sha256:8fcfd10ae2a1c4ce231a33013f2539e07c3836bf17cc945cc25cc30bf8e68e45 \
|
|
64
|
+
--hash=sha256:908fe072efd2432fb0975a61124609a8e05021367f6a3463d45f5e3e74c4fdda \
|
|
65
|
+
--hash=sha256:914e589f40573035006913861ed2adc28fbe70082a8b6bff5be7ee430b7b5c2e \
|
|
66
|
+
--hash=sha256:a04d58a2a21e9a089306d3f99c4b12bf5b656a79c198ef2321e80f8fd9afab06 \
|
|
67
|
+
--hash=sha256:a417735d4023d47d048a6288c88dbceadd20abaaf65a11bb4fda1e8458057019 \
|
|
68
|
+
--hash=sha256:c30f8bc839747b6da59274e0c6e4361915d66532e26448d589cb2b1846d7bf11 \
|
|
69
|
+
--hash=sha256:c7278c1c25bb90d8e554df92cfb3b6a1195004ead50f764653d3093933ee0877 \
|
|
70
|
+
--hash=sha256:c7728e3b546b1b6ea08cab721e8e21409dbcc11b881d0b87d10b0be8930af2a2 \
|
|
71
|
+
--hash=sha256:cf74d7ea5e191f0f344b354eed8b7c83eeafbd9a97bec3a579c3d26edf11b005 \
|
|
72
|
+
--hash=sha256:d0afc6e7b64ef30d6dcde88830ec1a237b9f16a39f920a8fd159928684ccf8db \
|
|
73
|
+
--hash=sha256:d4e263fa9428704fd94c2cb565c7519ca1d225217943f71caffe6741ab5b9df1 \
|
|
74
|
+
--hash=sha256:e923c105100ab70abde1c01d3196ddd6b07255e32073685542be4e3a60870c8e \
|
|
75
|
+
--hash=sha256:ee386bec6d62f8c814d65c011d604a7c82d24aa3f718facd66e850eea8d6a5a1 \
|
|
76
|
+
--hash=sha256:f15673e97f0a68b4c378c4d15b088fe96d60bc106d278c88829923118833c20f \
|
|
77
|
+
--hash=sha256:f7a1fcdbafaacac0530da04edca4a44303baab430ea42e7d59aece4b3f3e9a51
|
|
78
|
+
# via django-compressor
|
|
79
|
+
rjsmin==1.2.1 \
|
|
80
|
+
--hash=sha256:113132a40ce7d03b2ced4fac215f0297338ed1c207394b739266efab7831988b \
|
|
81
|
+
--hash=sha256:122aa52bcf7ad9f12728d309012d1308c6ecfe4d6b09ea867a110dcad7b7728c \
|
|
82
|
+
--hash=sha256:145c6af8df42d8af102d0d39a6de2e5fa66aef9e38947cfb9d65377d1b9940b2 \
|
|
83
|
+
--hash=sha256:1f982be8e011438777a94307279b40134a3935fc0f079312ee299725b8af5411 \
|
|
84
|
+
--hash=sha256:3453ee6d5e7a2723ec45c2909e2382371783400e8d51952b692884c6d850a3d0 \
|
|
85
|
+
--hash=sha256:35827844d2085bd59d34214dfba6f1fc42a215c455887437b07dbf9c73019cc1 \
|
|
86
|
+
--hash=sha256:35f21046504544e2941e04190ce24161255479133751550e36ddb3f4af0ecdca \
|
|
87
|
+
--hash=sha256:5d67ec09da46a492186e35cabca02a0d092eda5ef5b408a419b99ee4acf28d5c \
|
|
88
|
+
--hash=sha256:747bc9d3bc8a220f40858e6aad50b2ae2eb7f69c924d4fa3803b81be1c1ddd02 \
|
|
89
|
+
--hash=sha256:7dd58b5ed88233bc61dc80b0ed87b93a1786031d9977c70d335221ef1ac5581a \
|
|
90
|
+
--hash=sha256:812af25c08d6a5ae98019a2e1b47ebb47f7469abd351670c353d619eaeae4064 \
|
|
91
|
+
--hash=sha256:8a6710e358c661dcdcfd027e67de3afd72a6af4c88101dcf110de39e9bbded39 \
|
|
92
|
+
--hash=sha256:8c340e251619c97571a5ade20f147f1f7e8664f66a2d6d7319e05e3ef6a4423c \
|
|
93
|
+
--hash=sha256:99c074cd6a8302ff47118a9c3d086f89328dc8e5c4b105aa1f348fb85c765a30 \
|
|
94
|
+
--hash=sha256:b8464629a18fe69f70677854c93a3707976024b226a0ce62707c618f923e1346 \
|
|
95
|
+
--hash=sha256:bbd7a0abaa394afd951f5d4e05249d306fec1c9674bfee179787674dddd0bdb7 \
|
|
96
|
+
--hash=sha256:bc5bc2f94e59bc81562c572b7f1bdd6bcec4f61168dc68a2993bad2d355b6e19 \
|
|
97
|
+
--hash=sha256:bd1faedc425006d9e86b23837d164f01d105b7a8b66b767a9766d0014773db2a \
|
|
98
|
+
--hash=sha256:ca90630b84fe94bb07739c3e3793e87d30c6ee450dde08653121f0d9153c8d0d \
|
|
99
|
+
--hash=sha256:d332e44a1b21ad63401cc7eebc81157e3d982d5fb503bb4faaea5028068d71e9 \
|
|
100
|
+
--hash=sha256:eb770aaf637919b0011c4eb87b9ac6317079fb9800eb17c90dda05fc9de4ebc3 \
|
|
101
|
+
--hash=sha256:f0895b360dccf7e2d6af8762a52985e3fbaa56778de1bf6b20dbc96134253807 \
|
|
102
|
+
--hash=sha256:f7cd33602ec0f393a0058e883284496bb4dbbdd34e0bbe23b594c8933ddf9b65
|
|
103
|
+
# via django-compressor
|
|
104
|
+
s3transfer==0.19.0 \
|
|
105
|
+
--hash=sha256:777cc2415536f1debadb5c2ef7779275d0fc0fe0e042411cdd6caebeb2685262 \
|
|
106
|
+
--hash=sha256:ce436931687addc4c1712d52d40b32f53e88315723f107ffa20ba82b05a0f685
|
|
107
|
+
# via boto3
|
|
108
|
+
six==1.17.0 \
|
|
109
|
+
--hash=sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274 \
|
|
110
|
+
--hash=sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81
|
|
111
|
+
# via python-dateutil
|
|
112
|
+
sqlparse==0.5.5 \
|
|
113
|
+
--hash=sha256:12a08b3bf3eec877c519589833aed092e2444e68240a3577e8e26148acc7b1ba \
|
|
114
|
+
--hash=sha256:e20d4a9b0b8585fdf63b10d30066c7c94c5d7a7ec47c889a2d83a3caa93ff28e
|
|
115
|
+
# via django
|
|
116
|
+
typing-extensions==4.15.0 \
|
|
117
|
+
--hash=sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466 \
|
|
118
|
+
--hash=sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548
|
|
119
|
+
# via asgiref
|
|
120
|
+
urllib3==2.7.0 \
|
|
121
|
+
--hash=sha256:231e0ec3b63ceb14667c67be60f2f2c40a518cb38b03af60abc813da26505f4c \
|
|
122
|
+
--hash=sha256:9fb4c81ebbb1ce9531cce37674bbc6f1360472bc18ca9a553ede278ef7276897
|
|
123
|
+
# via botocore
|