feat(core): add core module with mixins, services, and background jobs

- Add Model Mixins: TimestampMixin, SoftDeleteMixin, AuditMixin, etc.
- Add Base Services: BaseService, BulkOperationsMixin, QueryOptimizerMixin
- Add Base ViewSets with bulk operations
- Add BackgroundJob model for Celery task tracking
- Add BaseAppCommand for management commands
- Add permissions, pagination, filters, cache, logging
- Migrate tests to factory_boy + faker
- Add CHANGELOG.md
- 297 tests passing
This commit is contained in:
2026-01-21 11:47:26 +01:00
parent 06b30fca02
commit f121445313
72 changed files with 9258 additions and 594 deletions

View File

@@ -147,12 +147,8 @@ class UserUpdateView(APIView):
serializer = UserUpdateSerializer(request.user, data=request.data, partial=True)
if serializer.is_valid():
user = UserService.update_user(request.user.id, **serializer.validated_data)
if user:
user_serializer = UserSerializer(user)
return Response(user_serializer.data)
return Response(
{"error": "Пользователь не найден"}, status=status.HTTP_404_NOT_FOUND
)
user_serializer = UserSerializer(user)
return Response(user_serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
@@ -163,7 +159,7 @@ class ProfileDetailView(generics.RetrieveUpdateAPIView):
serializer_class = ProfileUpdateSerializer
def get_object(self):
profile = ProfileService.get_profile_by_user_id(self.request.user.id)
profile = ProfileService.get_profile_by_user_id_or_none(self.request.user.id)
if not profile:
# Если профиль не существует, создаем его
from .models import Profile
@@ -206,11 +202,7 @@ class ProfileDetailView(generics.RetrieveUpdateAPIView):
updated_profile = ProfileService.update_profile(
request.user.id, **serializer.validated_data
)
if updated_profile:
return Response(ProfileUpdateSerializer(updated_profile).data)
return Response(
{"error": "Профиль не найден"}, status=status.HTTP_404_NOT_FOUND
)
return Response(ProfileUpdateSerializer(updated_profile).data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
@@ -259,9 +251,7 @@ class PasswordChangeView(APIView):
def user_profile_detail(request):
"""Получение полных данных профиля пользователя"""
profile_data = ProfileService.get_full_profile_data(request.user.id)
if profile_data:
return Response(profile_data)
return Response({"error": "Профиль не найден"}, status=status.HTTP_404_NOT_FOUND)
return Response(profile_data)
class TokenRefreshView(APIView):