refactor. pre-deploy

This commit is contained in:
2025-10-29 20:22:35 +09:00
parent 18497d4343
commit 367e1c932e
113 changed files with 8245 additions and 67 deletions

27
backend/Dockerfile Normal file
View File

@@ -0,0 +1,27 @@
FROM python:3.11-slim
WORKDIR /app
# Установка системных зависимостей
RUN apt-get update && apt-get install -y \
gcc \
postgresql-client \
&& rm -rf /var/lib/apt/lists/*
# Копирование и установка requirements
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Копирование кода приложения
COPY . .
# Создание директорий для статики и медиа
RUN mkdir -p staticfiles storage
# Копируем entrypoint скрипт
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
EXPOSE 8000
ENTRYPOINT ["/entrypoint.sh"]

View File

@@ -10,15 +10,24 @@ from .views import (
from rest_framework.routers import DefaultRouter
from drf_spectacular.views import SpectacularAPIView, SpectacularSwaggerView
router = DefaultRouter()
class NoTrailingSlashRouter(DefaultRouter):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.trailing_slash = '/?'
router = NoTrailingSlashRouter()
router.register('links', LinkViewSet, basename='link')
router.register('groups', LinkGroupViewSet, basename='group')
urlpatterns = [
path('auth/register/', RegisterView.as_view(), name='auth_register'),
path('auth/register', RegisterView.as_view(), name='auth_register_no_slash'),
path('auth/login/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
path('auth/login', TokenObtainPairView.as_view(), name='token_obtain_pair_no_slash'),
path('auth/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
path('auth/refresh', TokenRefreshView.as_view(), name='token_refresh_no_slash'),
path('auth/user/', UserProfileView.as_view(), name='user-profile'), # ← новый
path('auth/user', UserProfileView.as_view(), name='user-profile-no-slash'),
path('users/<str:username>/public/',
PublicUserGroupsView.as_view(),
name='public-user-groups'

View File

@@ -5,6 +5,8 @@ from rest_framework_simplejwt.views import TokenObtainPairView
from rest_framework.views import APIView
from rest_framework.response import Response
from django.shortcuts import get_object_or_404
from django.views.decorators.csrf import csrf_exempt
from django.utils.decorators import method_decorator
from drf_spectacular.utils import extend_schema, OpenApiParameter
from django.contrib.auth import get_user_model
@@ -25,6 +27,7 @@ class RegisterView(generics.CreateAPIView):
serializer_class = RegisterSerializer
@method_decorator(csrf_exempt, name='dispatch')
class LoginView(TokenObtainPairView):
permission_classes = [permissions.AllowAny]

View File

@@ -31,11 +31,30 @@ DEBUG = os.getenv('DJANGO_DEBUG', 'False') == 'True'
ALLOWED_HOSTS = os.getenv('DJANGO_ALLOWED_HOSTS', '127.0.0.1').split(',')
# Отключаем APPEND_SLASH для корректной работы API с Next.js proxy
APPEND_SLASH = False
CORS_ALLOWED_ORIGINS = [
"http://127.0.0.1:3000",
"http://localhost:3000",
"http://127.0.0.1:3001",
"http://localhost:3001",
]
CORS_ALLOW_ALL_ORIGINS = True # Для разработки
CORS_ALLOW_CREDENTIALS = True
CORS_ALLOW_HEADERS = [
'accept',
'accept-encoding',
'authorization',
'content-type',
'dnt',
'origin',
'user-agent',
'x-csrftoken',
'x-requested-with',
]
# Application definition
INSTALLED_APPS = [
@@ -60,6 +79,7 @@ INSTALLED_APPS = [
MIDDLEWARE = [
"corsheaders.middleware.CorsMiddleware",
'django.middleware.security.SecurityMiddleware',
'whitenoise.middleware.WhiteNoiseMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
@@ -88,13 +108,16 @@ TEMPLATES = [
WSGI_APPLICATION = 'backend.wsgi.application'
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework_simplejwt.authentication.JWTAuthentication',
),
'DEFAULT_PERMISSION_CLASSES': (
],
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticatedOrReadOnly',
),
],
'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema',
'DEFAULT_RENDERER_CLASSES': [
'rest_framework.renderers.JSONRenderer',
],
}
from datetime import timedelta
@@ -159,6 +182,10 @@ STATIC_ROOT = BASE_DIR / 'staticfiles'
# URL, по которому статика будет доступна
STATIC_URL = '/static/'
# WhiteNoise настройки
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
# Default primary key field type
# https://docs.djangoproject.com/en/5.2/ref/settings/#default-auto-field

Binary file not shown.

10
backend/entrypoint.sh Normal file
View File

@@ -0,0 +1,10 @@
#!/bin/bash
echo "Collecting static files..."
python3 manage.py collectstatic --noinput --clear
echo "Applying database migrations..."
python3 manage.py migrate --noinput
echo "Starting server..."
exec gunicorn backend.wsgi:application --bind 0.0.0.0:8000

12
backend/requirements.txt Normal file
View File

@@ -0,0 +1,12 @@
Django==5.2.*
djangorestframework
djangorestframework-simplejwt
psycopg2-binary
pillow
python-dotenv
django-cors-headers
django-extensions
drf-spectacular
drf-spectacular-sidecar
whitenoise
gunicorn