Initial commit

This commit is contained in:
minguezsanzjuanjose
2026-04-11 03:31:05 +02:00
commit 1e78ad3a40
15 changed files with 244 additions and 0 deletions

10
.env Normal file
View File

@@ -0,0 +1,10 @@
# Seguridad
DEBUG=True
SECRET_KEY=una-clave-muy-secreta-y-larga-123456
# Base de Datos (Conectando al PostgreSQL que instalamos)
DB_NAME=gitea
DB_USER=gitea
DB_PASSWORD=gitea_password
DB_HOST=db
DB_PORT=5432

2
.gitattributes vendored Normal file
View File

@@ -0,0 +1,2 @@
# Auto detect text files and perform LF normalization
* text=auto

29
Dockerfile Normal file
View File

@@ -0,0 +1,29 @@
# Usamos una imagen ligera de Python
FROM python:3.12-slim
# Evitar que Python genere archivos .pyc y que el buffer se sature
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1
# Directorio de trabajo
WORKDIR /app
# Instalar dependencias del sistema necesarias
RUN apt-get update && apt-get install -y \
libpq-dev \
gcc \
gettext \
&& rm -rf /var/lib/apt/lists/*
# Instalar dependencias de Python
COPY requirements.txt /app/
RUN pip install --no-cache-dir -r requirements.txt
# Copiar el resto del código
COPY . /app/
# Exponer el puerto de Django
EXPOSE 8000
# Comando por defecto para arrancar (usaremos manage.py en dev y gunicorn en prod)
CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]

2
README.md Normal file
View File

@@ -0,0 +1,2 @@
# django-core-base

0
apps/__init__.py Normal file
View File

11
apps/common/utils.py Normal file
View File

@@ -0,0 +1,11 @@
# Ejemplo de limpieza de tipos para SQL
def clean_sql_string(value):
if value is None:
return ""
return str(value).strip().replace("'", "''")
def clean_sql_int(value):
try:
return int(value)
except (ValueError, TypeError):
return 0

View File

@@ -0,0 +1,56 @@
from django.db import connection
from common.utils import clean_sql_string, clean_sql_int
def getData(params):
"""
Función estándar para obtener datos de promociones.
"""
# 1. Definimos la query con placeholders (%s)
query = """
SELECT id, nombre, fecha_inicio, descripcion
FROM promociones
WHERE id = %s AND activo = %s
"""
# 2. Preparamos el diccionario de parámetros (tu estándar get_parameterized)
# Limpiamos los datos antes de enviarlos a la base de datos
id_promocion = clean_sql_int(params.get('id'))
is_active = 1 if params.get('activo') else 0
parameter_dict = [id_promocion, is_active]
# 3. Ejecución parametrizada
with connection.cursor() as cursor:
cursor.execute(query, parameter_dict)
columns = [col[0] for col in cursor.description]
result = [dict(zip(columns, row)) for row in cursor.fetchall()]
return result
def setData(params):
"""
Función estándar para insertar o actualizar (set_parameterized).
"""
# Ejemplo de UPDATE con JOIN (como solicitaste en tu estándar)
query = """
UPDATE promociones p
SET p.nombre = %s, p.fecha_modificacion = %s
FROM categorias c
WHERE p.categoria_id = c.id AND p.id = %s
"""
# Fecha en formato Año-Día-Mes (Y-d-m)
import datetime
fecha_hoy = datetime.datetime.now().strftime('%Y-%d-%m')
parameter_dict = [
clean_sql_string(params.get('nombre')),
fecha_hoy,
clean_sql_int(params.get('id'))
]
with connection.cursor() as cursor:
cursor.execute(query, parameter_dict)
affected_rows = cursor.rowcount
return affected_rows

7
apps/promociones/urls.py Normal file
View File

@@ -0,0 +1,7 @@
from django.urls import path
from .views import get_promocion_view
urlpatterns = [
# Capa 1: Definición del endpoint
path('obtener/', get_promocion_view, name='get_promocion'),
]

54
apps/promociones/views.py Normal file
View File

@@ -0,0 +1,54 @@
import logging
from django.http import JsonResponse
from .actions import getData
# Configuración del logger para rastrear la ejecución
logger = logging.getLogger(__name__)
def get_promocion_view(request):
"""
Vista estandarizada para la obtención de una promoción.
"""
# ---------------------------------------------------------
# BLOQUE 1: Log de iniciación
# ---------------------------------------------------------
logger.info("[START] Iniciando ejecución de get_promocion_view")
try:
# ---------------------------------------------------------
# BLOQUE 2: Limpieza de datos (Data Cleaning)
# ---------------------------------------------------------
# Extraemos los parámetros del request y preparamos el diccionario
raw_data = request.GET.dict()
# Aquí es donde ella aplicaría validaciones adicionales si fuera necesario
clean_params = {
'id': raw_data.get('id'),
'activo': raw_data.get('activo', True) # Valor por defecto
}
# ---------------------------------------------------------
# BLOQUE 3: Llamada a la Action (Execution)
# ---------------------------------------------------------
# La lógica de SQL y parametrización vive dentro de esta llamada
resultado_db = getData(clean_params)
# ---------------------------------------------------------
# BLOQUE 4: Log de cierre y respuesta (Closure)
# ---------------------------------------------------------
logger.info(f"[SUCCESS] get_promocion_view finalizada. Registros encontrados: {len(resultado_db)}")
return JsonResponse({
'status': 'success',
'data': resultado_db
}, status=200)
except Exception as e:
# Log de error detallado en caso de fallo
logger.error(f"[ERROR] Fallo crítico en get_promocion_view: {str(e)}")
return JsonResponse({
'status': 'error',
'message': 'Error interno del servidor'
}, status=500)

0
core/__init__.py Normal file
View File

20
core/settings.py Normal file
View File

@@ -0,0 +1,20 @@
from dotenv import load_dotenv
import os
# Cargar variables desde el archivo .env
load_dotenv()
SECRET_KEY = os.getenv('SECRET_KEY')
DEBUG = os.getenv('DEBUG') == 'True'
# Configuración de base de datos usando las variables
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': os.getenv('DB_NAME'),
'USER': os.getenv('DB_USER'),
'PASSWORD': os.getenv('DB_PASSWORD'),
'HOST': os.getenv('DB_HOST'),
'PORT': os.getenv('DB_PORT'),
}
}

6
core/urls.py Normal file
View File

@@ -0,0 +1,6 @@
from django.urls import path, include
urlpatterns = [
# Redirigimos todas las peticiones de /api/promociones/ a nuestra app
path('api/promociones/', include('promociones.urls')),
]

22
docker-compose.yml Normal file
View File

@@ -0,0 +1,22 @@
version: '3.8'
networks:
# Usamos la red que creamos al principio para que el Proxy lo vea
frontend:
external: true
services:
web:
build: .
container_name: django_app_dev
restart: always
environment:
- DEBUG=1
- DATABASE_URL=postgres://gitea:gitea_password@db:5432/gitea
# Usamos la base de datos de Gitea para empezar, o luego creamos una aparte
volumes:
- .:/app
networks:
- frontend
ports:
- "8000:8000"

21
manage.py Normal file
View File

@@ -0,0 +1,21 @@
#!/usr/bin/env python
"""Django's command-line utility for administrative tasks."""
import os
import sys
def main():
"""Run administrative tasks."""
# Apuntamos a la configuración dentro de la carpeta 'core'
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'core.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()

4
requirements.txt Normal file
View File

@@ -0,0 +1,4 @@
Django==5.0.3
psycopg2-binary==2.9.9
gunicorn==21.2.0
python-dotenv==1.0.1