From c2f956bf1f7d64e2b6408b2baf13eece08c0925f Mon Sep 17 00:00:00 2001
From: Kristof Daja <22156894+theriverman@users.noreply.github.com>
Date: Thu, 2 Jan 2025 19:05:37 +0100
Subject: [PATCH] README.md restructured
* Python and Django requirements clarified and updated
* Section "What's in the box?" added
* Fenced code blocks indented to fix numbered lists
* Typo/grammar/other small corrections
---
README.md | 211 +++++++++++++++++++++++++++++-------------------------
setup.py | 1 -
2 files changed, 115 insertions(+), 97 deletions(-)
diff --git a/README.md b/README.md
index b082267..2d70fcd 100644
--- a/README.md
+++ b/README.md
@@ -7,108 +7,129 @@ The **django-minio-backend** provides a wrapper around the
[MinIO Python SDK](https://docs.min.io/docs/python-client-quickstart-guide.html).
See [minio/minio-py](https://github.com/minio/minio-py) for the source.
+## Requirements & Compatibility
+ * Django 4.2 or later
+ * Python 3.11.0 or later
+ * MinIO SDK 7.2.8 or later (installed automatically)
+
+## What's in the box?
+The following set of features are available in **django-minio-backend**:
+* Django File Storage System Integration
+ * Compliance with the `django.core.files.storage.Storage` class
+ * Static Files Support
+* Utilise/manage private and public buckets
+ * Create buckets with custom policy hooks (`MINIO_POLICY_HOOKS`)
+ * Consistency Check on Start (`MINIO_CONSISTENCY_CHECK_ON_START`)
+ * Bucket Check on Upload (`MINIO_BUCKET_CHECK_ON_SAVE`)
+* Health Check (`MinioBackend.is_minio_available()`)
+* Docker Networking Support
+* Management Commands:
+ * initialize_buckets
+ * is_minio_available
+
## Integration
1. Get and install the package:
-```bash
-pip install django-minio-backend
-```
+ ```bash
+ pip install django-minio-backend
+ ```
2. Add `django_minio_backend` to `INSTALLED_APPS`:
-```python
-INSTALLED_APPS = [
- # '...'
- 'django_minio_backend', # https://github.com/theriverman/django-minio-backend
-]
-```
-
-If you would like to enable on-start consistency check, install via `DjangoMinioBackendConfig`:
-```python
-INSTALLED_APPS = [
- # '...'
- 'django_minio_backend.apps.DjangoMinioBackendConfig', # https://github.com/theriverman/django-minio-backend
-]
-```
-Then add the following parameter to your settings file:
-```python
-MINIO_CONSISTENCY_CHECK_ON_START = True
-```
-
-**Note:** The on-start consistency check equals to manually calling `python manage.py initialize_buckets`.
-It is recommended to turn *off* this feature during development by setting `MINIO_CONSISTENCY_CHECK_ON_START` to `False`,
-because this operation can noticeably slow down Django's boot time when many buckets are configured.
+ ```python
+ INSTALLED_APPS = [
+ # '...'
+ 'django_minio_backend', # https://github.com/theriverman/django-minio-backend
+ ]
+ ```
+
+ If you would like to enable on-start consistency check, install via `DjangoMinioBackendConfig`:
+ ```python
+ INSTALLED_APPS = [
+ # '...'
+ 'django_minio_backend.apps.DjangoMinioBackendConfig', # https://github.com/theriverman/django-minio-backend
+ ]
+ ```
+
+ Then add the following parameter to your settings file:
+ ```python
+ MINIO_CONSISTENCY_CHECK_ON_START = True
+ ```
+
+ **Note:** The on-start consistency check equals to manually calling `python manage.py initialize_buckets`.
+ It is recommended to turn *off* this feature during development by setting `MINIO_CONSISTENCY_CHECK_ON_START` to `False`,
+ because this operation can noticeably slow down Django's boot time when many buckets are configured.
3. Add the following parameters to your `settings.py`:
-```python
-from datetime import timedelta
-from typing import List, Tuple
-
-STORAGES = { # -- ADDED IN Django 5.1
- "default": {
- "BACKEND": "django_minio_backend.models.MinioBackend",
- },
- # "staticfiles": { # -- OPTIONAL
- # "BACKEND": "django_minio_backend.models.MinioBackendStatic",
- # },
-}
-
-MINIO_ENDPOINT = 'minio.your-company.co.uk'
-MINIO_EXTERNAL_ENDPOINT = "external-minio.your-company.co.uk" # Default is same as MINIO_ENDPOINT
-MINIO_EXTERNAL_ENDPOINT_USE_HTTPS = True # Default is same as MINIO_USE_HTTPS
-MINIO_REGION = 'us-east-1' # Default is set to None
-MINIO_ACCESS_KEY = 'yourMinioAccessKey'
-MINIO_SECRET_KEY = 'yourVeryS3cr3tP4ssw0rd'
-MINIO_USE_HTTPS = True
-MINIO_URL_EXPIRY_HOURS = timedelta(days=1) # Default is 7 days (longest) if not defined
-MINIO_CONSISTENCY_CHECK_ON_START = True
-MINIO_PRIVATE_BUCKETS = [
- 'django-backend-dev-private',
-]
-MINIO_PUBLIC_BUCKETS = [
- 'django-backend-dev-public',
-]
-MINIO_POLICY_HOOKS: List[Tuple[str, dict]] = []
-# MINIO_MEDIA_FILES_BUCKET = 'my-media-files-bucket' # replacement for MEDIA_ROOT
-# MINIO_STATIC_FILES_BUCKET = 'my-static-files-bucket' # replacement for STATIC_ROOT
-MINIO_BUCKET_CHECK_ON_SAVE = True # Default: True // Creates bucket if missing, then save
-
-# Custom HTTP Client (OPTIONAL)
-import os
-import certifi
-import urllib3
-timeout = timedelta(minutes=5).seconds
-ca_certs = os.environ.get('SSL_CERT_FILE') or certifi.where()
-MINIO_HTTP_CLIENT: urllib3.poolmanager.PoolManager = urllib3.PoolManager(
- timeout=urllib3.util.Timeout(connect=timeout, read=timeout),
- maxsize=10,
- cert_reqs='CERT_REQUIRED',
- ca_certs=ca_certs,
- retries=urllib3.Retry(
- total=5,
- backoff_factor=0.2,
- status_forcelist=[500, 502, 503, 504]
+ ```python
+ from datetime import timedelta
+ from typing import List, Tuple
+
+ STORAGES = { # -- ADDED IN Django 5.1
+ "default": {
+ "BACKEND": "django_minio_backend.models.MinioBackend",
+ },
+ # "staticfiles": { # -- OPTIONAL
+ # "BACKEND": "django_minio_backend.models.MinioBackendStatic",
+ # },
+ }
+
+ MINIO_ENDPOINT = 'minio.your-company.co.uk'
+ MINIO_EXTERNAL_ENDPOINT = "external-minio.your-company.co.uk" # Default is same as MINIO_ENDPOINT
+ MINIO_EXTERNAL_ENDPOINT_USE_HTTPS = True # Default is same as MINIO_USE_HTTPS
+ MINIO_REGION = 'us-east-1' # Default is set to None
+ MINIO_ACCESS_KEY = 'yourMinioAccessKey'
+ MINIO_SECRET_KEY = 'yourVeryS3cr3tP4ssw0rd'
+ MINIO_USE_HTTPS = True
+ MINIO_URL_EXPIRY_HOURS = timedelta(days=1) # Default is 7 days (longest) if not defined
+ MINIO_CONSISTENCY_CHECK_ON_START = True
+ MINIO_PRIVATE_BUCKETS = [
+ 'django-backend-dev-private',
+ ]
+ MINIO_PUBLIC_BUCKETS = [
+ 'django-backend-dev-public',
+ ]
+ MINIO_POLICY_HOOKS: List[Tuple[str, dict]] = []
+ # MINIO_MEDIA_FILES_BUCKET = 'my-media-files-bucket' # replacement for MEDIA_ROOT
+ # MINIO_STATIC_FILES_BUCKET = 'my-static-files-bucket' # replacement for STATIC_ROOT
+ MINIO_BUCKET_CHECK_ON_SAVE = True # Default: True // Creates bucket if missing, then save
+
+ # Custom HTTP Client (OPTIONAL)
+ import os
+ import certifi
+ import urllib3
+ timeout = timedelta(minutes=5).seconds
+ ca_certs = os.environ.get('SSL_CERT_FILE') or certifi.where()
+ MINIO_HTTP_CLIENT: urllib3.poolmanager.PoolManager = urllib3.PoolManager(
+ timeout=urllib3.util.Timeout(connect=timeout, read=timeout),
+ maxsize=10,
+ cert_reqs='CERT_REQUIRED',
+ ca_certs=ca_certs,
+ retries=urllib3.Retry(
+ total=5,
+ backoff_factor=0.2,
+ status_forcelist=[500, 502, 503, 504]
+ )
)
-)
-```
+ ```
4. Implement your own Attachment handler and integrate **django-minio-backend**:
-```python
-from django.db import models
-from django_minio_backend import MinioBackend, iso_date_prefix
-
-class PrivateAttachment(models.Model):
- file = models.FileField(verbose_name="Object Upload",
- storage=MinioBackend(bucket_name='django-backend-dev-private'),
- upload_to=iso_date_prefix)
-```
+ ```python
+ from django.db import models
+ from django_minio_backend import MinioBackend, iso_date_prefix
+
+ class PrivateAttachment(models.Model):
+ file = models.FileField(verbose_name="Object Upload",
+ storage=MinioBackend(bucket_name='django-backend-dev-private'),
+ upload_to=iso_date_prefix)
+ ```
5. Initialize the buckets & set their public policy (OPTIONAL):
This `django-admin` command creates both the private and public buckets in case one of them does not exist,
and sets the *public* bucket's privacy policy from `private`(default) to `public`.
-```bash
-python manage.py initialize_buckets
-```
+ ```bash
+ python manage.py initialize_buckets
+ ```
-Code reference: [initialize_buckets.py](django_minio_backend/management/commands/initialize_buckets.py).
+ Code reference: [initialize_buckets.py](django_minio_backend/management/commands/initialize_buckets.py).
### Static Files Support
**django-minio-backend** allows serving static files from MinIO.
@@ -184,13 +205,13 @@ You can configure **django-minio-backend** to automatically execute a set of pre
Policy hooks can be defined in `settings.py` by adding `MINIO_POLICY_HOOKS` which must be a list of tuples.
Policy hooks are automatically picked up by the `initialize_buckets` management command.
-For an exemplary policy, see the implementation of `def set_bucket_to_public(self)`
+For an exemplary policy, see the implementation of `set_bucket_to_public()`
in [django_minio_backend/models.py](django_minio_backend/models.py) or the contents
of [examples/policy_hook.example.py](examples/policy_hook.example.py).
### Consistency Check On Start
When enabled, the `initialize_buckets` management command gets called automatically when Django starts.
-This command connects to the configured minIO server and checks if all buckets defined in `settings.py`.
+This command connects to the configured MinIO server and checks if all buckets defined in `settings.py`.
In case a bucket is missing or its configuration differs, it gets created and corrected.
### Reference Implementation
@@ -205,7 +226,10 @@ The following list summarises the key characteristics of **django-minio-backend*
* Many configuration errors are validated through `AppConfig` but not every error can be captured there.
* Files with the same name in the same bucket are **not** replaced on save by default. Django will store the newer file with an altered file name
To allow replacing existing files, pass the `replace_existing=True` kwarg to `MinioBackend`.
- For example: `image = models.ImageField(storage=MinioBackend(bucket_name='images-public', replace_existing=True))`
+ For example:
+ ```python
+ image = models.ImageField(storage=MinioBackend(bucket_name='images-public', replace_existing=True))
+ ```
* Depending on your configuration, **django-minio-backend** may communicate over two kind of interfaces: internal and external.
If your `settings.py` defines a different value for `MINIO_ENDPOINT` and `MINIO_EXTERNAL_ENDPOINT`, then the former will be used for internal communication
between Django and MinIO, and the latter for generating URLs for users. This behaviour optimises the network communication.
@@ -224,11 +248,6 @@ To learn more about Docker networking, see [Networking overview](https://docs.do
See [README.Docker.md](README.Docker.md) for a real-life Docker Compose demonstration.
-## Compatibility
- * Django 4.2 or later
- * Python 3.10.0 or later
- * MinIO SDK 7.0.2 or later
-
## Contribution
Please find the details in [CONTRIBUTE.md](CONTRIBUTE.md)
diff --git a/setup.py b/setup.py
index c9d7e36..e597f42 100644
--- a/setup.py
+++ b/setup.py
@@ -37,7 +37,6 @@
'License :: OSI Approved :: MIT License',
'Operating System :: OS Independent',
'Programming Language :: Python',
- 'Programming Language :: Python :: 3.10',
'Programming Language :: Python :: 3.11',
'Programming Language :: Python :: 3.12',
'Programming Language :: Python :: 3.13',