config
This commit is contained in:
parent
b1867a9a07
commit
da7d25d29e
7 changed files with 131 additions and 12 deletions
|
|
@ -1,4 +1,12 @@
|
|||
from django.contrib import admin
|
||||
from .models import Config
|
||||
|
||||
|
||||
class ConfigAdmin(admin.ModelAdmin):
|
||||
list_display = ['key', 'value', 'value_type', 'get_value', 'description', 'comment']
|
||||
|
||||
admin.site.register(Config, ConfigAdmin)
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
31
apps/core/decorators.py
Normal file
31
apps/core/decorators.py
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
from functools import wraps
|
||||
|
||||
from django.utils import timezone
|
||||
|
||||
from apps.core.models import Config, ConfigValueChoices
|
||||
from utils.exceptions import ServiceUnavailable
|
||||
|
||||
|
||||
def service_availability(key:str):
|
||||
def with_params(view_func):
|
||||
@wraps(view_func)
|
||||
def wrapper(self, request, *args, **kwargs):
|
||||
print(key)
|
||||
print(f"Executing {view_func.__name__} action")
|
||||
|
||||
service_is_available = Config.get_value_of(f"SERVICE_IS_AVAILABLE_{key.upper()}", "True", ConfigValueChoices.BOOLEAN)
|
||||
config = Config.objects.get(key=f"SERVICE_IS_AVAILABLE_{key.upper()}")
|
||||
if not service_is_available:
|
||||
raise ServiceUnavailable(
|
||||
detail={
|
||||
# "code": 'service_unavailable_at_now',
|
||||
# "timestamp": timezone.now().isoformat(),
|
||||
"message": config.description or "این سرویس در حال حاضر در دسترس نیست"
|
||||
},
|
||||
)
|
||||
|
||||
return view_func(self, request, *args, **kwargs)
|
||||
|
||||
return wrapper
|
||||
|
||||
return with_params
|
||||
31
apps/core/migrations/0001_initial.py
Normal file
31
apps/core/migrations/0001_initial.py
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
# Generated by Django 5.1.4 on 2026-03-29 13:38
|
||||
|
||||
import uuid
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Config',
|
||||
fields=[
|
||||
('uuid', models.UUIDField(db_index=True, default=uuid.uuid4, editable=False, primary_key=True, serialize=False, unique=True)),
|
||||
('created_at', models.DateTimeField(auto_now_add=True, db_index=True)),
|
||||
('updated_at', models.DateTimeField(auto_now=True, db_index=True)),
|
||||
('key', models.CharField(db_index=True, max_length=255, unique=True, verbose_name='key')),
|
||||
('value', models.TextField(blank=True, null=True, verbose_name='value')),
|
||||
('value_type', models.CharField(choices=[('INT', 'Integer'), ('FLOAT', 'Float'), ('BOOLEAN', 'Boolean'), ('STRING', 'String'), ('DATE', 'Date'), ('DATETIME', 'DateTime'), ('JSON', 'JSON')], max_length=64)),
|
||||
('description', models.TextField(blank=True, null=True, verbose_name='description')),
|
||||
('comment', models.TextField(blank=True, null=True, verbose_name='comment')),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
]
|
||||
0
apps/core/migrations/__init__.py
Normal file
0
apps/core/migrations/__init__.py
Normal file
|
|
@ -6,6 +6,7 @@ from django.db import models
|
|||
from django.utils.translation import gettext_lazy as _
|
||||
from django.core.cache import cache
|
||||
|
||||
|
||||
class BaseModel(models.Model):
|
||||
id = None
|
||||
uuid = models.UUIDField(primary_key=True, editable=False, default=uuid.uuid4, unique=True, db_index=True)
|
||||
|
|
@ -16,7 +17,6 @@ class BaseModel(models.Model):
|
|||
abstract = True
|
||||
|
||||
|
||||
|
||||
class BasePGModel(models.Model):
|
||||
created_at = models.DateTimeField(auto_now_add=True, db_index=True)
|
||||
updated_at = models.DateTimeField(auto_now=True, db_index=True)
|
||||
|
|
@ -39,8 +39,64 @@ class BasePGModel(models.Model):
|
|||
abstract = True
|
||||
|
||||
|
||||
class ConfigValueChoices(models.TextChoices):
|
||||
INT = 'INT', _('Integer')
|
||||
FLOAT = 'FLOAT', _('Float')
|
||||
BOOLEAN = 'BOOLEAN', _('Boolean')
|
||||
STRING = 'STRING', _('String')
|
||||
DATE = 'DATE', _('Date')
|
||||
DATETIME = 'DATETIME', _('DateTime')
|
||||
JSON = 'JSON', _('JSON')
|
||||
|
||||
|
||||
class Config(BaseModel):
|
||||
key = models.CharField(_('key'), max_length=255, unique=True, db_index=True)
|
||||
value = models.TextField(_('value'), null=True, blank=True)
|
||||
value_type = models.CharField(choices=ConfigValueChoices.choices, max_length=64)
|
||||
description = models.TextField(_('description'), null=True, blank=True)
|
||||
comment = models.TextField(_('comment'), null=True, blank=True)
|
||||
|
||||
def get_value(self):
|
||||
return Config.get_value_of(self.key)
|
||||
|
||||
@staticmethod
|
||||
def type_cast(value, value_type):
|
||||
|
||||
try:
|
||||
if value_type == ConfigValueChoices.STRING.value:
|
||||
value = str(value)
|
||||
|
||||
elif value_type == ConfigValueChoices.BOOLEAN.value:
|
||||
value = value.lower() == 'true'
|
||||
|
||||
elif value_type == ConfigValueChoices.DATE.value:
|
||||
value = datetime.fromisoformat(value)
|
||||
|
||||
elif value_type == ConfigValueChoices.DATETIME.value:
|
||||
value = datetime.fromisoformat(value)
|
||||
|
||||
elif value_type == ConfigValueChoices.JSON.value:
|
||||
value = json.loads(value)
|
||||
|
||||
elif value_type == ConfigValueChoices.INT.value:
|
||||
value = int(value)
|
||||
|
||||
elif value_type == ConfigValueChoices.FLOAT.value:
|
||||
value = float(value)
|
||||
|
||||
except Exception as e:
|
||||
value = None
|
||||
|
||||
return value
|
||||
|
||||
@staticmethod
|
||||
def get_value_of(key, default=None, casting_type=None):
|
||||
# TODO: use cache
|
||||
config, created = Config.objects.get_or_create(key=key, defaults={'value': default})
|
||||
|
||||
if config.value is None:
|
||||
return default
|
||||
|
||||
value = Config.type_cast(config.value, casting_type or config.value_type)
|
||||
|
||||
return value
|
||||
|
|
|
|||
|
|
@ -10,7 +10,8 @@ from rest_framework.permissions import AllowAny
|
|||
from rest_framework.response import Response
|
||||
from rest_framework.views import APIView
|
||||
|
||||
from utils.exceptions import StatusError
|
||||
from apps.core.decorators import service_availability
|
||||
from utils.exceptions import ServiceUnavailable
|
||||
|
||||
|
||||
# Create your views here.
|
||||
|
|
@ -22,16 +23,8 @@ class HomeView(TemplateView):
|
|||
class StatusView(APIView):
|
||||
permission_classes = [AllowAny]
|
||||
|
||||
@service_availability('status')
|
||||
def get(self, request, format=None):
|
||||
if self.request.GET.get('raise_error'):
|
||||
raise StatusError(
|
||||
# code='service_unavailable_at_now',
|
||||
detail={
|
||||
# "code": 'service_unavailable_at_now',
|
||||
"timestamp": timezone.now().isoformat(),
|
||||
"message": "برخی سرویسهای خارجی در دسترس نیستند لطفا بعدا تلاش کنید"
|
||||
},
|
||||
)
|
||||
|
||||
data = {
|
||||
"status": "ok",
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ class UnprocessableEntity(APIException):
|
|||
default_detail = 'The request was well-formed but cannot be processed due to semantic errors.'
|
||||
default_code = 'unprocessable_entity'
|
||||
|
||||
class StatusError(APIException):
|
||||
class ServiceUnavailable(APIException):
|
||||
status_code = status.HTTP_503_SERVICE_UNAVAILABLE
|
||||
default_ = _('SERVICE_UNAVAILABLE')
|
||||
default_code = 'service_unavailable'
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue