Compare commits

...

3 Commits

Author SHA1 Message Date
16db83fd6d + API schema as Redoc
+ Django & DRF API exceptions in one format
2024-05-21 01:19:10 +04:00
fa5e1cd860 * Checklist.bonus_used as an absolute value 2024-05-21 01:15:55 +04:00
0c51a7c3fb * Missing LocMemCache backend 2024-05-21 01:09:27 +04:00
6 changed files with 40 additions and 3 deletions

View File

@ -1,3 +1,4 @@
from .celery import app as celery_app from .celery import app as celery_app
import poizonstore.schema
__all__ = ('celery_app',) __all__ = ('celery_app',)

18
poizonstore/exceptions.py Normal file
View File

@ -0,0 +1,18 @@
from django.core.exceptions import ValidationError as DjangoValidationError
from rest_framework.exceptions import ValidationError as DRFValidationError
from rest_framework.views import exception_handler as drf_exception_handler
def exception_handler(exc, context):
""" Handle Django ValidationError as an accepted exception """
if isinstance(exc, DjangoValidationError):
if hasattr(exc, 'message_dict'):
exc = DRFValidationError(detail={'error': exc.message_dict})
elif hasattr(exc, 'message'):
exc = DRFValidationError(detail={'error': exc.message})
elif hasattr(exc, 'messages'):
exc = DRFValidationError(detail={'error': exc.messages})
return drf_exception_handler(exc, context)

View File

@ -98,6 +98,7 @@ INSTALLED_APPS = [
'debug_toolbar', 'debug_toolbar',
'django_filters', 'django_filters',
'mptt', 'mptt',
'drf_spectacular',
'account', 'account',
'store', 'store',
@ -147,6 +148,12 @@ DATABASES = {
} }
} }
CACHES = {
"default": {
"BACKEND": "django.core.cache.backends.locmem.LocMemCache",
}
}
# Password validation # Password validation
# https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators # https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators
@ -179,7 +186,10 @@ REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': ['rest_framework.authentication.TokenAuthentication'], 'DEFAULT_AUTHENTICATION_CLASSES': ['rest_framework.authentication.TokenAuthentication'],
'DEFAULT_FILTER_BACKENDS': ['django_filters.rest_framework.DjangoFilterBackend'], 'DEFAULT_FILTER_BACKENDS': ['django_filters.rest_framework.DjangoFilterBackend'],
'DEFAULT_PAGINATION_CLASS': 'utils.drf.StandardResultsSetPagination' 'DEFAULT_PAGINATION_CLASS': 'utils.drf.StandardResultsSetPagination',
'EXCEPTION_HANDLER': 'poizonstore.exceptions.exception_handler',
'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema',
} }
DJOSER = { DJOSER = {

View File

@ -18,6 +18,7 @@ from django.conf import settings
from django.conf.urls.static import static from django.conf.urls.static import static
from django.contrib import admin from django.contrib import admin
from django.urls import path, include from django.urls import path, include
from drf_spectacular.views import SpectacularAPIView, SpectacularRedocView
urlpatterns = [ urlpatterns = [
@ -28,3 +29,9 @@ urlpatterns = [
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) \ ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) \
+ static(settings.STATIC_URL) + static(settings.STATIC_URL)
# API schema
if settings.DEBUG:
urlpatterns += [
path('api/schema/', SpectacularAPIView.as_view(), name='schema'),
path('api/redoc/', SpectacularRedocView.as_view(url_name='schema'), name='redoc'),
]

View File

@ -24,6 +24,7 @@ tqdm==4.65.0
django-debug-toolbar==4.1.0 django-debug-toolbar==4.1.0
requests==2.31.0 requests==2.31.0
python-dotenv==1.0.1 python-dotenv==1.0.1
drf-spectacular==0.27.2
# Logging # Logging
sentry-sdk==1.34.0 sentry-sdk==1.34.0

View File

@ -13,7 +13,7 @@ from django.core.files.base import ContentFile
from django.core.validators import MinValueValidator, MaxValueValidator from django.core.validators import MinValueValidator, MaxValueValidator
from django.db import models from django.db import models
from django.db.models import F, Case, When, DecimalField, Prefetch, Max, Q, Subquery, OuterRef from django.db.models import F, Case, When, DecimalField, Prefetch, Max, Q, Subquery, OuterRef
from django.db.models.functions import Ceil, Coalesce from django.db.models.functions import Ceil, Coalesce, Abs
from django.db.models.lookups import GreaterThan from django.db.models.lookups import GreaterThan
from django.db.transaction import atomic from django.db.transaction import atomic
from django.utils import timezone from django.utils import timezone
@ -215,7 +215,7 @@ class ChecklistQuerySet(models.QuerySet):
order_id=OuterRef('id')) order_id=OuterRef('id'))
.values('amount')) .values('amount'))
return self.annotate(_bonus_used=Coalesce(amount_subquery, 0)) return self.annotate(_bonus_used=Coalesce(Abs(amount_subquery), 0))
def default_ordering(self): def default_ordering(self):
return self.order_by(F('status_updated_at').desc(nulls_last=True)) return self.order_by(F('status_updated_at').desc(nulls_last=True))