@re-shell/cli
Version:
Full-stack development platform uniting microservices and microfrontends. Build complete applications with .NET (ASP.NET Core Web API, Minimal API), Java (Spring Boot, Quarkus, Micronaut, Vert.x), Rust (Actix-Web, Warp, Rocket, Axum), Python (FastAPI, Dja
1,468 lines (1,236 loc) • 39 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.djangoTemplate = void 0;
exports.djangoTemplate = {
id: 'django',
name: 'django',
displayName: 'Django',
description: 'Python\'s most popular web framework with batteries included',
language: 'python',
framework: 'django',
version: '5.0.1',
tags: ['python', 'django', 'rest-framework', 'orm', 'admin', 'batteries-included'],
port: 8000,
features: [
'Django REST Framework',
'PostgreSQL with Django ORM',
'JWT Authentication',
'Swagger/OpenAPI Documentation',
'Celery for Async Tasks',
'Redis Caching',
'Admin Interface',
'Email Backend',
'Static/Media Files',
'Docker Support'
],
dependencies: {
'django': '5.0.1',
'djangorestframework': '3.14.0',
'django-cors-headers': '4.3.1',
'djangorestframework-simplejwt': '5.3.1',
'drf-spectacular': '0.27.0',
'celery': '5.3.4',
'redis': '5.0.1',
'django-redis': '5.4.0',
'psycopg2-binary': '2.9.9',
'pillow': '10.2.0',
'django-environ': '0.11.2',
'gunicorn': '21.2.0',
'whitenoise': '6.6.0',
'django-debug-toolbar': '4.2.0',
'pytest': '7.4.4',
'pytest-django': '4.7.0',
'pytest-cov': '4.1.0',
'black': '23.12.1',
'flake8': '7.0.0',
'isort': '5.13.2',
'factory-boy': '3.3.0',
'faker': '22.0.0'
},
files: {
'manage.py': `#!/usr/bin/env python
"""Django's command-line utility for administrative tasks."""
import os
import sys
def main():
"""Run administrative tasks."""
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings')
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
raise ImportError(
"Couldn't import Django. Are you sure it's installed and "
"available on your PYTHONPATH environment variable? Did you "
"forget to activate a virtual environment?"
) from exc
execute_from_command_line(sys.argv)
if __name__ == '__main__':
main()
`,
'requirements.txt': `# Production dependencies
django==5.0.1
djangorestframework==3.14.0
django-cors-headers==4.3.1
djangorestframework-simplejwt==5.3.1
drf-spectacular==0.27.0
celery==5.3.4
redis==5.0.1
django-redis==5.4.0
psycopg2-binary==2.9.9
pillow==10.2.0
django-environ==0.11.2
gunicorn==21.2.0
whitenoise==6.6.0
`,
'requirements-dev.txt': `# Development dependencies
-r requirements.txt
django-debug-toolbar==4.2.0
pytest==7.4.4
pytest-django==4.7.0
pytest-cov==4.1.0
black==23.12.1
flake8==7.0.0
isort==5.13.2
factory-boy==3.3.0
faker==22.0.0
`,
'.env.example': `# Django settings
DEBUG=True
SECRET_KEY=your-secret-key-here
ALLOWED_HOSTS=localhost,127.0.0.1
# Database
DATABASE_URL=postgres://postgres:password@localhost:5432/{{service_name}}
# Redis
REDIS_URL=redis://localhost:6379/0
# Celery
CELERY_BROKER_URL=redis://localhost:6379/1
CELERY_RESULT_BACKEND=redis://localhost:6379/2
# Email
EMAIL_HOST=localhost
EMAIL_PORT=1025
EMAIL_USE_TLS=False
DEFAULT_FROM_EMAIL=noreply@example.com
# CORS
CORS_ALLOWED_ORIGINS=http://localhost:3000,http://localhost:3001
# JWT
ACCESS_TOKEN_LIFETIME_MINUTES=60
REFRESH_TOKEN_LIFETIME_DAYS=7
`,
'pytest.ini': `[tool:pytest]
DJANGO_SETTINGS_MODULE = config.settings.test
python_files = tests.py test_*.py *_tests.py
addopts =
--verbose
--strict-markers
--tb=short
--cov=.
--cov-report=term-missing:skip-covered
--cov-report=html
--cov-report=xml
testpaths = tests
`,
'setup.cfg': `[flake8]
max-line-length = 88
extend-ignore = E203, W503
exclude =
.git,
__pycache__,
migrations,
.venv,
venv
[isort]
profile = black
known_django = django
sections = FUTURE,STDLIB,DJANGO,THIRDPARTY,FIRSTPARTY,LOCALFOLDER
`,
'config/__init__.py': '',
'config/settings/__init__.py': `from .base import * # noqa
# Load environment-specific settings
import os
env = os.environ.get('DJANGO_ENV', 'development')
if env == 'production':
from .production import * # noqa
elif env == 'test':
from .test import * # noqa
else:
from .development import * # noqa
`,
'config/settings/base.py': `"""
Django base settings for {{service_name}} project.
"""
import os
from datetime import timedelta
from pathlib import Path
import environ
# Build paths inside the project
BASE_DIR = Path(__file__).resolve().parent.parent.parent
# Environment variables
env = environ.Env(
DEBUG=(bool, False),
ALLOWED_HOSTS=(list, ['localhost', '127.0.0.1']),
CORS_ALLOWED_ORIGINS=(list, []),
)
environ.Env.read_env(os.path.join(BASE_DIR, '.env'))
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = env('SECRET_KEY')
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = env('DEBUG')
ALLOWED_HOSTS = env('ALLOWED_HOSTS')
# Application definition
DJANGO_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
THIRD_PARTY_APPS = [
'rest_framework',
'rest_framework_simplejwt',
'corsheaders',
'drf_spectacular',
'django_redis',
]
LOCAL_APPS = [
'apps.users',
'apps.api',
]
INSTALLED_APPS = DJANGO_APPS + THIRD_PARTY_APPS + LOCAL_APPS
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'corsheaders.middleware.CorsMiddleware',
'whitenoise.middleware.WhiteNoiseMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
ROOT_URLCONF = 'config.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [BASE_DIR / 'templates'],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = 'config.wsgi.application'
# Database
DATABASES = {
'default': env.db(),
}
# Password validation
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
# Internationalization
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
STATIC_URL = 'static/'
STATIC_ROOT = BASE_DIR / 'staticfiles'
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
# Media files
MEDIA_URL = 'media/'
MEDIA_ROOT = BASE_DIR / 'media'
# Default primary key field type
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
# Custom user model
AUTH_USER_MODEL = 'users.User'
# REST Framework
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework_simplejwt.authentication.JWTAuthentication',
),
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
],
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 20,
'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema',
'DEFAULT_FILTER_BACKENDS': [
'rest_framework.filters.SearchFilter',
'rest_framework.filters.OrderingFilter',
],
}
# JWT Settings
SIMPLE_JWT = {
'ACCESS_TOKEN_LIFETIME': timedelta(minutes=env.int('ACCESS_TOKEN_LIFETIME_MINUTES', 60)),
'REFRESH_TOKEN_LIFETIME': timedelta(days=env.int('REFRESH_TOKEN_LIFETIME_DAYS', 7)),
'ROTATE_REFRESH_TOKENS': True,
'BLACKLIST_AFTER_ROTATION': True,
'UPDATE_LAST_LOGIN': True,
'ALGORITHM': 'HS256',
'SIGNING_KEY': SECRET_KEY,
'AUTH_HEADER_TYPES': ('Bearer',),
'AUTH_HEADER_NAME': 'HTTP_AUTHORIZATION',
'USER_ID_FIELD': 'id',
'USER_ID_CLAIM': 'user_id',
'USER_AUTHENTICATION_RULE': 'rest_framework_simplejwt.authentication.default_user_authentication_rule',
'AUTH_TOKEN_CLASSES': ('rest_framework_simplejwt.tokens.AccessToken',),
'TOKEN_TYPE_CLAIM': 'token_type',
'JTI_CLAIM': 'jti',
}
# CORS
CORS_ALLOWED_ORIGINS = env('CORS_ALLOWED_ORIGINS')
CORS_ALLOW_CREDENTIALS = True
# Celery Configuration
CELERY_BROKER_URL = env('CELERY_BROKER_URL', default='redis://localhost:6379/1')
CELERY_RESULT_BACKEND = env('CELERY_RESULT_BACKEND', default='redis://localhost:6379/2')
CELERY_ACCEPT_CONTENT = ['json']
CELERY_TASK_SERIALIZER = 'json'
CELERY_RESULT_SERIALIZER = 'json'
CELERY_TIMEZONE = TIME_ZONE
CELERY_BEAT_SCHEDULER = 'django_celery_beat.schedulers:DatabaseScheduler'
# Cache
CACHES = {
'default': {
'BACKEND': 'django_redis.cache.RedisCache',
'LOCATION': env('REDIS_URL', default='redis://localhost:6379/0'),
'OPTIONS': {
'CLIENT_CLASS': 'django_redis.client.DefaultClient',
}
}
}
# Email
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = env('EMAIL_HOST', default='localhost')
EMAIL_PORT = env.int('EMAIL_PORT', default=1025)
EMAIL_USE_TLS = env.bool('EMAIL_USE_TLS', default=False)
EMAIL_HOST_USER = env('EMAIL_HOST_USER', default='')
EMAIL_HOST_PASSWORD = env('EMAIL_HOST_PASSWORD', default='')
DEFAULT_FROM_EMAIL = env('DEFAULT_FROM_EMAIL', default='noreply@example.com')
# Spectacular Settings
SPECTACULAR_SETTINGS = {
'TITLE': '{{service_name}} API',
'DESCRIPTION': 'API documentation for {{service_name}}',
'VERSION': '1.0.0',
'SERVE_INCLUDE_SCHEMA': False,
'SWAGGER_UI_SETTINGS': {
'deepLinking': True,
'persistAuthorization': True,
'displayOperationId': True,
},
'COMPONENT_SPLIT_REQUEST': True,
'SCHEMA_PATH_PREFIX': '/api/v1',
}
# Logging
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'verbose': {
'format': '{levelname} {asctime} {module} {process:d} {thread:d} {message}',
'style': '{',
},
},
'handlers': {
'console': {
'class': 'logging.StreamHandler',
'formatter': 'verbose',
},
},
'root': {
'handlers': ['console'],
'level': 'INFO',
},
}
`,
'config/settings/development.py': `"""
Development settings
"""
from .base import * # noqa
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
# Django Debug Toolbar
INSTALLED_APPS += ['debug_toolbar'] # noqa
MIDDLEWARE.insert(0, 'debug_toolbar.middleware.DebugToolbarMiddleware') # noqa
# Debug toolbar config
INTERNAL_IPS = [
'127.0.0.1',
'localhost',
]
# Email backend for development
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
# Disable caching in development
CACHES = {
'default': {
'BACKEND': 'django.core.backends.dummy.DummyCache',
}
}
# Allow all origins in development
CORS_ALLOW_ALL_ORIGINS = True
`,
'config/settings/production.py': `"""
Production settings
"""
from .base import * # noqa
# Security
DEBUG = False
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
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_HSTS_PRELOAD = True
# Use production email backend
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
# Sentry error tracking
import sentry_sdk
from sentry_sdk.integrations.django import DjangoIntegration
sentry_sdk.init(
dsn=env('SENTRY_DSN'),
integrations=[DjangoIntegration()],
traces_sample_rate=0.1,
send_default_pii=True
)
`,
'config/settings/test.py': `"""
Test settings
"""
from .base import * # noqa
# Use in-memory database for tests
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': ':memory:',
}
}
# Disable migrations during tests
class DisableMigrations:
def __contains__(self, item):
return True
def __getitem__(self, item):
return None
MIGRATION_MODULES = DisableMigrations()
# Use dummy cache
CACHES = {
'default': {
'BACKEND': 'django.core.backends.dummy.DummyCache',
}
}
# Disable Celery during tests
CELERY_TASK_ALWAYS_EAGER = True
CELERY_TASK_EAGER_PROPAGATES = True
# Speed up password hashing
PASSWORD_HASHERS = [
'django.contrib.auth.hashers.MD5PasswordHasher',
]
# Email backend
EMAIL_BACKEND = 'django.core.mail.backends.locmem.EmailBackend'
`,
'config/urls.py': `"""
URL Configuration for {{service_name}}
"""
from django.conf import settings
from django.conf.urls.static import static
from django.contrib import admin
from django.urls import include, path
from drf_spectacular.views import (
SpectacularAPIView,
SpectacularRedocView,
SpectacularSwaggerView,
)
urlpatterns = [
# Admin
path('admin/', admin.site.urls),
# API
path('api/v1/', include('apps.api.urls')),
# API Documentation
path('api/schema/', SpectacularAPIView.as_view(), name='schema'),
path('api/swagger/', SpectacularSwaggerView.as_view(url_name='schema'), name='swagger-ui'),
path('api/redoc/', SpectacularRedocView.as_view(url_name='schema'), name='redoc'),
]
# Serve media files in development
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
# Debug toolbar
if 'debug_toolbar' in settings.INSTALLED_APPS:
import debug_toolbar
urlpatterns = [
path('__debug__/', include(debug_toolbar.urls)),
] + urlpatterns
`,
'config/wsgi.py': `"""
WSGI config for {{service_name}} project.
"""
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings')
application = get_wsgi_application()
`,
'config/asgi.py': `"""
ASGI config for {{service_name}} project.
"""
import os
from django.core.asgi import get_asgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings')
application = get_asgi_application()
`,
'config/celery.py': `"""
Celery configuration for {{service_name}}
"""
import os
from celery import Celery
# Set default Django settings
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings')
# Create Celery app
app = Celery('{{service_name}}')
# Load configuration from Django settings
app.config_from_object('django.conf:settings', namespace='CELERY')
# Auto-discover tasks from all registered Django apps
app.autodiscover_tasks()
`,
'config/celery_init.py': `# This will make sure the app is always imported when
# Django starts so that shared_task will use this app.
from .celery import app as celery_app
__all__ = ('celery_app',)
`,
'apps/__init__.py': '',
'apps/users/__init__.py': '',
'apps/users/apps.py': `from django.apps import AppConfig
class UsersConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'apps.users'
verbose_name = 'Users'
`,
'apps/users/models.py': `from django.contrib.auth.models import AbstractUser
from django.db import models
class User(AbstractUser):
"""
Custom User model
"""
email = models.EmailField(unique=True)
bio = models.TextField(blank=True)
avatar = models.ImageField(upload_to='avatars/', blank=True, null=True)
phone_number = models.CharField(max_length=20, blank=True)
date_of_birth = models.DateField(blank=True, null=True)
is_verified = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['username']
class Meta:
verbose_name = 'User'
verbose_name_plural = 'Users'
ordering = ['-created_at']
def __str__(self):
return self.email
`,
'apps/users/admin.py': `from django.contrib import admin
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from .models import User
class UserAdmin(BaseUserAdmin):
list_display = ['email', 'username', 'first_name', 'last_name', 'is_active', 'is_staff']
list_filter = ['is_active', 'is_staff', 'is_superuser', 'is_verified']
search_fields = ['email', 'username', 'first_name', 'last_name']
ordering = ['-created_at']
fieldsets = BaseUserAdmin.fieldsets + (
('Additional Info', {
'fields': ('bio', 'avatar', 'phone_number', 'date_of_birth', 'is_verified')
}),
)
add_fieldsets = BaseUserAdmin.add_fieldsets + (
('Additional Info', {
'fields': ('email', 'bio', 'avatar', 'phone_number', 'date_of_birth')
}),
)
`,
'apps/users/serializers.py': `from django.contrib.auth import get_user_model
from rest_framework import serializers
User = get_user_model()
class UserSerializer(serializers.ModelSerializer):
"""
User serializer
"""
class Meta:
model = User
fields = [
'id', 'username', 'email', 'first_name', 'last_name',
'bio', 'avatar', 'phone_number', 'date_of_birth',
'is_verified', 'created_at', 'updated_at'
]
read_only_fields = ['id', 'created_at', 'updated_at', 'is_verified']
class UserCreateSerializer(serializers.ModelSerializer):
"""
User registration serializer
"""
password = serializers.CharField(write_only=True, min_length=8)
password_confirm = serializers.CharField(write_only=True)
class Meta:
model = User
fields = ['username', 'email', 'password', 'password_confirm', 'first_name', 'last_name']
def validate(self, attrs):
if attrs['password'] != attrs['password_confirm']:
raise serializers.ValidationError("Passwords don't match")
return attrs
def create(self, validated_data):
validated_data.pop('password_confirm')
return User.objects.create_user(**validated_data)
class ChangePasswordSerializer(serializers.Serializer):
"""
Serializer for password change
"""
old_password = serializers.CharField(required=True)
new_password = serializers.CharField(required=True, min_length=8)
def validate_old_password(self, value):
user = self.context['request'].user
if not user.check_password(value):
raise serializers.ValidationError('Invalid password')
return value
`,
'apps/users/views.py': `from django.contrib.auth import get_user_model
from rest_framework import generics, permissions, status
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework.viewsets import ModelViewSet
from .serializers import (
ChangePasswordSerializer,
UserCreateSerializer,
UserSerializer,
)
User = get_user_model()
class UserViewSet(ModelViewSet):
"""
User viewset
"""
queryset = User.objects.all()
serializer_class = UserSerializer
permission_classes = [permissions.IsAuthenticated]
def get_serializer_class(self):
if self.action == 'create':
return UserCreateSerializer
return super().get_serializer_class()
def get_permissions(self):
if self.action == 'create':
return [permissions.AllowAny()]
return super().get_permissions()
def me(self, request):
"""Get current user"""
serializer = self.get_serializer(request.user)
return Response(serializer.data)
def change_password(self, request):
"""Change password"""
serializer = ChangePasswordSerializer(data=request.data, context={'request': request})
serializer.is_valid(raise_exception=True)
user = request.user
user.set_password(serializer.validated_data['new_password'])
user.save()
return Response({'detail': 'Password changed successfully'}, status=status.HTTP_200_OK)
`,
'apps/users/urls.py': `from django.urls import include, path
from rest_framework.routers import DefaultRouter
from .views import UserViewSet
router = DefaultRouter()
router.register('users', UserViewSet)
urlpatterns = [
path('', include(router.urls)),
]
`,
'apps/users/migrations/__init__.py': '',
'apps/users/tests/__init__.py': '',
'apps/users/tests/test_models.py': `import pytest
from django.contrib.auth import get_user_model
User = get_user_model()
class TestUserModel:
def test_create_user(self):
user = User.objects.create_user(
username='testuser',
email='test@example.com',
password='testpass123'
)
assert user.username == 'testuser'
assert user.email == 'test@example.com'
assert user.check_password('testpass123')
assert not user.is_staff
assert not user.is_superuser
def test_create_superuser(self):
user = User.objects.create_superuser(
username='admin',
email='admin@example.com',
password='adminpass123'
)
assert user.is_staff
assert user.is_superuser
def test_str_representation(self):
user = User(email='user@example.com')
assert str(user) == 'user@example.com'
`,
'apps/users/tests/test_views.py': `import pytest
from django.contrib.auth import get_user_model
from django.urls import reverse
from rest_framework import status
from rest_framework.test import APIClient
User = get_user_model()
class TestUserViews:
def api_client(self):
return APIClient()
def user(self):
return User.objects.create_user(
username='testuser',
email='test@example.com',
password='testpass123'
)
def test_register_user(self, api_client):
url = reverse('user-list')
data = {
'username': 'newuser',
'email': 'new@example.com',
'password': 'newpass123',
'password_confirm': 'newpass123',
'first_name': 'New',
'last_name': 'User'
}
response = api_client.post(url, data, format='json')
assert response.status_code == status.HTTP_201_CREATED
assert User.objects.filter(email='new@example.com').exists()
def test_get_current_user(self, api_client, user):
api_client.force_authenticate(user=user)
url = reverse('user-me')
response = api_client.get(url)
assert response.status_code == status.HTTP_200_OK
assert response.data['email'] == user.email
def test_change_password(self, api_client, user):
api_client.force_authenticate(user=user)
url = reverse('user-change-password')
data = {
'old_password': 'testpass123',
'new_password': 'newpass123'
}
response = api_client.post(url, data, format='json')
assert response.status_code == status.HTTP_200_OK
user.refresh_from_db()
assert user.check_password('newpass123')
`,
'apps/api/__init__.py': '',
'apps/api/apps.py': `from django.apps import AppConfig
class ApiConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'apps.api'
verbose_name = 'API'
`,
'apps/api/urls.py': `from django.urls import include, path
from rest_framework_simplejwt.views import (
TokenObtainPairView,
TokenRefreshView,
TokenVerifyView,
)
from .views import HealthCheckView
urlpatterns = [
# Health check
path('health/', HealthCheckView.as_view(), name='health-check'),
# Authentication
path('auth/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
path('auth/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
path('auth/token/verify/', TokenVerifyView.as_view(), name='token_verify'),
# Apps
path('', include('apps.users.urls')),
]
`,
'apps/api/views.py': `from django.db import connection
from django.core.cache import cache
from rest_framework import status
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework.permissions import AllowAny
import redis
from django.conf import settings
class HealthCheckView(APIView):
"""
Health check endpoint
"""
permission_classes = [AllowAny]
def get(self, request):
health_status = {
'status': 'healthy',
'services': {}
}
# Check database
try:
with connection.cursor() as cursor:
cursor.execute("SELECT 1")
health_status['services']['database'] = 'healthy'
except Exception as e:
health_status['services']['database'] = f'unhealthy: {str(e)}'
health_status['status'] = 'unhealthy'
# Check cache/Redis
try:
cache.set('health_check', 'ok', 1)
if cache.get('health_check') == 'ok':
health_status['services']['cache'] = 'healthy'
else:
health_status['services']['cache'] = 'unhealthy'
health_status['status'] = 'unhealthy'
except Exception as e:
health_status['services']['cache'] = f'unhealthy: {str(e)}'
health_status['status'] = 'unhealthy'
# Check Redis directly for Celery
try:
r = redis.from_url(settings.CELERY_BROKER_URL)
r.ping()
health_status['services']['celery_broker'] = 'healthy'
except Exception as e:
health_status['services']['celery_broker'] = f'unhealthy: {str(e)}'
health_status['status'] = 'unhealthy'
status_code = status.HTTP_200_OK if health_status['status'] == 'healthy' else status.HTTP_503_SERVICE_UNAVAILABLE
return Response(health_status, status=status_code)
`,
'apps/api/pagination.py': `from rest_framework.pagination import PageNumberPagination
class StandardResultsSetPagination(PageNumberPagination):
page_size = 20
page_size_query_param = 'page_size'
max_page_size = 100
class LargeResultsSetPagination(PageNumberPagination):
page_size = 100
page_size_query_param = 'page_size'
max_page_size = 1000
`,
'apps/api/permissions.py': `from rest_framework import permissions
class IsOwnerOrReadOnly(permissions.BasePermission):
"""
Object-level permission to only allow owners of an object to edit it.
"""
def has_object_permission(self, request, view, obj):
# Read permissions are allowed to any request
if request.method in permissions.SAFE_METHODS:
return True
# Write permissions are only allowed to the owner
return obj.owner == request.user
class IsOwner(permissions.BasePermission):
"""
Object-level permission to only allow owners of an object to view/edit it.
"""
def has_object_permission(self, request, view, obj):
return obj.owner == request.user
`,
'apps/api/exceptions.py': `from rest_framework.views import exception_handler
from rest_framework.exceptions import ValidationError
import logging
logger = logging.getLogger(__name__)
def custom_exception_handler(exc, context):
"""
Custom exception handler that logs errors
"""
response = exception_handler(exc, context)
if response is not None:
# Log the error
logger.error(
f"API Error: {exc.__class__.__name__} - {str(exc)}",
extra={
'status_code': response.status_code,
'request_path': context['request'].path,
'request_method': context['request'].method,
'user': str(context['request'].user) if context['request'].user.is_authenticated else 'Anonymous'
}
)
# Customize error format
if isinstance(exc, ValidationError) and isinstance(response.data, dict):
errors = []
for field, messages in response.data.items():
if isinstance(messages, list):
for message in messages:
errors.append({
'field': field,
'message': str(message)
})
else:
errors.append({
'field': field,
'message': str(messages)
})
response.data = {
'error': 'Validation failed',
'errors': errors
}
return response
`,
'apps/api/middleware.py': `import time
import uuid
from django.utils.deprecation import MiddlewareMixin
import logging
logger = logging.getLogger(__name__)
class RequestIdMiddleware(MiddlewareMixin):
"""
Add a unique request ID to each request
"""
def process_request(self, request):
request.id = request.META.get('HTTP_X_REQUEST_ID', str(uuid.uuid4()))
request.META['HTTP_X_REQUEST_ID'] = request.id
def process_response(self, request, response):
if hasattr(request, 'id'):
response['X-Request-ID'] = request.id
return response
class RequestLoggingMiddleware(MiddlewareMixin):
"""
Log all API requests
"""
def process_request(self, request):
request.start_time = time.time()
def process_response(self, request, response):
if hasattr(request, 'start_time'):
duration = time.time() - request.start_time
logger.info(
f"{request.method} {request.path} - {response.status_code}",
extra={
'request_id': getattr(request, 'id', None),
'method': request.method,
'path': request.path,
'status_code': response.status_code,
'duration': round(duration * 1000, 2), # in milliseconds
'user': str(request.user) if request.user.is_authenticated else 'Anonymous',
'ip': self.get_client_ip(request)
}
)
return response
def get_client_ip(self, request):
x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
if x_forwarded_for:
ip = x_forwarded_for.split(',')[0]
else:
ip = request.META.get('REMOTE_ADDR')
return ip
`,
'apps/api/migrations/__init__.py': '',
'apps/api/tests/__init__.py': '',
'apps/api/tests/test_api.py': `import pytest
from django.urls import reverse
from rest_framework import status
from rest_framework.test import APIClient
class TestHealthCheck:
def test_health_check(self):
client = APIClient()
url = reverse('health-check')
response = client.get(url)
assert response.status_code == status.HTTP_200_OK
assert response.data['status'] in ['healthy', 'unhealthy']
assert 'services' in response.data
`,
'tests/__init__.py': '',
'tests/conftest.py': `import pytest
from django.contrib.auth import get_user_model
from rest_framework.test import APIClient
User = get_user_model()
def api_client():
return APIClient()
def user():
return User.objects.create_user(
username='testuser',
email='test@example.com',
password='testpass123'
)
def authenticated_client(api_client, user):
api_client.force_authenticate(user=user)
return api_client
def admin_user():
return User.objects.create_superuser(
username='admin',
email='admin@example.com',
password='adminpass123'
)
def admin_client(api_client, admin_user):
api_client.force_authenticate(user=admin_user)
return api_client
`,
'tests/test_integration.py': `import pytest
from django.urls import reverse
from rest_framework import status
class TestUserFlow:
def test_complete_user_flow(self, api_client):
# Register
register_url = reverse('user-list')
register_data = {
'username': 'newuser',
'email': 'newuser@example.com',
'password': 'newpass123',
'password_confirm': 'newpass123'
}
response = api_client.post(register_url, register_data, format='json')
assert response.status_code == status.HTTP_201_CREATED
# Login
login_url = reverse('token_obtain_pair')
login_data = {
'email': 'newuser@example.com',
'password': 'newpass123'
}
response = api_client.post(login_url, login_data, format='json')
assert response.status_code == status.HTTP_200_OK
access_token = response.data['access']
# Get profile
api_client.credentials(HTTP_AUTHORIZATION=f'Bearer {access_token}')
profile_url = reverse('user-me')
response = api_client.get(profile_url)
assert response.status_code == status.HTTP_200_OK
assert response.data['email'] == 'newuser@example.com'
`,
'Dockerfile': `FROM python:3.11-slim
# Set environment variables
ENV PYTHONDONTWRITEBYTECODE=1 \\
PYTHONUNBUFFERED=1 \\
POETRY_VERSION=1.7.1 \\
POETRY_HOME="/opt/poetry" \\
POETRY_VIRTUALENVS_CREATE=false
# Install system dependencies
RUN apt-get update \\
&& apt-get install -y --no-install-recommends \\
build-essential \\
libpq-dev \\
curl \\
&& rm -rf /var/lib/apt/lists/*
# Install Poetry
RUN curl -sSL https://install.python-poetry.org | python3 -
ENV PATH="$POETRY_HOME/bin:$PATH"
# Set work directory
WORKDIR /app
# Copy dependency files
COPY pyproject.toml poetry.lock* ./
# Install dependencies
RUN poetry install --no-interaction --no-ansi --no-root --only main
# Copy project
COPY . .
# Collect static files
RUN python manage.py collectstatic --noinput
# Run gunicorn
CMD ["gunicorn", "--bind", "0.0.0.0:8000", "--workers", "3", "config.wsgi:application"]
`,
'docker-compose.yml': `version: '3.8'
services:
web:
build: .
command: python manage.py runserver 0.0.0.0:8000
volumes:
- .:/app
ports:
- "8000:8000"
env_file:
- .env
depends_on:
- db
- redis
restart: unless-stopped
db:
image: postgres:15-alpine
volumes:
- postgres_data:/var/lib/postgresql/data
environment:
- POSTGRES_DB={{service_name}}
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=postgres
ports:
- "5432:5432"
restart: unless-stopped
redis:
image: redis:7-alpine
ports:
- "6379:6379"
restart: unless-stopped
celery:
build: .
command: celery -A config worker -l info
volumes:
- .:/app
env_file:
- .env
depends_on:
- db
- redis
restart: unless-stopped
celery-beat:
build: .
command: celery -A config beat -l info
volumes:
- .:/app
env_file:
- .env
depends_on:
- db
- redis
restart: unless-stopped
flower:
build: .
command: celery -A config flower
volumes:
- .:/app
env_file:
- .env
ports:
- "5555:5555"
depends_on:
- celery
restart: unless-stopped
volumes:
postgres_data:
`,
'.gitignore': `# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
# Virtual Environment
venv/
ENV/
env/
.venv
# Django
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
media/
staticfiles/
# Environment variables
.env
.env.*
# IDE
.idea/
.vscode/
*.swp
*.swo
*~
.DS_Store
# Testing
.coverage
.pytest_cache/
htmlcov/
.tox/
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
# Celery
celerybeat-schedule
celerybeat.pid
# Migrations
# migrations/
# Production
*.pid
`,
'README.md': `# {{service_name}}
Django REST API with JWT authentication, Celery background tasks, and Redis caching.
## Features
- Django REST Framework
- JWT Authentication
- PostgreSQL database
- Redis caching
- Celery async tasks
- Swagger/ReDoc API documentation
- Docker support
- Comprehensive test suite
## Quick Start
1. Clone the repository
2. Copy \`.env.example\` to \`.env\` and update values
3. Run with Docker:
\`\`\`bash
docker-compose up
\`\`\`
4. Or run locally:
\`\`\`bash
python -m venv venv
source venv/bin/activate # On Windows: venv\\Scripts\\activate
pip install -r requirements.txt
python manage.py migrate
python manage.py createsuperuser
python manage.py runserver
\`\`\`
## API Documentation
- Swagger UI: http://localhost:8000/api/swagger/
- ReDoc: http://localhost:8000/api/redoc/
- Admin: http://localhost:8000/admin/
## Testing
Run tests:
\`\`\`bash
pytest
\`\`\`
With coverage:
\`\`\`bash
pytest --cov
\`\`\`
## Development
1. Install development dependencies:
\`\`\`bash
pip install -r requirements-dev.txt
\`\`\`
2. Run code formatting:
\`\`\`bash
black .
isort .
\`\`\`
3. Run linting:
\`\`\`bash
flake8
\`\`\`
## Deployment
1. Update environment variables
2. Collect static files: \`python manage.py collectstatic\`
3. Run migrations: \`python manage.py migrate\`
4. Start with gunicorn: \`gunicorn config.wsgi:application\`
## Project Structure
\`\`\`
backend/
├── apps/ # Django apps
├── config/ # Settings and configuration
├── tests/ # Test suite
├── manage.py # Django management script
└── docker-compose.yml
\`\`\`
## License
MIT License
`
}
};