🐛 fix(config): configure REST Framework settings and add JWT, Swagger, and Redoc views to urls

This commit is contained in:
sankalp committed 2025-06-15 19:19:03 +05:45
1 parent 163c628420
commit 603e37b588
6 files changed
+208 -10

No files matched your search

+21 -9
View File
@@ -2,6 +2,7 @@ import os
from decouple import config
from pathlib import Path
from .jazzmin import JAZZMIN_SETTINGS
from .rest_framework import REST_FRAMEWORK, SIMPLE_JWT, SPECTACULAR_SETTINGS
BASE_DIR = Path(__file__).resolve().parent.parent.parent
@@ -22,8 +23,10 @@ INSTALLED_APPS = [
"django.contrib.staticfiles",
# Third-party
"rest_framework",
'django_filters',
'corsheaders',
"rest_framework_simplejwt",
"django_filters",
"corsheaders",
"drf_spectacular",
# Local
"apps.accounts",
"apps.events",
@@ -40,7 +43,6 @@ INSTALLED_APPS = [
AUTH_USER_MODEL = "accounts.User"
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
@@ -52,7 +54,6 @@ MIDDLEWARE = [
"django.middleware.clickjacking.XFrameOptionsMiddleware",
]
ROOT_URLCONF = "config.urls"
TEMPLATES = [
@@ -97,22 +98,21 @@ AUTH_PASSWORD_VALIDATORS = [
},
]
# Internationalization
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'Asia/Kathmandu'
USE_I18N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
STATIC_URL = "/static/"
STATICFILES_DIRS = [BASE_DIR / "static"]
MEDIA_URL = "/media/"
MEDIA_ROOT = BASE_DIR / "media"
REST_FRAMEWORK = {"DEFAULT_SCHEMA_CLASS": "rest_framework.schemas.coreapi.AutoSchema"}
# REST Framework configuration is imported from rest_framework.py
# Default primary key field type
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
# CORS Configuration
@@ -144,3 +144,15 @@ CORS_ALLOW_HEADERS = [
"x-csrftoken",
"x-requested-with",
]
# Security Settings
if not DEBUG:
SECURE_SSL_REDIRECT = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
SECURE_BROWSER_XSS_FILTER = True
SECURE_CONTENT_TYPE_NOSNIFF = True
X_FRAME_OPTIONS = 'DENY'
SECURE_HSTS_SECONDS = 31536000 # 1 year
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_HSTS_PRELOAD = True
+120
View File
@@ -0,0 +1,120 @@
"""
REST Framework configuration settings
"""
from datetime import timedelta
REST_FRAMEWORK = {
# Use Django's standard `django.contrib.auth` permissions,
# or allow read-only access for unauthenticated users.
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
],
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework_simplejwt.authentication.JWTAuthentication',
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.BasicAuthentication',
],
# Pagination settings
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 10,
# Filtering
'DEFAULT_FILTER_BACKENDS': [
'django_filters.rest_framework.DjangoFilterBackend',
'rest_framework.filters.SearchFilter',
'rest_framework.filters.OrderingFilter',
],
# Throttling
'DEFAULT_THROTTLE_CLASSES': [
'rest_framework.throttling.AnonRateThrottle',
'rest_framework.throttling.UserRateThrottle'
],
'DEFAULT_THROTTLE_RATES': {
'anon': '100/day',
'user': '1000/day'
},
# Versioning
'DEFAULT_VERSIONING_CLASS': 'rest_framework.versioning.URLPathVersioning',
'DEFAULT_VERSION': 'v1',
'ALLOWED_VERSIONS': ['v1'],
'VERSION_PARAM': 'version',
# Schema
'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema',
# Renderer/Parser settings
'DEFAULT_RENDERER_CLASSES': [
'rest_framework.renderers.JSONRenderer',
'rest_framework.renderers.BrowsableAPIRenderer',
],
'DEFAULT_PARSER_CLASSES': [
'rest_framework.parsers.JSONParser',
'rest_framework.parsers.FormParser',
'rest_framework.parsers.MultiPartParser'
],
# Exception handling
'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler',
# Content negotiation
'DEFAULT_CONTENT_NEGOTIATION_CLASS': 'rest_framework.negotiation.DefaultContentNegotiation',
# Metadata
'DEFAULT_METADATA_CLASS': 'rest_framework.metadata.SimpleMetadata',
# Caching
'DEFAULT_CACHE_RESPONSE_TIMEOUT': 60 * 15, # 15 minutes
# Test settings
'TEST_REQUEST_DEFAULT_FORMAT': 'json',
'TEST_REQUEST_RENDERER_CLASSES': [
'rest_framework.renderers.JSONRenderer',
],
}
# JWT Settings
SIMPLE_JWT = {
'ACCESS_TOKEN_LIFETIME': timedelta(minutes=60),
'REFRESH_TOKEN_LIFETIME': timedelta(days=1),
'ROTATE_REFRESH_TOKENS': False,
'BLACKLIST_AFTER_ROTATION': True,
'UPDATE_LAST_LOGIN': False,
'ALGORITHM': 'HS256',
'SIGNING_KEY': None, # Will use Django's SECRET_KEY
'VERIFYING_KEY': None,
'AUDIENCE': None,
'ISSUER': None,
'AUTH_HEADER_TYPES': ('Bearer',),
'AUTH_HEADER_NAME': 'HTTP_AUTHORIZATION',
'USER_ID_FIELD': 'id',
'USER_ID_CLAIM': 'user_id',
'AUTH_TOKEN_CLASSES': ('rest_framework_simplejwt.tokens.AccessToken',),
'TOKEN_TYPE_CLAIM': 'token_type',
'JTI_CLAIM': 'jti',
'SLIDING_TOKEN_REFRESH_EXP_CLAIM': 'refresh_exp',
'SLIDING_TOKEN_LIFETIME': timedelta(minutes=5),
'SLIDING_TOKEN_REFRESH_LIFETIME': timedelta(days=1),
}
# Spectacular API settings
SPECTACULAR_SETTINGS = {
'TITLE': 'AlumniVerse API',
'DESCRIPTION': 'API documentation for AlumniVerse platform',
'VERSION': '1.0.0',
'SERVE_INCLUDE_SCHEMA': False,
'COMPONENT_SPLIT_REQUEST': True,
'SWAGGER_UI_SETTINGS': {
'deepLinking': True,
'persistAuthorization': True,
'displayOperationId': True,
},
'SWAGGER_UI_DIST': 'SIDECAR',
'SWAGGER_UI_FAVICON_HREF': 'SIDECAR',
'REDOC_DIST': 'SIDECAR',
'PREPROCESSING_HOOKS': [],
'SERVE_PERMISSIONS': ['rest_framework.permissions.IsAuthenticated'],
'SERVE_AUTHENTICATION': ['rest_framework.authentication.SessionAuthentication'],
'SWAGGER_UI_SETTINGS': {
'deepLinking': True,
'persistAuthorization': True,
'displayOperationId': True,
},
}
+40 -1
View File
@@ -15,8 +15,47 @@ Including another URLconf
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static
from rest_framework_simplejwt.views import (
TokenObtainPairView,
TokenRefreshView,
TokenVerifyView,
)
from drf_spectacular.views import (
SpectacularAPIView,
SpectacularRedocView,
SpectacularSwaggerView,
)
urlpatterns = [
path('admin/', admin.site.urls),
# API Authentication
path('api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
path('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
path('api/token/verify/', TokenVerifyView.as_view(), name='token_verify'),
# API Documentation
path('api/schema/', SpectacularAPIView.as_view(), name='schema'),
path('api/schema/swagger-ui/', SpectacularSwaggerView.as_view(url_name='schema'), name='swagger-ui'),
path('api/schema/redoc/', SpectacularRedocView.as_view(url_name='schema'), name='redoc'),
# API Apps
path('api/accounts/', include('apps.accounts.urls')),
path('api/events/', include('apps.events.urls')),
path('api/news/', include('apps.news.urls')),
path('api/jobs/', include('apps.jobs.urls')),
path('api/forum/', include('apps.forum.urls')),
path('api/mentorship/', include('apps.mentorship.urls')),
path('api/achievements/', include('apps.achievements.urls')),
path('api/groups/', include('apps.groups.urls')),
path('api/messaging/', include('apps.messaging.urls')),
path('api/notifications/', include('apps.notifications.urls')),
path('api/dashboard/', include('apps.dashboard.urls')),
]
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
+1
View File
@@ -10,6 +10,7 @@ dependencies = [
"django-filter>=25.1",
"django-jazzmin>=3.0.1",
"djangorestframework>=3.16.0",
"djangorestframework-simplejwt>=5.5.0",
"drf-spectacular>=0.28.0",
"pillow>=11.2.1",
"python-decouple>=3.8",
+1
View File
@@ -5,6 +5,7 @@ django-cors-headers==4.7.0
django-filter==25.1
django-jazzmin==3.0.1
djangorestframework==3.16.0
djangorestframework-simplejwt==5.3.1
drf-spectacular==0.28.0
inflection==0.5.1
jsonschema==4.24.0
Generated
+25
View File
@@ -12,6 +12,7 @@ dependencies = [
{ name = "django-filter" },
{ name = "django-jazzmin" },
{ name = "djangorestframework" },
{ name = "djangorestframework-simplejwt" },
{ name = "drf-spectacular" },
{ name = "pillow" },
{ name = "python-decouple" },
@@ -24,6 +25,7 @@ requires-dist = [
{ name = "django-filter", specifier = ">=25.1" },
{ name = "django-jazzmin", specifier = ">=3.0.1" },
{ name = "djangorestframework", specifier = ">=3.16.0" },
{ name = "djangorestframework-simplejwt", specifier = ">=5.5.0" },
{ name = "drf-spectacular", specifier = ">=0.28.0" },
{ name = "pillow", specifier = ">=11.2.1" },
{ name = "python-decouple", specifier = ">=3.8" },
@@ -110,6 +112,20 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/eb/3e/2448e93f4f87fc9a9f35e73e3c05669e0edd0c2526834686e949bb1fd303/djangorestframework-3.16.0-py3-none-any.whl", hash = "sha256:bea7e9f6b96a8584c5224bfb2e4348dfb3f8b5e34edbecb98da258e892089361", size = 1067305, upload-time = "2025-03-28T14:18:39.489Z" },
]
[[package]]
name = "djangorestframework-simplejwt"
version = "5.5.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "django" },
{ name = "djangorestframework" },
{ name = "pyjwt" },
]
sdist = { url = "https://files.pythonhosted.org/packages/db/1e/0d4439d0fa1d93599fbcfc56efdc02cbf012e3a4b4ef90c835e0a51017d4/djangorestframework_simplejwt-5.5.0.tar.gz", hash = "sha256:474a1b737067e6462b3609627a392d13a4da8a08b1f0574104ac6d7b1406f90e", size = 97946, upload-time = "2025-02-26T19:36:01.717Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/42/b4/d1c1750aa7c8cc07e4974275f96b9b9b3a38e95ff734e14b4e97790c8974/djangorestframework_simplejwt-5.5.0-py3-none-any.whl", hash = "sha256:4ef6b38af20cdde4a4a51d1fd8e063cbbabb7b45f149cc885d38d905c5a62edb", size = 103480, upload-time = "2025-02-26T19:36:29.04Z" },
]
[[package]]
name = "drf-spectacular"
version = "0.28.0"
@@ -204,6 +220,15 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/67/32/32dc030cfa91ca0fc52baebbba2e009bb001122a1daa8b6a79ad830b38d3/pillow-11.2.1-cp313-cp313t-win_arm64.whl", hash = "sha256:225c832a13326e34f212d2072982bb1adb210e0cc0b153e688743018c94a2681", size = 2417234, upload-time = "2025-04-12T17:49:08.399Z" },
]
[[package]]
name = "pyjwt"
version = "2.9.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/fb/68/ce067f09fca4abeca8771fe667d89cc347d1e99da3e093112ac329c6020e/pyjwt-2.9.0.tar.gz", hash = "sha256:7e1e5b56cc735432a7369cbfa0efe50fa113ebecdc04ae6922deba8b84582d0c", size = 78825, upload-time = "2024-08-01T15:01:08.445Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/79/84/0fdf9b18ba31d69877bd39c9cd6052b47f3761e9910c15de788e519f079f/PyJWT-2.9.0-py3-none-any.whl", hash = "sha256:3b02fb0f44517787776cf48f2ae25d8e14f300e6d7545a4315cee571a415e850", size = 22344, upload-time = "2024-08-01T15:01:06.481Z" },
]
[[package]]
name = "python-decouple"
version = "3.8"