From 6a8de76c42babbd9438e890988fdfc8677cc47ce Mon Sep 17 00:00:00 2001 From: Dmitry Titenkov Date: Sun, 16 Nov 2025 20:34:14 +0300 Subject: [PATCH 1/2] logging, exceptions --- .gitignore | 3 ++ backend/api/v1/views.py | 85 +++++++++++++++++++++++++++++-------- backend/bookinn/settings.py | 43 +++++++++++++++++++ requirements.txt | 3 ++ 4 files changed, 117 insertions(+), 17 deletions(-) diff --git a/.gitignore b/.gitignore index 6394a79..4e5619c 100644 --- a/.gitignore +++ b/.gitignore @@ -207,3 +207,6 @@ marimo/_lsp/ __marimo__/ media/ + +logs/ +*.log diff --git a/backend/api/v1/views.py b/backend/api/v1/views.py index b9a8b7f..3017750 100644 --- a/backend/api/v1/views.py +++ b/backend/api/v1/views.py @@ -1,6 +1,8 @@ +import logging + from django_filters.rest_framework import DjangoFilterBackend from drf_spectacular.utils import extend_schema -from rest_framework import filters, permissions, viewsets +from rest_framework import filters, permissions, serializers, viewsets from api.v1.permissions import IsAdminOrReadOnly, IsOwnerOrAdmin from api.v1.serializers import ( @@ -15,6 +17,9 @@ from rooms.models import Booking, Room, RoomImage, RoomType +logger = logging.getLogger('rooms') + + @extend_schema(tags=["RoomType"], summary="Управление типами номеров") class RoomTypeViewSet(viewsets.ModelViewSet): """Позволяет администратору создавать, изменять и удалять типы номеров, @@ -28,6 +33,15 @@ class RoomTypeViewSet(viewsets.ModelViewSet): filter_backends = (filters.OrderingFilter,) ordering_fields = ("name",) + def get_queryset(self): + try: + queryset = RoomType.objects.all() + logger.info(f'Запрошены типы номеров, всего найдено: {queryset.count()}') + return queryset + except Exception as error: + logger.debug(f'Ошибка при получении типов номеров: {error}', exc_info=True) + return RoomType.objects.none() + @extend_schema(tags=["RoomImage"]) class RoomImageViewSet(viewsets.ModelViewSet): @@ -36,9 +50,15 @@ class RoomImageViewSet(viewsets.ModelViewSet): permission_classes = (permissions.IsAdminUser,) def get_serializer_class(self): - if self.action in ["list", "retrieve"]: - return RoomImageReadSerializer - return RoomImageWriteSerializer + try: + if self.action in ["list", "retrieve"]: + logger.debug(f'Используется RoomImageReadSerializer для действия {self.action}') + return RoomImageReadSerializer + logger.debug(f'Используется RoomImageWriteSerializer для действия {self.action}') + return RoomImageWriteSerializer + except Exception as error: + logger.error(f'Ошибка при выборе сериализатора для RoomImage: {error}', exc_info=True) + return RoomImageWriteSerializer @extend_schema( @@ -66,14 +86,27 @@ class RoomViewSet(viewsets.ModelViewSet): ) def get_serializer_class(self): - if self.action in ["list", "retrieve"]: - return RoomReadSerializer - return RoomWriteSerializer + try: + if self.action in ["list", "retrieve"]: + logger.debug(f'Используется RoomReadSerializer для действия {self.action}') + return RoomReadSerializer + logger.debug(f'Используется RoomWriteSerializer для действия {self.action}') + return RoomWriteSerializer + except Exception as error: + logger.error(f'Ошибка при выборе сериализатора для Room: {error}', exc_info=True) + return RoomWriteSerializer def get_queryset(self): - if self.request.user.is_staff or self.request.user.is_superuser: - return Room.objects.all() - return Room.objects.filter(is_available=True) + try: + if self.request.user.is_staff or self.request.user.is_superuser: + queryset = Room.objects.all() + else: + queryset = Room.objects.filter(is_available=True) + logger.debug(f'Запрошены номера, всего найдено: {queryset.count()}') + return queryset + except Exception as error: + logger.error(f'Ошибка при получении списка номеров: {error}', exc_info=True) + return Room.objects.none() @extend_schema(tags=["Booking"], summary="Работа с бронированиями") @@ -92,14 +125,32 @@ class BookingViewSet(viewsets.ModelViewSet): ordering_fields = ("status", "check_in", "check_out") def get_serializer_class(self): - if self.action in ["list", "retrieve"]: - return BookingReadSerializer - return BookingWriteSerializer + try: + if self.action in ["list", "retrieve"]: + logger.debug(f'Используется BookingReadSerializer для действия {self.action}') + return BookingReadSerializer + logger.debug(f'Используется BookingWriteSerializer для действия {self.action}') + return BookingWriteSerializer + except Exception as error: + logger.error(f'Ошибка при выборе сериализатора для Booking: {error}', exc_info=True) + return BookingWriteSerializer def get_queryset(self): - if self.request.user.is_staff or self.request.user.is_superuser: - return Booking.objects.all() - return Booking.objects.filter(user=self.request.user) + try: + if self.request.user.is_staff or self.request.user.is_superuser: + queryset = Booking.objects.all() + else: + queryset = Booking.objects.filter(user=self.request.user) + logger.debug(f'Запрошены бронирования пользователем: {self.request.user}, найдеено бронирований: {queryset.count()}') + return queryset + except Exception as error: + logger.error(f'Ошибка при получении списка бронирований: {error}', exc_info=True) + return Booking.objects.none() def perform_create(self, serializer): - serializer.save(user=self.request.user) + try: + serializer.save(user=self.request.user) + logger.info(f'Пользователь {self.request.user} создал бронирование для номера {serializer.instance.room}') + except Exception as error: + logger.error(f'Не удалось создать бронирование: {error}', exc_info=True) + raise serializers.ValidationError({'error': 'Не Удалось создать бронирование'}) diff --git a/backend/bookinn/settings.py b/backend/bookinn/settings.py index e5a3913..4fa0e90 100644 --- a/backend/bookinn/settings.py +++ b/backend/bookinn/settings.py @@ -6,6 +6,49 @@ BASE_DIR = Path(__file__).resolve().parent.parent +LOG_DIR = Path(BASE_DIR / 'logs') +LOG_DIR.mkdir(exist_ok=True) + +LOGGING = { + 'version': 1, + 'disable_existing_loggers': False, + 'formatters': { + "verbose": { + "format": "{levelname} {asctime} {module} {message}", + "style": "{", + }, + "simple": { + "format": "{levelname} {message}", + "style": "{", + }, + }, + 'handlers': { + 'console': { + 'level': 'DEBUG', + 'class': 'logging.StreamHandler', + 'formatter': 'verbose', + }, + 'file': { + 'level': 'INFO', + 'class': 'logging.FileHandler', + 'filename': LOG_DIR / 'django.log', + 'formatter': 'verbose' + }, + }, + 'loggers': { + 'django': { + 'handlers': ['console', 'file'], + 'level': 'INFO', + 'propagate': True + }, + 'rooms': { + 'handlers': ['console', 'file'], + 'level': 'DEBUG', + 'propagate': False + } + }, +} + load_dotenv() SECRET_KEY = os.getenv("SECRET_KEY", default="supersecretkey") diff --git a/requirements.txt b/requirements.txt index 9d7eacc..e61e612 100644 --- a/requirements.txt +++ b/requirements.txt @@ -14,9 +14,11 @@ djangorestframework_simplejwt==5.5.1 djoser==2.3.3 drf-spectacular==0.29.0 flake8==7.3.0 +flake8-isort==6.1.2 idna==3.11 importlib_metadata==8.7.0 inflection==0.5.1 +isort==6.1.0 jsonschema==4.25.1 jsonschema-specifications==2025.9.1 Markdown==3.9 @@ -27,6 +29,7 @@ packaging==25.0 pathspec==0.12.1 pillow==11.3.0 platformdirs==4.4.0 +psycopg2-binary==2.9.11 pycodestyle==2.14.0 pycparser==2.23 pyflakes==3.4.0 From e84f6b1c7ef375fc17ae31c12de0e8aaaee00407 Mon Sep 17 00:00:00 2001 From: Dmitry Titenkov Date: Sun, 16 Nov 2025 20:34:50 +0300 Subject: [PATCH 2/2] logging, exceptions --- backend/api/v1/views.py | 63 +++++++++++++++++++++++++------------ backend/bookinn/settings.py | 42 ++++++++++--------------- 2 files changed, 60 insertions(+), 45 deletions(-) diff --git a/backend/api/v1/views.py b/backend/api/v1/views.py index 3017750..1a6e8f1 100644 --- a/backend/api/v1/views.py +++ b/backend/api/v1/views.py @@ -16,8 +16,7 @@ ) from rooms.models import Booking, Room, RoomImage, RoomType - -logger = logging.getLogger('rooms') +logger = logging.getLogger("rooms") @extend_schema(tags=["RoomType"], summary="Управление типами номеров") @@ -36,10 +35,10 @@ class RoomTypeViewSet(viewsets.ModelViewSet): def get_queryset(self): try: queryset = RoomType.objects.all() - logger.info(f'Запрошены типы номеров, всего найдено: {queryset.count()}') + logger.info(f"Запрошены типы номеров, всего найдено: {queryset.count()}") return queryset except Exception as error: - logger.debug(f'Ошибка при получении типов номеров: {error}', exc_info=True) + logger.debug(f"Ошибка при получении типов номеров: {error}", exc_info=True) return RoomType.objects.none() @@ -52,12 +51,18 @@ class RoomImageViewSet(viewsets.ModelViewSet): def get_serializer_class(self): try: if self.action in ["list", "retrieve"]: - logger.debug(f'Используется RoomImageReadSerializer для действия {self.action}') + logger.debug( + f"Используется RoomImageReadSerializer для действия {self.action}" + ) return RoomImageReadSerializer - logger.debug(f'Используется RoomImageWriteSerializer для действия {self.action}') + logger.debug( + f"Используется RoomImageWriteSerializer для действия {self.action}" + ) return RoomImageWriteSerializer except Exception as error: - logger.error(f'Ошибка при выборе сериализатора для RoomImage: {error}', exc_info=True) + logger.error( + f"Ошибка при выборе сериализатора для RoomImage: {error}", exc_info=True + ) return RoomImageWriteSerializer @@ -88,12 +93,16 @@ class RoomViewSet(viewsets.ModelViewSet): def get_serializer_class(self): try: if self.action in ["list", "retrieve"]: - logger.debug(f'Используется RoomReadSerializer для действия {self.action}') + logger.debug( + f"Используется RoomReadSerializer для действия {self.action}" + ) return RoomReadSerializer - logger.debug(f'Используется RoomWriteSerializer для действия {self.action}') + logger.debug(f"Используется RoomWriteSerializer для действия {self.action}") return RoomWriteSerializer except Exception as error: - logger.error(f'Ошибка при выборе сериализатора для Room: {error}', exc_info=True) + logger.error( + f"Ошибка при выборе сериализатора для Room: {error}", exc_info=True + ) return RoomWriteSerializer def get_queryset(self): @@ -102,10 +111,10 @@ def get_queryset(self): queryset = Room.objects.all() else: queryset = Room.objects.filter(is_available=True) - logger.debug(f'Запрошены номера, всего найдено: {queryset.count()}') + logger.debug(f"Запрошены номера, всего найдено: {queryset.count()}") return queryset except Exception as error: - logger.error(f'Ошибка при получении списка номеров: {error}', exc_info=True) + logger.error(f"Ошибка при получении списка номеров: {error}", exc_info=True) return Room.objects.none() @@ -127,12 +136,18 @@ class BookingViewSet(viewsets.ModelViewSet): def get_serializer_class(self): try: if self.action in ["list", "retrieve"]: - logger.debug(f'Используется BookingReadSerializer для действия {self.action}') + logger.debug( + f"Используется BookingReadSerializer для действия {self.action}" + ) return BookingReadSerializer - logger.debug(f'Используется BookingWriteSerializer для действия {self.action}') + logger.debug( + f"Используется BookingWriteSerializer для действия {self.action}" + ) return BookingWriteSerializer except Exception as error: - logger.error(f'Ошибка при выборе сериализатора для Booking: {error}', exc_info=True) + logger.error( + f"Ошибка при выборе сериализатора для Booking: {error}", exc_info=True + ) return BookingWriteSerializer def get_queryset(self): @@ -141,16 +156,24 @@ def get_queryset(self): queryset = Booking.objects.all() else: queryset = Booking.objects.filter(user=self.request.user) - logger.debug(f'Запрошены бронирования пользователем: {self.request.user}, найдеено бронирований: {queryset.count()}') + logger.debug( + f"Запрошены бронирования пользователем: {self.request.user}, найдеено бронирований: {queryset.count()}" + ) return queryset except Exception as error: - logger.error(f'Ошибка при получении списка бронирований: {error}', exc_info=True) + logger.error( + f"Ошибка при получении списка бронирований: {error}", exc_info=True + ) return Booking.objects.none() def perform_create(self, serializer): try: serializer.save(user=self.request.user) - logger.info(f'Пользователь {self.request.user} создал бронирование для номера {serializer.instance.room}') + logger.info( + f"Пользователь {self.request.user} создал бронирование для номера {serializer.instance.room}" + ) except Exception as error: - logger.error(f'Не удалось создать бронирование: {error}', exc_info=True) - raise serializers.ValidationError({'error': 'Не Удалось создать бронирование'}) + logger.error(f"Не удалось создать бронирование: {error}", exc_info=True) + raise serializers.ValidationError( + {"error": "Не Удалось создать бронирование"} + ) diff --git a/backend/bookinn/settings.py b/backend/bookinn/settings.py index 4fa0e90..fac870e 100644 --- a/backend/bookinn/settings.py +++ b/backend/bookinn/settings.py @@ -6,13 +6,13 @@ BASE_DIR = Path(__file__).resolve().parent.parent -LOG_DIR = Path(BASE_DIR / 'logs') +LOG_DIR = Path(BASE_DIR / "logs") LOG_DIR.mkdir(exist_ok=True) LOGGING = { - 'version': 1, - 'disable_existing_loggers': False, - 'formatters': { + "version": 1, + "disable_existing_loggers": False, + "formatters": { "verbose": { "format": "{levelname} {asctime} {module} {message}", "style": "{", @@ -22,30 +22,22 @@ "style": "{", }, }, - 'handlers': { - 'console': { - 'level': 'DEBUG', - 'class': 'logging.StreamHandler', - 'formatter': 'verbose', + "handlers": { + "console": { + "level": "DEBUG", + "class": "logging.StreamHandler", + "formatter": "verbose", }, - 'file': { - 'level': 'INFO', - 'class': 'logging.FileHandler', - 'filename': LOG_DIR / 'django.log', - 'formatter': 'verbose' + "file": { + "level": "INFO", + "class": "logging.FileHandler", + "filename": LOG_DIR / "django.log", + "formatter": "verbose", }, }, - 'loggers': { - 'django': { - 'handlers': ['console', 'file'], - 'level': 'INFO', - 'propagate': True - }, - 'rooms': { - 'handlers': ['console', 'file'], - 'level': 'DEBUG', - 'propagate': False - } + "loggers": { + "django": {"handlers": ["console", "file"], "level": "INFO", "propagate": True}, + "rooms": {"handlers": ["console", "file"], "level": "DEBUG", "propagate": False}, }, }