Pourquoi Deployer Django sur Fly.io ?
Deployer Django sur Fly.io est une solution idéale pour les développeurs qui cherchent à rendre leurs applications web plus scalables, fiables et performantes. Avec Fly.io, vous pouvez facilement déployer, mettre à l'échelle et gérer vos applications en quelques minutes.
Un cas d'usage concret est une application de gestion de projet pour une petite équipe. En utilisant Fly.io, cette application peut être déployée rapidement sur un serveur cloud et mise à l'échelle en fonction du nombre de projets que la team gère.
Prerequis
- Connaissance approfondie de Django
- Python 3.8 ou ultérieur
- PostgreSQL (ou une autre base de données SQL)
- Git
- Compte Fly.io
Concepts fondamentaux
1. Environnements virtuels et requirements.txt
Un environnement virtuel est un espace isolé où les dépendances Python pour votre projet sont installées. Cela aide à éviter les conflits de version entre les projets.
## Créer un environnement virtuel
python -m venv venv
## Activer l'environnement virtuel
source venv/bin/activate # Sous Unix/macOS
venv\Scripts\activate # Sous Windows
## Installer les dépendances depuis requirements.txt
pip install -r requirements.txt
2. Configuration de Fly.io
Fly.io utilise un fichier fly.toml pour configurer le déploiement de votre application.
app = "mon-projet-django"
kill_signal = "SIGINT"
kill_timeout = 5
[env]
DJANGO_SETTINGS_MODULE = "mon_projet.settings"
DATABASE_URL = "postgres://user:password@host:port/dbname"
[build]
image = "python:3.8"
3. Django settings pour Fly.io
Vous devez configurer settings.py pour qu'il fonctionne sur Fly.io.
## settings.py
import dj_database_url
DATABASES = {
'default': dj_database_url.config(default='postgres://user:password@host:port/dbname')
}
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
## Configurer les fichiers statiques pour Fly.io
if os.getenv('DJANGO_SETTINGS_MODULE') == 'mon_projet.settings':
STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.StaticFilesStorage'
else:
STATICFILES_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
## Configurer les tâches asynchrones avec Celery
CELERY_BROKER_URL = os.getenv('REDIS_URL', 'redis://localhost:6379')
CELERY_RESULT_BACKEND = os.getenv('REDIS_URL', 'redis://localhost:6379')
if not DEBUG:
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'file': {
'level': 'DEBUG',
'class': 'logging.FileHandler',
'filename': '/var/log/django/debug.log',
},
},
'loggers': {
'django': {
'handlers': ['file'],
'level': 'DEBUG',
'propagate': True,
},
},
}
4. Base de données PostgreSQL sur Fly.io
Fly.io offre un service intégré pour PostgreSQL, ce qui simplifie le déploiement et la gestion de la base de données.
fly pg create mydb --region ord1
Mise en pratique : projet fil rouge
Nous allons créer un mini-projet complet : une application de gestion des tâches. Cette application permettra aux utilisateurs de créer, lire, mettre à jour et supprimer des tâches.
Étape 1 : Créer un nouveau projet Django
django-admin startproject mon_projet .
Étape 2 : Créer une application
python manage.py startapp tasks
Étape 3 : Configurer les modèles de données
## tasks/models.py
from django.db import models
class Task(models.Model):
title = models.CharField(max_length=255)
description = models.TextField(blank=True)
completed = models.BooleanField(default=False)
def __str__(self):
return self.title
Étape 4 : Configurer les vues
## tasks/views.py
from django.shortcuts import render, redirect
from .models import Task
from .forms import TaskForm
def task_list(request):
tasks = Task.objects.all()
return render(request, 'tasks/task_list.html', {'tasks': tasks})
def task_create(request):
if request.method == 'POST':
form = TaskForm(request.POST)
if form.is_valid():
form.save()
return redirect('task_list')
else:
form = TaskForm()
return render(request, 'tasks/task_form.html', {'form': form})
def task_update(request, pk):
task = Task.objects.get(pk=pk)
if request.method == 'POST':
form = TaskForm(request.POST, instance=task)
if form.is_valid():
form.save()
return redirect('task_list')
else:
form = TaskForm(instance=task)
return render(request, 'tasks/task_form.html', {'form': form})
def task_delete(request, pk):
task = Task.objects.get(pk=pk)
if request.method == 'POST':
task.delete()
return redirect('task_list')
return render(request, 'tasks/task_confirm_delete.html', {'task': task})
Étape 5 : Configurer les formulaires
## tasks/forms.py
from django import forms
from .models import Task
class TaskForm(forms.ModelForm):
class Meta:
model = Task
fields = ['title', 'description', 'completed']
Étape 6 : Configurer les URL
## mon_projet/urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('tasks.urls')),
]
python
## tasks/urls.py
from django.urls import path
from .views import task_list, task_create, task_update, task_delete
urlpatterns = [
path('', task_list, name='task_list'),
path('create/', task_create, name='task_create'),
path('<int:pk>/update/', task_update, name='task_update'),
path('<int:pk>/delete/', task_delete, name='task_delete'),
]
Étape 7 : Créer les templates
<!-- tasks/templates/tasks/task_list.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Task List</title>
</head>
<body>
<h1>Task List</h1>
<ul>
{% for task in tasks %}
<li>task.title - task.description
<a href="{% url 'task_update' task.pk %}">Edit</a>
<form method="post" action="{% url 'task_delete' task.pk %}" style="display:inline;">
{% csrf_token %}
<button type="submit">Delete</button>
</form>
</li>
{% endfor %}
</ul>
<a href="{% url 'task_create' %}">Create New Task</a>
</body>
</html>
html
<!-- tasks/templates/tasks/task_form.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Task Form</title>
</head>
<body>
<h1>{% if form.instance.pk %}Edit{% else %}Create{% endif %} Task</h1>
<form method="post">
{% csrf_token %}
form.as_p
<button type="submit">Save</button>
</form>
</body>
</html>
html
<!-- tasks/templates/tasks/task_confirm_delete.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Delete Task</title>
</head>
<body>
<h1>Confirm Delete</h1>
<p>Are you sure you want to delete "task.title"?</p>
<form method="post">
{% csrf_token %}
<button type="submit">Yes, delete</button>
<a href="{% url 'task_list' %}">Cancel</a>
</form>
</body>
</html>
Étape 8 : Installer les dépendances
pip install psycopg2-binary django-celery-results redis
Étape 9 : Configurer Celery et Redis
## mon_projet/celery.py
import os
from celery import Celery
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mon_projet.settings')
app = Celery('mon_projet')
app.config_from_object('django.conf:settings', namespace='CELERY')
app.autodiscover_tasks()
python
## mon_projet/__init__.py
from .celery import app as celery_app
__all__ = ('celery_app',)
Étape 10 : Configurer les tâches Celery
## tasks/tasks.py
from celery import shared_task
@shared_task
def send_email(subject, message, from_email, recipient_list):
# Code pour envoyer un email
pass
Étape 11 : Déploiement sur Fly.io
fly launch --image python:3.8
Erreurs frequentes et debugging
1. Mauvais chemin de template
## ❌ Mauvais
{% include 'tasks/task_form.html' %}
## ✅ Correct
{% include 'tasks/task_form.html' %}
2. Base de données non configurée
## ❌ Mauvais
DATABASES = {
'default': dj_database_url.config(default='sqlite:///db.sqlite3')
}
## ✅ Correct
DATABASES = {
'default': dj_database_url.config(default='postgres://user:password@host:port/dbname')
}
3. Erreur de configuration du serveur
## ❌ Mauvais
WSGI_APPLICATION = 'mon_projet.wsgi.application'
## ✅ Correct
WSGI_APPLICATION = 'mon_projet.wsgi.application'
Pour aller plus loin
- Gestion des fichiers statiques : Utilisez S3 pour stocker les fichiers statiques de votre application.
- Authentification et sécurité : Ajoutez une authentification utilisateurs avec Django Auth et configurez la sécurité des sessions.
- Monitoring et logs : Utilisez Fly.io monitoring et logs pour surveiller l'état de votre application.
Défi pratique
Développez un système d'authentification basique pour votre application de gestion des tâches en utilisant Django Auth et configurez les vues pour permettre aux utilisateurs de s'inscrire, se connecter et voir leurs tâches.