| @ -0,0 +1,4 @@ | |||||
| Dockerfile | |||||
| Makefile | |||||
| volcadossql/ | |||||
| venv/ | |||||
| @ -0,0 +1,73 @@ | |||||
| # syntax=docker/dockerfile:1 | |||||
| ################## | |||||
| # BUILDER # | |||||
| ################## | |||||
| FROM python:3.11.4-slim-buster AS builder | |||||
| # set work directory | |||||
| WORKDIR /app | |||||
| # set environment variables | |||||
| ENV PYTHONDONTWRITEBYTECODE=1 | |||||
| ENV PYTHONUNBUFFERED=1 | |||||
| # install system dependencies | |||||
| RUN apt-get update && \ | |||||
| apt-get install -y --no-install-recommends gcc | |||||
| # lint | |||||
| RUN pip install --upgrade pip | |||||
| RUN pip install flake8==6.0.0 | |||||
| COPY . /app/ | |||||
| RUN flake8 --ignore=E501,F401,E126 . | |||||
| COPY ./requirements.txt . | |||||
| RUN pip wheel --no-cache-dir --no-deps --wheel-dir /app/wheels -r requirements.txt | |||||
| ################## | |||||
| # FINAL # | |||||
| ################## | |||||
| FROM python:3.11.4-slim-buster | |||||
| # create directory for the app user | |||||
| RUN mkdir -p /app | |||||
| # create the app user | |||||
| #RUN addgroup --system app && adduser --system --group app | |||||
| # create the appropriate directories | |||||
| ENV APP_HOME=/app | |||||
| RUN mkdir -p $APP_HOME | |||||
| #RUN mkdir -p $APP_HOME/staticfiles | |||||
| #RUN mkdir -p $APP_HOME/mediafiles | |||||
| WORKDIR $APP_HOME | |||||
| # install system dependencies | |||||
| RUN apt-get update && apt-get install -y sqlite3 netcat | |||||
| COPY --from=builder /app/wheels /wheels | |||||
| COPY --from=builder /app/requirements.txt . | |||||
| RUN pip install --upgrade pip | |||||
| RUN pip install --no-cache /wheels/* | |||||
| # copy entrypoint.sh | |||||
| COPY ./entrypoint.sh . | |||||
| # copy project | |||||
| COPY . $APP_HOME | |||||
| # chown all the files to the app user | |||||
| #RUN chown -R app:app $APP_HOME | |||||
| # change to the app user | |||||
| #USER app | |||||
| WORKDIR $APP_HOME/vehiculos | |||||
| # run entrypoint.sh | |||||
| ENTRYPOINT ["/app/entrypoint.sh"] | |||||
| @ -0,0 +1,50 @@ | |||||
| export ARQUITECTURA := $(shell lscpu |grep itectur | tr -d ' '| cut -f2 -d':') | |||||
| #export REGISTRY=registry.cube.local | |||||
| export REGISTRY=registry.reymota.es | |||||
| export IMG_VERSION = 1.16 | |||||
| export IMG_NGINX_VERSION = 1.0 | |||||
| # limpia todo | |||||
| all: imagen clean install | |||||
| imagen: | |||||
| cd ../; make | |||||
| install: | |||||
| -kubectl create -f namespace.yaml | |||||
| -kubectl create -f reg-secret.yaml | |||||
| -kubectl create -f env-prod-configmap.yaml | |||||
| -kubectl create -f env-prod-db-configmap.yaml | |||||
| -kubectl create -f pv-local-finanzas.yaml | |||||
| -kubectl create -f finanzas-prod-persistentvolumeclaim.yaml | |||||
| -kubectl create -f static-volume-persistentvolumeclaim.yaml | |||||
| -kubectl create -f postgres-data-persistentvolumeclaim.yaml | |||||
| -kubectl create -f db-deployment.yaml | |||||
| -kubectl create -f db-service.yaml | |||||
| -envsubst < finanzas-deployment.yaml |kubectl create -f - | |||||
| -envsubst < nginx-deployment.yaml |kubectl create -f - | |||||
| -kubectl create -f nginx-service.yaml | |||||
| clean: | |||||
| -envsubst < nginx-deployment.yaml |kubectl delete -f - | |||||
| -kubectl delete -f nginx-service.yaml | |||||
| -envsubst < finanzas-deployment.yaml |kubectl delete -f - | |||||
| -kubectl delete -f db-deployment.yaml | |||||
| -kubectl delete -f db-service.yaml | |||||
| -kubectl delete -f env-prod-configmap.yaml | |||||
| -kubectl delete -f env-prod-db-configmap.yaml | |||||
| -kubectl delete -f postgres-data-persistentvolumeclaim.yaml | |||||
| -kubectl delete -f static-volume-persistentvolumeclaim.yaml | |||||
| -kubectl delete -f finanzas-prod-persistentvolumeclaim.yaml | |||||
| -kubectl delete -f pv-local-finanzas.yaml | |||||
| -kubectl delete -f reg-secret.yaml | |||||
| -kubectl delete -f namespace.yaml | |||||
| nginx: | |||||
| cd ../nginx; make | |||||
| @ -0,0 +1,52 @@ | |||||
| apiVersion: apps/v1 | |||||
| kind: Deployment | |||||
| metadata: | |||||
| annotations: | |||||
| kompose.cmd: kompose convert | |||||
| kompose.version: 1.34.0 (cbf2835db) | |||||
| labels: | |||||
| io.kompose.service: db | |||||
| name: db | |||||
| namespace: finanzas | |||||
| spec: | |||||
| replicas: 1 | |||||
| selector: | |||||
| matchLabels: | |||||
| io.kompose.service: db | |||||
| strategy: | |||||
| type: Recreate | |||||
| template: | |||||
| metadata: | |||||
| annotations: | |||||
| kompose.cmd: kompose convert | |||||
| kompose.version: 1.34.0 (cbf2835db) | |||||
| labels: | |||||
| io.kompose.service: db | |||||
| spec: | |||||
| containers: | |||||
| - env: | |||||
| - name: POSTGRES_DB | |||||
| valueFrom: | |||||
| configMapKeyRef: | |||||
| key: POSTGRES_DB | |||||
| name: env-prod-db | |||||
| - name: POSTGRES_PASSWORD | |||||
| valueFrom: | |||||
| configMapKeyRef: | |||||
| key: POSTGRES_PASSWORD | |||||
| name: env-prod-db | |||||
| - name: POSTGRES_USER | |||||
| valueFrom: | |||||
| configMapKeyRef: | |||||
| key: POSTGRES_USER | |||||
| name: env-prod-db | |||||
| image: postgres:15 | |||||
| name: db | |||||
| volumeMounts: | |||||
| - mountPath: /var/lib/postgresql/data | |||||
| name: postgres-data | |||||
| restartPolicy: Always | |||||
| volumes: | |||||
| - name: postgres-data | |||||
| persistentVolumeClaim: | |||||
| claimName: postgres-data | |||||
| @ -0,0 +1,17 @@ | |||||
| apiVersion: v1 | |||||
| kind: Service | |||||
| metadata: | |||||
| annotations: | |||||
| kompose.cmd: kompose convert | |||||
| kompose.version: 1.34.0 (cbf2835db) | |||||
| labels: | |||||
| io.kompose.service: db | |||||
| name: db | |||||
| namespace: finanzas | |||||
| spec: | |||||
| ports: | |||||
| - name: "5432" | |||||
| port: 5432 | |||||
| targetPort: 5432 | |||||
| selector: | |||||
| io.kompose.service: db | |||||
| @ -0,0 +1 @@ | |||||
| kubectl -n finanzas exec -ti deployment.apps/finanzas -- /bin/bash | |||||
| @ -0,0 +1 @@ | |||||
| kubectl -n finanzas exec -ti deployment.apps/db -- psql --username=creylopez --dbname=finanzas | |||||
| @ -0,0 +1,19 @@ | |||||
| apiVersion: v1 | |||||
| data: | |||||
| DEBUG: "False" | |||||
| DJANGO_ALLOWED_HOSTS: "finanzas.reymota.es k8s-server localhost 127.0.0.1 [::1]" | |||||
| CSRF_TRUSTED_ORIGINS: "https://finanzas.reymota.es" | |||||
| SECRET_KEY: change_me | |||||
| SQL_DATABASE: finanzas | |||||
| SQL_ENGINE: django.db.backends.postgresql | |||||
| SQL_HOST: db | |||||
| SQL_PASSWORD: Dsa-0213 | |||||
| SQL_PORT: "5432" | |||||
| SQL_USER: creylopez | |||||
| DATABASE: postgres | |||||
| kind: ConfigMap | |||||
| metadata: | |||||
| labels: | |||||
| io.kompose.service: web-env-prod | |||||
| name: env-prod | |||||
| namespace: finanzas | |||||
| @ -0,0 +1,11 @@ | |||||
| apiVersion: v1 | |||||
| data: | |||||
| POSTGRES_DB: finanzas | |||||
| POSTGRES_PASSWORD: Dsa-0213 | |||||
| POSTGRES_USER: creylopez | |||||
| kind: ConfigMap | |||||
| metadata: | |||||
| labels: | |||||
| io.kompose.service: db-env-prod-db | |||||
| name: env-prod-db | |||||
| namespace: finanzas | |||||
| @ -0,0 +1,124 @@ | |||||
| apiVersion: v1 | |||||
| kind: Service | |||||
| metadata: | |||||
| name: finanzas | |||||
| namespace: finanzas | |||||
| spec: | |||||
| ports: | |||||
| - name: "8000" | |||||
| port: 8000 | |||||
| targetPort: 8000 | |||||
| selector: | |||||
| app: finanzas | |||||
| --- | |||||
| apiVersion: apps/v1 | |||||
| kind: Deployment | |||||
| metadata: | |||||
| name: finanzas | |||||
| namespace: finanzas | |||||
| labels: | |||||
| app: finanzas | |||||
| spec: | |||||
| replicas: 1 | |||||
| selector: | |||||
| matchLabels: | |||||
| app: finanzas | |||||
| strategy: | |||||
| type: Recreate | |||||
| template: | |||||
| metadata: | |||||
| labels: | |||||
| app: finanzas | |||||
| spec: | |||||
| containers: | |||||
| - args: | |||||
| - gunicorn | |||||
| - finanzas.wsgi:application | |||||
| - --bind | |||||
| - 0.0.0.0:8000 | |||||
| name: finanzas | |||||
| image: $REGISTRY/finanzas-$ARQUITECTURA:$IMG_VERSION | |||||
| env: | |||||
| - name: VERSION | |||||
| value: "$IMG_VERSION" | |||||
| - name: ENVIRONMENT | |||||
| value: "Producción" | |||||
| - name: DEBUG | |||||
| valueFrom: | |||||
| configMapKeyRef: | |||||
| key: DEBUG | |||||
| name: env-prod | |||||
| - name: DJANGO_ALLOWED_HOSTS | |||||
| valueFrom: | |||||
| configMapKeyRef: | |||||
| key: DJANGO_ALLOWED_HOSTS | |||||
| name: env-prod | |||||
| - name: CSRF_TRUSTED_ORIGINS | |||||
| valueFrom: | |||||
| configMapKeyRef: | |||||
| key: CSRF_TRUSTED_ORIGINS | |||||
| name: env-prod | |||||
| - name: SECRET_KEY | |||||
| valueFrom: | |||||
| configMapKeyRef: | |||||
| key: SECRET_KEY | |||||
| name: env-prod | |||||
| - name: DATABASE | |||||
| valueFrom: | |||||
| configMapKeyRef: | |||||
| key: DATABASE | |||||
| name: env-prod | |||||
| - name: SQL_HOST | |||||
| valueFrom: | |||||
| configMapKeyRef: | |||||
| key: SQL_HOST | |||||
| name: env-prod | |||||
| - name: SQL_PORT | |||||
| valueFrom: | |||||
| configMapKeyRef: | |||||
| key: SQL_PORT | |||||
| name: env-prod | |||||
| - name: SQL_ENGINE | |||||
| valueFrom: | |||||
| configMapKeyRef: | |||||
| key: SQL_ENGINE | |||||
| name: env-prod | |||||
| - name: SQL_DATABASE | |||||
| valueFrom: | |||||
| configMapKeyRef: | |||||
| key: SQL_DATABASE | |||||
| name: env-prod | |||||
| - name: SQL_USER | |||||
| valueFrom: | |||||
| configMapKeyRef: | |||||
| key: SQL_USER | |||||
| name: env-prod | |||||
| - name: SQL_PASSWORD | |||||
| valueFrom: | |||||
| configMapKeyRef: | |||||
| key: SQL_PASSWORD | |||||
| name: env-prod | |||||
| ports: | |||||
| - containerPort: 8000 | |||||
| protocol: TCP | |||||
| volumeMounts: | |||||
| - mountPath: /app/finanzas/mediafiles | |||||
| name: finanzas-media | |||||
| - mountPath: /app/finanzas/repostajes/migrations | |||||
| name: finanzas-migrations | |||||
| - mountPath: /app/finanzas/staticfiles | |||||
| name: static-volume | |||||
| imagePullSecrets: | |||||
| - name: myregistrykey | |||||
| restartPolicy: Always | |||||
| volumes: | |||||
| - name: finanzas-media | |||||
| persistentVolumeClaim: | |||||
| claimName: finanzas-media | |||||
| - name: finanzas-migrations | |||||
| persistentVolumeClaim: | |||||
| claimName: finanzas-migrations | |||||
| - name: static-volume | |||||
| persistentVolumeClaim: | |||||
| claimName: static-volume | |||||
| status: {} | |||||
| @ -0,0 +1,32 @@ | |||||
| apiVersion: v1 | |||||
| kind: PersistentVolumeClaim | |||||
| metadata: | |||||
| creationTimestamp: null | |||||
| labels: | |||||
| io.kompose.service: finanzas-media | |||||
| name: finanzas-media | |||||
| namespace: finanzas | |||||
| spec: | |||||
| accessModes: | |||||
| - ReadWriteOnce | |||||
| resources: | |||||
| requests: | |||||
| storage: 100Mi | |||||
| status: {} | |||||
| --- | |||||
| apiVersion: v1 | |||||
| kind: PersistentVolumeClaim | |||||
| metadata: | |||||
| creationTimestamp: null | |||||
| labels: | |||||
| io.kompose.service: finanzas-migrations | |||||
| name: finanzas-migrations | |||||
| namespace: finanzas | |||||
| spec: | |||||
| accessModes: | |||||
| - ReadWriteOnce | |||||
| resources: | |||||
| requests: | |||||
| storage: 50Mi | |||||
| status: {} | |||||
| @ -0,0 +1,7 @@ | |||||
| ################################################### | |||||
| # Namespace Vehículos | |||||
| ################################################### | |||||
| apiVersion: v1 | |||||
| kind: Namespace | |||||
| metadata: | |||||
| name: finanzas | |||||
| @ -0,0 +1,46 @@ | |||||
| apiVersion: apps/v1 | |||||
| kind: Deployment | |||||
| metadata: | |||||
| annotations: | |||||
| kompose.cmd: kompose convert | |||||
| kompose.version: 1.34.0 (cbf2835db) | |||||
| labels: | |||||
| io.kompose.service: nginx | |||||
| name: nginx | |||||
| namespace: finanzas | |||||
| spec: | |||||
| replicas: 1 | |||||
| selector: | |||||
| matchLabels: | |||||
| io.kompose.service: nginx | |||||
| strategy: | |||||
| type: Recreate | |||||
| template: | |||||
| metadata: | |||||
| annotations: | |||||
| kompose.cmd: kompose convert | |||||
| kompose.version: 1.34.0 (cbf2835db) | |||||
| labels: | |||||
| io.kompose.service: nginx | |||||
| spec: | |||||
| containers: | |||||
| - image: $REGISTRY/nginx-finanzas-$ARQUITECTURA:$IMG_NGINX_VERSION | |||||
| name: nginx | |||||
| ports: | |||||
| - containerPort: 80 | |||||
| protocol: TCP | |||||
| volumeMounts: | |||||
| - mountPath: /app/finanzas/staticfiles | |||||
| name: static-volume | |||||
| - mountPath: /app/finanzas/mediafiles | |||||
| name: finanzas-media | |||||
| imagePullSecrets: | |||||
| - name: myregistrykey | |||||
| restartPolicy: Always | |||||
| volumes: | |||||
| - name: static-volume | |||||
| persistentVolumeClaim: | |||||
| claimName: static-volume | |||||
| - name: finanzas-media | |||||
| persistentVolumeClaim: | |||||
| claimName: finanzas-media | |||||
| @ -0,0 +1,20 @@ | |||||
| apiVersion: v1 | |||||
| kind: Service | |||||
| metadata: | |||||
| annotations: | |||||
| kompose.cmd: kompose convert | |||||
| kompose.version: 1.34.0 (cbf2835db) | |||||
| labels: | |||||
| io.kompose.service: nginx | |||||
| name: nginx | |||||
| namespace: finanzas | |||||
| spec: | |||||
| type: NodePort | |||||
| ports: | |||||
| - name: "1337" | |||||
| port: 1337 | |||||
| nodePort: 30340 | |||||
| targetPort: 80 | |||||
| selector: | |||||
| io.kompose.service: nginx | |||||
| @ -0,0 +1,13 @@ | |||||
| apiVersion: v1 | |||||
| kind: PersistentVolumeClaim | |||||
| metadata: | |||||
| labels: | |||||
| io.kompose.service: postgres-data | |||||
| name: postgres-data | |||||
| namespace: finanzas | |||||
| spec: | |||||
| accessModes: | |||||
| - ReadWriteOnce | |||||
| resources: | |||||
| requests: | |||||
| storage: 100Mi | |||||
| @ -0,0 +1,59 @@ | |||||
| apiVersion: v1 | |||||
| kind: PersistentVolume | |||||
| metadata: | |||||
| name: finanzas-media-folder | |||||
| namespace: finanzas | |||||
| labels: | |||||
| app: finanzas | |||||
| spec: | |||||
| capacity: | |||||
| storage: 100Mi | |||||
| accessModes: | |||||
| - ReadWriteOnce | |||||
| hostPath: | |||||
| path: "/mnt/Externo/finanzas/media" | |||||
| --- | |||||
| apiVersion: v1 | |||||
| kind: PersistentVolume | |||||
| metadata: | |||||
| name: finanzas-migrations-folder | |||||
| namespace: finanzas | |||||
| labels: | |||||
| app: finanzas | |||||
| spec: | |||||
| capacity: | |||||
| storage: 50Mi | |||||
| accessModes: | |||||
| - ReadWriteOnce | |||||
| hostPath: | |||||
| path: "/mnt/Externo/finanzas/migrations" | |||||
| --- | |||||
| apiVersion: v1 | |||||
| kind: PersistentVolume | |||||
| metadata: | |||||
| name: finanzas-static-folder | |||||
| namespace: finanzas | |||||
| labels: | |||||
| app: finanzas | |||||
| spec: | |||||
| capacity: | |||||
| storage: 70Mi | |||||
| accessModes: | |||||
| - ReadWriteOnce | |||||
| hostPath: | |||||
| path: "/mnt/Externo/finanzas/static" | |||||
| --- | |||||
| apiVersion: v1 | |||||
| kind: PersistentVolume | |||||
| metadata: | |||||
| name: finanzas-pg-folder | |||||
| namespace: finanzas | |||||
| labels: | |||||
| app: finanzas | |||||
| spec: | |||||
| capacity: | |||||
| storage: 200Mi | |||||
| accessModes: | |||||
| - ReadWriteOnce | |||||
| hostPath: | |||||
| path: "/mnt/Externo/finanzas/pg" | |||||
| @ -0,0 +1,8 @@ | |||||
| apiVersion: v1 | |||||
| kind: Secret | |||||
| metadata: | |||||
| name: myregistrykey | |||||
| namespace: finanzas | |||||
| data: | |||||
| .dockerconfigjson: ewoJImF1dGhzIjogewoJCSJyZWdpc3RyeS5yZXltb3RhLmVzIjogewoJCQkiYXV0aCI6ICJZM0psZVd4dmNHVjZPbEpsZVMweE1UYzIiCgkJfQoJfQp9 | |||||
| type: kubernetes.io/dockerconfigjson | |||||
| @ -0,0 +1,13 @@ | |||||
| apiVersion: v1 | |||||
| kind: PersistentVolumeClaim | |||||
| metadata: | |||||
| labels: | |||||
| io.kompose.service: static-volume | |||||
| name: static-volume | |||||
| namespace: finanzas | |||||
| spec: | |||||
| accessModes: | |||||
| - ReadWriteOnce | |||||
| resources: | |||||
| requests: | |||||
| storage: 70Mi | |||||
| @ -0,0 +1 @@ | |||||
| docker run -it registry.reymota.es/finanzas:1.19 bash | |||||
| @ -0,0 +1,8 @@ | |||||
| install: | |||||
| echo "Creando imagen con version '${IMG_VERSION}' para la arquitectura '${ARQUITECTURA}' en el registry '${REGISTRY}'" | |||||
| docker build --no-cache -t ${REGISTRY}/finanzas-${ARQUITECTURA}:${IMG_VERSION} . | |||||
| docker push ${REGISTRY}/finanzas-${ARQUITECTURA}:${IMG_VERSION} | |||||
| @ -0,0 +1,40 @@ | |||||
| # Instalación | |||||
| Desde el directorio K8S ejecutar make (esto hace todo: la imagen, para los pods y los lanza otra vez) | |||||
| La primera vez, hay que entrar en el pod de vehículos con 'entra.sh' y | |||||
| python manage.py createsuperuser | |||||
| python manage.py makemigrations | |||||
| python manage.py migrate | |||||
| ## Comprobar la base de datos | |||||
| Con la shell entraPsql.sh: | |||||
| \l para listar las BD | |||||
| \c vehiculos para usar nuestra db | |||||
| \dt para ver las tablas | |||||
| # De dónde cogí ideas | |||||
| https://learndjango.com/tutorials/django-login-and-logout-tutorial | |||||
| Username: {{ user.username }} | |||||
| User Full name: {{ user.get_full_name }} | |||||
| User Group: {{ user.groups.all.0 }} | |||||
| Email: {{ user.email }} | |||||
| Session Started at: {{ user.last_login }} | |||||
| ## Para funcionar con gunicorn y nginx | |||||
| https://testdriven.io/blog/dockerizing-django-with-postgres-gunicorn-and-nginx/ | |||||
| @ -0,0 +1,20 @@ | |||||
| #!/bin/bash | |||||
| if [ "$DATABASE" = "postgres" ] | |||||
| then | |||||
| echo "Waiting for postgres..." | |||||
| while ! nc -z $SQL_HOST $SQL_PORT; do | |||||
| sleep 0.1 | |||||
| done | |||||
| echo "PostgreSQL started" | |||||
| else | |||||
| echo "la base de datos no es postgres: '$DATABASE'" | |||||
| fi | |||||
| python manage.py collectstatic --noinput | |||||
| #python manage.py flush --no-input | |||||
| #python manage.py migrate | |||||
| exec "$@" | |||||
| @ -0,0 +1,6 @@ | |||||
| export CSRF_TRUSTED_ORIGINS="http://localhost" | |||||
| export DEBUG="True" | |||||
| export SECRET_KEY="hola" | |||||
| export DJANGO_ALLOWED_HOSTS="localhost" | |||||
| @ -0,0 +1,4 @@ | |||||
| FROM nginx:1.25 | |||||
| RUN rm /etc/nginx/conf.d/default.conf | |||||
| COPY nginx.conf /etc/nginx/conf.d | |||||
| @ -0,0 +1,8 @@ | |||||
| install: | |||||
| echo "Creando imagen con version '${IMG_NGINX_VERSION}' para la arquitectura '${ARQUITECTURA}' en el registry '${REGISTRY}'" | |||||
| docker build --no-cache -t ${REGISTRY}/nginx-vehiculos-${ARQUITECTURA}:${IMG_NGINX_VERSION} . | |||||
| docker push ${REGISTRY}/nginx-vehiculos-${ARQUITECTURA}:${IMG_NGINX_VERSION} | |||||
| @ -0,0 +1,25 @@ | |||||
| upstream vehiculos { | |||||
| server vehiculos:8000; | |||||
| } | |||||
| server { | |||||
| listen 80; | |||||
| location / { | |||||
| proxy_pass http://vehiculos; | |||||
| proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; | |||||
| proxy_set_header Host $http_host; | |||||
| proxy_redirect off; | |||||
| client_max_body_size 100M; | |||||
| } | |||||
| location /static/ { | |||||
| alias /app/vehiculos/staticfiles/; | |||||
| } | |||||
| location /media/ { | |||||
| alias /app/vehiculos/mediafiles/; | |||||
| } | |||||
| } | |||||
| @ -0,0 +1,13 @@ | |||||
| asgiref==3.8.1 | |||||
| Django==4.2 | |||||
| flake8==7.1.1 | |||||
| gunicorn==22.0.0 | |||||
| mccabe==0.7.0 | |||||
| packaging==24.1 | |||||
| pillow==10.4.0 | |||||
| psycopg2-binary==2.9.6 | |||||
| pycodestyle==2.12.1 | |||||
| pyflakes==3.2.0 | |||||
| sqlparse==0.5.1 | |||||
| typing_extensions==4.12.2 | |||||
| django-calculation==1.0.0 | |||||