From 6165a951df466cdb404ef648a9395f94444ed2a8 Mon Sep 17 00:00:00 2001 From: Sayyid Hamid Mahdavi Date: Tue, 22 Jul 2025 15:25:02 +0330 Subject: [PATCH] minio --- accounts/settings.py | 59 ++++++++++++++++++- .../migrations/0006_alter_user_avatar.py | 19 ++++++ apps/users/models.py | 4 +- requirements.in | 3 +- requirements.txt | 24 +++++++- 5 files changed, 103 insertions(+), 6 deletions(-) create mode 100644 apps/users/migrations/0006_alter_user_avatar.py diff --git a/accounts/settings.py b/accounts/settings.py index b02b1ea..591a480 100644 --- a/accounts/settings.py +++ b/accounts/settings.py @@ -49,6 +49,7 @@ INSTALLED_APPS = [ 'crispy_bootstrap5', 'django_filters', 'jalali_date', + 'django_minio_backend.apps.DjangoMinioBackendConfig', # local apps 'apps.core', @@ -275,4 +276,60 @@ CACHES = { "CLIENT_CLASS": "django_redis.client.DefaultClient", } } -} \ No newline at end of file +} + +from datetime import timedelta +from typing import List, Tuple + +STORAGES = { + "default": { + "BACKEND": "django_minio_backend.models.MinioBackend", + }, + "staticfiles": { + # "BACKEND": "django_minio_backend.models.MinioBackendStatic", + # "BACKEND": "django.core.files.storage.FileSystemStorage", + "BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage", + }, +} + +MINIO_ENDPOINT = config('MINIO_ENDPOINT', default='drive.gooyal.com') +MINIO_USE_HTTPS = config('MINIO_USE_HTTPS', default=True, cast=bool) + +MINIO_EXTERNAL_ENDPOINT = config('MINIO_EXTERNAL_ENDPOINT', default='drive.gooyal.com') # Default is same as MINIO_ENDPOINT +MINIO_EXTERNAL_ENDPOINT_USE_HTTPS = config('MINIO_EXTERNAL_ENDPOINT_USE_HTTPS', default=True, cast=bool) # Default is same as MINIO_USE_HTTPS +MINIO_REGION = None # Default is set to None +MINIO_ACCESS_KEY = config('MINIO_ACCESS_KEY') +MINIO_SECRET_KEY = config('MINIO_SECRET_KEY') +MINIO_URL_EXPIRY_HOURS = timedelta(days=1) # Default is 7 days (longest) if not defined +MINIO_CONSISTENCY_CHECK_ON_START = True +MINIO_MEDIA_FILES_BUCKET = config('MINIO_MEDIA_FILES_BUCKET') # replacement for MEDIA_ROOT +# MINIO_STATIC_FILES_BUCKET = 'my-static-files-bucket' # replacement for STATIC_ROOT + +MINIO_PRIVATE_BUCKETS = [ + 'default', +] +MINIO_PUBLIC_BUCKETS = [ + 'default-public', + MINIO_MEDIA_FILES_BUCKET +] +MINIO_POLICY_HOOKS: List[Tuple[str, dict]] = [] +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] + ) +) diff --git a/apps/users/migrations/0006_alter_user_avatar.py b/apps/users/migrations/0006_alter_user_avatar.py new file mode 100644 index 0000000..d589f74 --- /dev/null +++ b/apps/users/migrations/0006_alter_user_avatar.py @@ -0,0 +1,19 @@ +# Generated by Django 5.1.4 on 2025-07-22 11:34 + +import django_minio_backend.models +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('users', '0005_user_birthdate_user_education_degree_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='user', + name='avatar', + field=models.ImageField(blank=True, null=True, storage=django_minio_backend.models.MinioBackend(), upload_to=django_minio_backend.models.iso_date_prefix), + ), + ] diff --git a/apps/users/models.py b/apps/users/models.py index 1a87da2..2ee813c 100644 --- a/apps/users/models.py +++ b/apps/users/models.py @@ -12,6 +12,8 @@ from django.utils import timezone from django.utils.translation import gettext_lazy as _ import uuid +from django_minio_backend import MinioBackend, iso_date_prefix + from utils.clients.payam_sms import send_sms from .provinces_and_cities import state # from .tasks import send_notification @@ -123,7 +125,7 @@ class User(AbstractUser): iban = models.CharField(null=True, max_length=30, blank=True) iban_verified = models.BooleanField(null=True) - avatar = models.ImageField(upload_to='avatars', null=True, blank=True) + avatar = models.ImageField(null=True, blank=True, storage=MinioBackend(), upload_to=iso_date_prefix) gender = models.CharField(_('gender'), choices=GenderChoices.choices, blank=True, null=True) education_degree = models.CharField(_('education degree'), choices=EducationDegreeChoices.choices, max_length=10, null=True, blank=True) education_field = models.CharField(_('education field'), max_length=100, null=True, blank=True) diff --git a/requirements.in b/requirements.in index 45b5ac7..d95440d 100644 --- a/requirements.in +++ b/requirements.in @@ -17,4 +17,5 @@ crispy_bootstrap5 django-jalali-date django-betterforms psycopg[binary] -django_redis \ No newline at end of file +django_redis +django_minio_backend \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 31a335e..06169ec 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,6 +6,10 @@ # amqp==5.3.1 # via kombu +argon2-cffi==25.1.0 + # via minio +argon2-cffi-bindings==21.2.0 + # via argon2-cffi asgiref==3.8.1 # via # django @@ -21,9 +25,13 @@ billiard==4.2.1 celery==5.4.0 # via -r requirements.in certifi==2024.12.14 - # via requests + # via + # minio + # requests cffi==1.17.1 - # via cryptography + # via + # argon2-cffi-bindings + # cryptography charset-normalizer==3.4.0 # via requests click==8.1.7 @@ -51,6 +59,7 @@ django==5.1.4 # django-crispy-forms # django-filter # django-jalali-date + # django-minio-backend # django-oauth-toolkit # django-redis # djangorestframework @@ -67,6 +76,8 @@ django-filter==24.3 # via -r requirements.in django-jalali-date==1.1.3 # via -r requirements.in +django-minio-backend==3.8.0 + # via -r requirements.in django-oauth-toolkit==3.0.1 # via -r requirements.in django-redis==6.0.0 @@ -101,6 +112,8 @@ kombu==5.4.2 # via celery markdown==3.7 # via -r requirements.in +minio==7.2.16 + # via django-minio-backend oauthlib==3.2.2 # via django-oauth-toolkit packaging==24.2 @@ -115,6 +128,8 @@ psycopg-binary==3.2.3 # via psycopg pycparser==2.22 # via cffi +pycryptodome==3.23.0 + # via minio python-dateutil==2.9.0.post0 # via celery python-decouple==3.8 @@ -142,6 +157,7 @@ sqlparse==0.5.3 typing-extensions==4.12.2 # via # jwcrypto + # minio # psycopg tzdata==2024.2 # via @@ -150,7 +166,9 @@ tzdata==2024.2 uritemplate==4.1.1 # via drf-spectacular urllib3==2.2.3 - # via requests + # via + # minio + # requests vine==5.1.0 # via # amqp