""" Django settings for proyecto project. Generated by 'django-admin startproject' using Django 6.0.1. For more information on this file, see https://docs.djangoproject.com/en/6.0/topics/settings/ For the full list of settings and their values, see https://docs.djangoproject.com/en/6.0/ref/settings/ """ import logging import os import sys from pathlib import Path import environ DEV_ENV = len(sys.argv) > 1 and sys.argv[1] == 'runserver' RUNNING_TESTS = any(arg in {'test', 'pytest'} for arg in sys.argv) or 'PYTEST_CURRENT_TEST' in os.environ # Build paths inside the project like this: BASE_DIR / 'subdir'. BASE_DIR = Path(__file__).resolve().parent.parent env = environ.Env( DEBUG=(bool, True), S3_ENABLE=(bool, False), S3_USE_LOCAL_URLS=(bool, False), POSTGRES_ENABLED=(bool, True), POSTGRES_PORT=(int, 5432), SMTP_PORT=(int, 587), AWS_S3_USE_SSL=(bool, True), AWS_QUERYSTRING_AUTH=(bool, False), ) env.read_env(BASE_DIR / '.env') # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/6.0/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! SECRET_KEY = env('SECRET_KEY', default='') # SECURITY WARNING: don't run with debug turned on in production! DEBUG = env.bool('DEBUG') S3_ENABLE = env.bool('S3_ENABLE') S3_USE_LOCAL_URLS = env.bool('S3_USE_LOCAL_URLS') ALLOWED_HOSTS = env.list('ALLOWED_HOSTS', default=[ 'localhost', '127.0.0.1', 'zkqpv8r3-8000.uks1.devtunnels.ms' ]) # Application definition INSTALLED_APPS = [ 'tienda.apps.TiendaConfig', 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'django.forms', 'compressor', 'ninja', ] if S3_ENABLE: INSTALLED_APPS.append('storages') MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', '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', ] if not S3_ENABLE: MIDDLEWARE.insert(1, 'whitenoise.middleware.WhiteNoiseMiddleware') ROOT_URLCONF = 'proyecto.urls' TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', 'tienda.context_processors.cart_context', ], }, }, ] WSGI_APPLICATION = 'proyecto.wsgi.application' # Database # https://docs.djangoproject.com/en/6.0/ref/settings/#databases # Usa PostgreSQL por defecto (POSTGRES_ENABLED=True); si no, SQLite. if RUNNING_TESTS or not env.bool('POSTGRES_ENABLED'): DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': BASE_DIR / 'db.sqlite3', } } else: DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql', 'NAME': env('POSTGRES_DB', default='tienda'), 'USER': env('POSTGRES_USER', default='postgres'), 'PASSWORD': env('POSTGRES_PASSWORD', default=''), 'HOST': env('POSTGRES_HOST', default='127.0.0.1'), 'PORT': env.int('POSTGRES_PORT'), } } # Password validation # https://docs.djangoproject.com/en/6.0/ref/settings/#auth-password-validators 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 # https://docs.djangoproject.com/en/6.0/topics/i18n/ LANGUAGE_CODE = 'en-us' TIME_ZONE = 'UTC' USE_I18N = True USE_TZ = True # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/6.0/howto/static-files/ STATIC_URL = 'static/' STATIC_ROOT = BASE_DIR / 'staticfiles' COMPRESS_ROOT = STATIC_ROOT COMPRESS_URL = STATIC_URL STATICFILES_DIRS = [ BASE_DIR / 'tienda' / 'static', ] STORAGES = { 'default': { 'BACKEND': 'django.core.files.storage.FileSystemStorage', }, 'staticfiles': { 'BACKEND': ( 'django.contrib.staticfiles.storage.StaticFilesStorage' if DEBUG else 'whitenoise.storage.CompressedManifestStaticFilesStorage' ), }, } if S3_ENABLE: AWS_STORAGE_BUCKET_NAME = env('AWS_STORAGE_BUCKET_NAME', default='') or None AWS_ACCESS_KEY_ID = env('AWS_ACCESS_KEY_ID', default=None) AWS_SECRET_ACCESS_KEY = env('AWS_SECRET_ACCESS_KEY', default=None) AWS_S3_REGION_NAME = env('AWS_S3_REGION_NAME', default=None) AWS_S3_ENDPOINT_URL = env('AWS_S3_ENDPOINT_URL', default=None) AWS_S3_CUSTOM_DOMAIN = env('AWS_S3_CUSTOM_DOMAIN', default=None) AWS_S3_USE_SSL = env.bool('AWS_S3_USE_SSL') AWS_QUERYSTRING_AUTH = env.bool('AWS_QUERYSTRING_AUTH') AWS_DEFAULT_ACL = env('AWS_DEFAULT_ACL', default='public-read') or None AWS_S3_OBJECT_PARAMETERS = {} STORAGES = { 'default': { 'BACKEND': 'tienda.storage_backends.MediaStorage', }, 'staticfiles': { 'BACKEND': 'tienda.storage_backends.StaticStorage', }, } STATICFILES_FINDERS = [ 'django.contrib.staticfiles.finders.FileSystemFinder', 'django.contrib.staticfiles.finders.AppDirectoriesFinder', 'compressor.finders.CompressorFinder' ] COMPRESS_PRECOMPILERS = () # Media files (User uploads) MEDIA_URL = 'media/' MEDIA_ROOT = Path(env('MEDIA_ROOT', default='/app/media')) # Redis Configuration CACHES = { 'default': { 'BACKEND': 'django_redis.cache.RedisCache', 'LOCATION': env('REDIS_URL', default='redis://127.0.0.1:6379/1'), 'OPTIONS': { 'CLIENT_CLASS': 'django_redis.client.DefaultClient', } } } # Session Configuration - Use Redis for session storage SESSION_ENGINE = 'django.contrib.sessions.backends.cache' SESSION_CACHE_ALIAS = 'default' # Configuración de mensajes para Bootstrap from django.contrib.messages import constants as messages MESSAGE_TAGS = { messages.DEBUG: 'debug', messages.INFO: 'info', messages.SUCCESS: 'success', messages.WARNING: 'warning', messages.ERROR: 'danger', } # Login URL LOGIN_URL = '/tienda/login/' STRIPE_PUBLISHABLE_KEY = env('STRIPE_PUBLISHABLE_KEY', default='') STRIPE_SECRET_KEY = env('STRIPE_SECRET_KEY', default='') # PayPal Configuration (Sandbox) # Para obtener credenciales: https://sandbox.paypal.com/ PAYPAL_CLIENT_ID = env('PAYPAL_CLIENT_ID', default='') # Reemplazar con tu Client ID de PayPal Sandbox PAYPAL_CLIENT_SECRET = env('PAYPAL_CLIENT_SECRET', default='') # Reemplazar con tu Client Secret de PayPal Sandbox PAYPAL_MODE = env('PAYPAL_MODE', default='sandbox') # Cambiar a 'live' en producción SMTP_ENDPOINT = env('SMTP_ENDPOINT', default='smtp.email.eu-paris-1.oci.oraclecloud.com') SMTP_PORT = env.int('SMTP_PORT') SECURITY = env('SECURITY', default='tls') SMTP_USERNAME = env('SMTP_USERNAME', default=None) SMTP_PASSWORD = env('SMTP_PASSWORD', default=None) SMTP_EMAIL = env('SMTP_EMAIL', default=None) AUTH_USER_MODEL = 'tienda.User' DOMAIN = env('DOMAIN', default='localhost') PROTOCOL = env('PROTOCOL', default='http') default_csrf_trusted_origins = [] if DOMAIN: default_csrf_trusted_origins.append(f"{PROTOCOL}://{DOMAIN}") for host in ALLOWED_HOSTS: if host and host != '*': default_csrf_trusted_origins.append(f"{PROTOCOL}://{host}") CSRF_TRUSTED_ORIGINS = env.list( 'CSRF_TRUSTED_ORIGINS', default=list(dict.fromkeys(default_csrf_trusted_origins)), ) LOG_LEVEL = env('LOG_LEVEL', default='INFO').upper() LOG_DIR = Path(env('LOG_DIR', default=str(BASE_DIR / 'logs'))) LOG_DIR.mkdir(parents=True, exist_ok=True) LOG_FILE = LOG_DIR / env('LOG_FILE', default='app.log') LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'formatters': { 'standard': { 'format': '%(asctime)s | %(levelname)s | %(name)s | %(message)s', }, }, 'handlers': { 'console': { 'class': 'logging.StreamHandler', 'formatter': 'standard', 'level': LOG_LEVEL, }, 'file': { 'class': 'logging.handlers.RotatingFileHandler', 'formatter': 'standard', 'filename': str(LOG_FILE), 'maxBytes': 5 * 1024 * 1024, 'backupCount': 5, 'level': LOG_LEVEL, 'encoding': 'utf-8', }, }, 'loggers': { 'tienda': { 'handlers': ['console', 'file'], 'level': LOG_LEVEL, 'propagate': False, }, 'tienda.audit': { 'handlers': ['console', 'file'], 'level': LOG_LEVEL, 'propagate': False, }, 'django': { 'handlers': ['console'], 'level': 'INFO', 'propagate': False, }, 'email.system': { 'handlers': ['console', 'file'], 'level': LOG_LEVEL, 'propagate': False } }, } logging.captureWarnings(True) if RUNNING_TESTS: EMAIL_BACKEND = 'django.core.mail.backends.locmem.EmailBackend' elif SMTP_USERNAME and SMTP_PASSWORD and SMTP_EMAIL: EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' else: print("ADVERTENCIA: Sin credenciales SMTP - usando backend console") EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' EMAIL_HOST = SMTP_ENDPOINT EMAIL_PORT = SMTP_PORT EMAIL_USE_TLS = (SECURITY == 'tls') # True si SECURITY es 'tls' EMAIL_USE_SSL = (SECURITY == 'ssl') # True si SECURITY es 'ssl' EMAIL_HOST_USER = SMTP_USERNAME EMAIL_HOST_PASSWORD = SMTP_PASSWORD # El correo que se usará como remitente por defecto DEFAULT_FROM_EMAIL = env('DEFAULT_FROM_EMAIL', default='') or SMTP_EMAIL or 'no-reply@localhost' # URL de Redis (asumiendo que corre en el puerto default 6379) CELERY_BROKER_URL = env('REDIS_URL', default='redis://localhost:6379/0') # Opcional: para guardar el resultado de las tareas CELERY_RESULT_BACKEND = env('REDIS_URL', default='redis://localhost:6379/0') # Configuraciones adicionales recomendadas CELERY_ACCEPT_CONTENT = ['json'] CELERY_TASK_SERIALIZER = 'json' CELERY_RESULT_SERIALIZER = 'json' SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https") USE_X_FORWARDED_HOST = True SECURE_REFERER_POLICY = "strict-origin-when-cross-origin" from django.forms.renderers import TemplatesSetting class CustomFormRenderer(TemplatesSetting): form_template_name = "tienda/form_snippet.html" FORM_RENDERER = "proyecto.settings.CustomFormRenderer"