Overview
Inventario is a Django 5.2 application designed for easy deployment on cloud platforms or traditional servers. This guide covers local development setup, environment configuration, and production deployment.
System Requirements
Python Version: 3.11.9 or higherRequired for Django 5.2 compatibility
Database Production: PostgreSQL 12+Development: SQLite (included)
Memory Minimum: 512 MB RAMRecommended: 1 GB+ for production
Storage Minimum: 500 MBIncludes dependencies, static files, and media uploads
Dependencies
The application requires the following key packages:
Django==5.2.6
django-allauth==65.14.3 # Google OAuth & authentication
django-widget-tweaks==1.5.1 # Form rendering utilities
gunicorn==25.1.0 # Production WSGI server
whitenoise==6.11.0 # Static file serving
psycopg2-binary==2.9.11 # PostgreSQL adapter
dj-database-url==3.1.2 # Database URL parsing
python-dotenv==1.2.1 # Environment variable management
openai==2.21.0 # AI-powered insights
twilio==9.10.1 # SMS notifications
Pillow==12.1.1 # Image processing
reportlab==4.4.10 # PDF generation
barcode==1.0.4 # Barcode generation
pandas==3.0.0 # Data analysis for reports
resend==2.0.0 # Email service
Environment Variables
Create a .env file in the project root with the following configuration:
.env (Production)
.env (Development)
# Core Django Settings
DEBUG = False
SECRET_KEY = your-secret-key-here-min-50-characters
ALLOWED_HOSTS = yourdomain.com,www.yourdomain.com
CSRF_TRUSTED_ORIGINS = https://yourdomain.com,https://www.yourdomain.com
# Database (PostgreSQL)
DATABASE_URL = postgresql://user:password@host:5432/database_name
# Email Configuration (Resend)
RESEND_API_KEY = re_xxxxxxxxxxxxx
DEFAULT_FROM_EMAIL = [email protected]
# Google OAuth (Optional)
GOOGLE_CLIENT_ID = your-google-client-id.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET = your-google-client-secret
# AI Features (Optional)
OPENAI_API_KEY = sk-proj-xxxxxxxxxxxxxxxx
# SMS Notifications (Optional)
TWILIO_ACCOUNT_SID = ACxxxxxxxxxxxxxxxx
TWILIO_AUTH_TOKEN = your-twilio-auth-token
TWILIO_PHONE_NUMBER = +1234567890
# Security
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
Configuration Breakdown
Django’s cryptographic signing key. Generate a secure random string: from django.core.management.utils import get_random_secret_key
print (get_random_secret_key())
Never commit this to version control!
DATABASE_URL - Production Required
Database connection string parsed by dj-database-url: # From inventario/settings.py:79-84
DATABASES = {
'default' : dj_database_url.config(
default = f 'sqlite:/// { BASE_DIR / "db.sqlite3" } ' ,
conn_max_age = 600
)
}
Format: postgresql://username:password@host:port/databaseIf not provided, defaults to SQLite (dev only).
Enable “Sign in with Google” functionality:
Go to Google Cloud Console
Create a new project or select existing
Enable Google+ API
Create OAuth 2.0 credentials
Add authorized redirect URI: https://yourdomain.com/accounts/google/login/callback/
# Configuration from inventario/settings.py:130-141
SOCIALACCOUNT_PROVIDERS = {
'google' : {
'SCOPE' : [ 'profile' , 'email' ],
'AUTH_PARAMS' : { 'access_type' : 'online' },
'VERIFIED_EMAIL' : True ,
'APP' : {
'client_id' : os.environ.get( 'GOOGLE_CLIENT_ID' , '' ),
'secret' : os.environ.get( 'GOOGLE_CLIENT_SECRET' , '' ),
'key' : ''
}
}
}
OpenAI API Key - Optional
Powers AI-driven dashboard insights and recommendations:
Predictive analytics for sales trends
Stock replenishment suggestions
Customer behavior analysis
Automated report summaries
Get your API key from OpenAI Platform
Twilio Configuration - Optional
Enable SMS notifications for:
Low stock alerts
Daily sales summaries
Order confirmations
Sign up at Twilio and get your credentials from the dashboard.
Local Development Setup
Clone Repository
git clone < repository-ur l >
cd inventario
Create Virtual Environment
python3.11 -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
Install Dependencies
pip install -r requirements.txt
Configure Environment
Copy the development .env template: Edit .env and set minimum required variables:
DEBUG=True
SECRET_KEY=<generate-one>
Run Database Migrations
This creates the SQLite database and all required tables.
Create Superuser
python manage.py createsuperuser
Enter username, email, and password. This account has full admin access.
Collect Static Files
python manage.py collectstatic --no-input
Gathers all static files (CSS, JS, images) into staticfiles/ directory.
Run Development Server
python manage.py runserver
Access the application at http://127.0.0.1:8000 Admin panel: http://127.0.0.1:8000/admin/
Production Deployment
Option 1: Railway Deployment
Prepare Project
Ensure these files exist in your repository: Procfile: web: gunicorn inventario.wsgi:application --log-file - --workers 2 --timeout 120
runtime.txt:
Create Railway Project
Go to Railway.app
Click New Project → Deploy from GitHub repo
Select your repository
Railway auto-detects Django and Python version
Add PostgreSQL Database
In your Railway project, click New → Database → Add PostgreSQL
Railway automatically creates DATABASE_URL environment variable
The database is linked to your application
Configure Environment Variables
In Railway dashboard, add all production environment variables: DEBUG = False
SECRET_KEY =< generate-secure-key >
ALLOWED_HOSTS = ${{ RAILWAY_PUBLIC_DOMAIN }}
CSRF_TRUSTED_ORIGINS = https:// ${{ RAILWAY_PUBLIC_DOMAIN }}
DATABASE_URL = ${{ DATABASE_URL }} # Auto-provided by Railway
RESEND_API_KEY =< your-resend-key >
DEFAULT_FROM_EMAIL = [email protected]
Deploy
Railway automatically deploys on every push to your main branch. Build process:
Installs dependencies from requirements.txt
Runs migrations automatically
Collects static files
Starts Gunicorn server
Monitor deployment in Railway dashboard logs.
Configure Custom Domain (Optional)
In Railway project settings, go to Domains
Add your custom domain
Update DNS records as shown
Update ALLOWED_HOSTS and CSRF_TRUSTED_ORIGINS with your domain
Option 2: Render Deployment
Prepare Build Script
Create build.sh in project root: #!/usr/bin/env bash
set -o errexit
echo "📦 Installing dependencies..."
pip install -r requirements.txt
echo "📁 Collecting static files..."
python manage.py collectstatic --no-input
echo "🗄️ Running migrations..."
python manage.py migrate
echo "🌐 Configuring Site domain..."
python manage.py shell -c "
from django.contrib.sites.models import Site
site, _ = Site.objects.get_or_create(id=1)
site.domain = 'yourdomain.com'
site.name = 'Inventario'
site.save()
"
echo "✅ Build completed successfully."
Make it executable:
Create Render Web Service
Go to Render Dashboard
Click New → Web Service
Connect your GitHub/GitLab repository
Configure:
Name: inventario
Environment: Python 3
Build Command: ./build.sh
Start Command: gunicorn inventario.wsgi:application --workers 2 --timeout 120
Add PostgreSQL Database
In Render dashboard, click New → PostgreSQL
Create database
Copy the Internal Database URL
Add to your web service as DATABASE_URL environment variable
Configure Environment Variables
In web service Environment tab, add: PYTHON_VERSION = 3.11.9
DEBUG = False
SECRET_KEY =< generate-secure-key >
ALLOWED_HOSTS = .onrender.com,yourdomain.com
CSRF_TRUSTED_ORIGINS = https://your-service.onrender.com
DATABASE_URL =< internal-database-url >
Deploy
Render automatically builds and deploys:
Runs build.sh
Executes migrations
Collects static files
Starts Gunicorn
Monitor in Logs tab.
Option 3: Traditional Server (Ubuntu)
Prepare Server
# Update system
sudo apt update && sudo apt upgrade -y
# Install Python and dependencies
sudo apt install python3.11 python3.11-venv python3-pip postgresql nginx -y
Setup PostgreSQL
# Start PostgreSQL
sudo systemctl start postgresql
sudo systemctl enable postgresql
# Create database and user
sudo -u postgres psql
In PostgreSQL shell: CREATE DATABASE inventario_db ;
CREATE USER inventario_user WITH PASSWORD 'secure_password' ;
ALTER ROLE inventario_user SET client_encoding TO 'utf8' ;
ALTER ROLE inventario_user SET default_transaction_isolation TO 'read committed' ;
ALTER ROLE inventario_user SET timezone TO 'America/Bogota' ;
GRANT ALL PRIVILEGES ON DATABASE inventario_db TO inventario_user;
\q
Deploy Application
# Create application directory
sudo mkdir -p /var/www/inventario
cd /var/www/inventario
# Clone repository
sudo git clone < repository-ur l > .
# Create virtual environment
sudo python3.11 -m venv venv
sudo chown -R $USER : $USER /var/www/inventario
source venv/bin/activate
# Install dependencies
pip install -r requirements.txt
Configure Environment
# Create .env file
nano .env
Add production configuration: DEBUG = False
SECRET_KEY =< generate-secure-key >
ALLOWED_HOSTS = yourdomain.com,www.yourdomain.com
DATABASE_URL = postgresql://inventario_user:secure_password@localhost:5432/inventario_db
CSRF_TRUSTED_ORIGINS = https://yourdomain.com,https://www.yourdomain.com
Initialize Database
# Run migrations
python manage.py migrate
# Collect static files
python manage.py collectstatic --no-input
# Create superuser
python manage.py createsuperuser
Configure Gunicorn
Create systemd service file: sudo nano /etc/systemd/system/inventario.service
[Unit]
Description =Inventario Gunicorn Daemon
After =network.target
[Service]
User =www-data
Group =www-data
WorkingDirectory =/var/www/inventario
EnvironmentFile =/var/www/inventario/.env
ExecStart =/var/www/inventario/venv/bin/gunicorn \
--workers 3 \
--bind unix:/var/www/inventario/inventario.sock \
--timeout 120 \
inventario.wsgi:application
[Install]
WantedBy =multi-user.target
Enable and start service: sudo systemctl start inventario
sudo systemctl enable inventario
sudo systemctl status inventario
Configure Nginx
Create Nginx configuration: sudo nano /etc/nginx/sites-available/inventario
server {
listen 80 ;
server_name yourdomain.com www.yourdomain.com;
client_max_body_size 10M ;
location = /favicon.ico { access_log off ; log_not_found off ; }
location /static/ {
alias /var/www/inventario/staticfiles/;
}
location /media/ {
alias /var/www/inventario/media/;
}
location / {
include proxy_params;
proxy_pass http://unix:/var/www/inventario/inventario.sock;
}
}
Enable site: sudo ln -s /etc/nginx/sites-available/inventario /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl restart nginx
Setup SSL with Certbot
# Install Certbot
sudo apt install certbot python3-certbot-nginx -y
# Obtain SSL certificate
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com
# Test auto-renewal
sudo certbot renew --dry-run
Static Files Configuration
Inventario uses WhiteNoise for efficient static file serving in production:
# From inventario/settings.py:46,97-101
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware' ,
'whitenoise.middleware.WhiteNoiseMiddleware' , # Must be after SecurityMiddleware
# ... other middleware
]
STATIC_URL = 'static/'
STATICFILES_DIRS = [ BASE_DIR / 'static' ]
STATIC_ROOT = BASE_DIR / 'staticfiles'
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
Benefits:
Serves compressed static files (gzip/brotli)
Adds far-future cache headers
No CDN required for small to medium applications
Works seamlessly with Django’s collectstatic
Always run python manage.py collectstatic --no-input before deploying or after modifying static files.
Database Migrations
Inventario uses Django’s built-in migration system:
# Create new migrations after model changes
python manage.py makemigrations
# Apply migrations
python manage.py migrate
# Show migration status
python manage.py showmigrations
# Rollback to specific migration
python manage.py migrate app_name migration_name
Production Best Practices:
Always backup database before running migrations
Test migrations in staging environment first
Migrations run automatically during Railway/Render deployments
For manual deployments, run migrations before restarting application
Health Checks & Monitoring
Application Health
# Check if application is running
curl https: // yourdomain.com / login /
# Check admin panel
curl https: // yourdomain.com / admin /
Database Connection
# Test database connectivity
python manage.py dbshell
# Or check in Django shell
python manage.py shell
>>> from django.db import connection
>>> connection.ensure_connection ()
>>> print ( "Database connected successfully!" )
Common Issues
Static files not loading (404 errors)
Symptoms: CSS/JS files return 404 in productionSolution: # Ensure static files are collected
python manage.py collectstatic --no-input --clear
# Verify STATIC_ROOT directory exists
ls -la staticfiles/
# Check WhiteNoise is in MIDDLEWARE (must be after SecurityMiddleware)
Database connection errors
Symptoms: django.db.utils.OperationalError: FATAL: password authentication failedSolution:
Verify DATABASE_URL format is correct
Check database credentials
Ensure database server is running and accessible
For PostgreSQL, verify pg_hba.conf allows connections
# Test PostgreSQL connection
psql $DATABASE_URL
Symptoms: 403 Forbidden on form submissionsSolution: # Ensure CSRF_TRUSTED_ORIGINS includes your domain
CSRF_TRUSTED_ORIGINS = [
'https://yourdomain.com' ,
'https://www.yourdomain.com' ,
]
# For Railway: https://*.railway.app
# For Render: https://*.onrender.com
Google OAuth redirect mismatch
Symptoms: Google login fails with “redirect_uri_mismatch”Solution:
Go to Google Cloud Console
Navigate to APIs & Services → Credentials
Edit your OAuth 2.0 Client
Add authorized redirect URI: https://yourdomain.com/accounts/google/login/callback/
Update Site domain in Django admin:
python manage.py shell
>>> from django.contrib.sites.models import Site
>>> site = Site.objects.get( id = 1 )
>>> site.domain = 'yourdomain.com'
>>> site.name = 'Inventario'
>>> site.save()
Symptoms: 502 Bad Gateway or worker restart logsSolution:
Increase timeout in Procfile or systemd service:# Procfile
web: gunicorn inventario.wsgi:application --timeout 300 --workers 2
# For long-running reports/exports, increase to 300-600 seconds
Security Checklist
Before going to production, verify:
Database Connection Pooling
# Already configured in settings.py:79-84
DATABASES = {
'default' : dj_database_url.config(
default = f 'sqlite:/// { BASE_DIR / "db.sqlite3" } ' ,
conn_max_age = 600 # Reuse connections for 10 minutes
)
}
Gunicorn Workers
Calculate optimal worker count:
# Formula: (2 x CPU cores) + 1
# For 1 CPU: 3 workers
# For 2 CPU: 5 workers
gunicorn inventario.wsgi:application --workers 3 --threads 2
Static File Compression
WhiteNoise automatically compresses static files. Verify:
# After collectstatic, check for .gz files
ls -la staticfiles/ | grep \. gz
Backup & Recovery
Database Backup
# Backup PostgreSQL database
pg_dump $DATABASE_URL > backup_ $( date +%Y%m%d ) .sql
# Restore from backup
psql $DATABASE_URL < backup_20260310.sql
Automated Backups (Ubuntu)
# Create backup script
sudo nano /usr/local/bin/backup-inventario.sh
#!/bin/bash
BACKUP_DIR = "/var/backups/inventario"
DATE = $( date +%Y%m%d_%H%M%S )
mkdir -p $BACKUP_DIR
pg_dump inventario_db > $BACKUP_DIR /db_ $DATE .sql
# Keep only last 7 days
find $BACKUP_DIR -name "db_*.sql" -mtime +7 -delete
# Make executable
sudo chmod +x /usr/local/bin/backup-inventario.sh
# Add to crontab (daily at 2 AM)
sudo crontab -e
0 2 * * * /usr/local/bin/backup-inventario.sh
Updating the Application
Pull Latest Changes
cd /var/www/inventario
git pull origin main
Activate Virtual Environment
Update Dependencies
pip install -r requirements.txt --upgrade
Collect Static Files
python manage.py collectstatic --no-input
Restart Application
# Systemd service
sudo systemctl restart inventario
# Or if using supervisor
sudo supervisorctl restart inventario
Support & Resources
Django Documentation Official Django 5.2 documentation
Railway Docs Railway deployment guides
Render Docs Render deployment documentation
Gunicorn Docs Gunicorn configuration reference