Tutoriel : Application complète avec Forge¶
Ce tutoriel guide le développement d'une petite application Forge de bout en bout.
Il suppose que Forge est déjà installé et que MariaDB est disponible.
Nouveau sur Forge ?
Commencez par Bonjour Forge pour découvrir les
bases avant d'aborder ce tutoriel.
Objectif¶
À la fin de ce tutoriel, vous aurez :
- un projet Forge fonctionnel avec plusieurs entités ;
- deux entités (
VilleetContact) reliées par une relationmany_to_one; - des CRUD générés pour chaque entité ;
- une compréhension claire des fichiers générés et préservés ;
- un projet validé par les outils de diagnostic Forge.
Ce que tu vas construire¶
Un carnet de contacts minimal :
- une entité
Ville(nom, code postal) ; - une entité
Contact(nom, prénom, email, ville) ; - une relation : un contact appartient à une ville ;
- les vues liste, fiche, création, modification et suppression pour chaque entité.
Ce n'est pas une application métier complète. Le but est de montrer Forge :
comment les entités s'organisent, comment les relations se déclarent, et comment
le code généré se distingue du code que vous écrivez.
Le workflow officiel en un coup d'œil¶
forge make:entity → crée l'entité JSON (vous éditez les champs)
forge make:relation → déclare les relations dans relations.json
forge build:model → régénère TOUT depuis le JSON : SQL, _base.py, relations.sql
forge db:init → crée la base et applique le SQL généré
forge make:crud → génère contrôleurs, formulaires et vues
forge run → lance l'application
forge build:model est la commande centrale : elle régénère, pour toutes les
entités, le schéma SQL, l'interface _base.py et le relations.sql, à partir des
fichiers JSON. Les variantes ciblées forge sync:entity <Nom> (une seule entité)
et forge sync:relations (relations seules) servent à régénérer après édition
d'un élément précis ; pour le parcours initial, build:model suffit.
Prérequis¶
- Forge installé (
forge --versiondoit répondre) ; - Python 3.12 ou plus ;
- MariaDB installé et démarré (pour
forge db:init) ; - npm installé (optionnel, pour recompiler le CSS Tailwind).
1. Créer le projet¶
forge new crée la structure du projet, installe les dépendances Python,
génère les certificats SSL de développement, compile le CSS Tailwind si npm
est disponible, et initialise un dépôt Git propre.
Structure créée :
carnet_contacts/
├── app.py # point d'entrée
├── env/dev # configuration (.env)
├── mvc/
│ ├── routes.py # déclaration des routes
│ ├── controllers/ # contrôleurs applicatifs
│ ├── models/ # modèles applicatifs
│ ├── forms/ # formulaires
│ ├── views/ # templates Jinja
│ └── entities/ # entités JSON et relations
│ └── relations.json # relations globales (vide au départ)
├── static/ # fichiers statiques
└── forge_profile.txt # profil du projet
2. Vérifier le projet¶
Ces deux commandes sont complémentaires :
forge doctor: diagnostic de l'environnement d'exécution ;forge project:check: cohérence interne du projet Forge (dossiers,
configuration, entités, routes, templates, modules).
Un projet neuf doit être sain dès la création.
3. Créer l'entité Ville¶
Fichiers créés dans mvc/entities/ville/ (le sous-dossier est en minuscule) :
| Fichier | Rôle | Régénérable ? |
|---|---|---|
ville.json |
Source de vérité de l'entité | Non (source) |
ville.sql |
Schéma SQL généré | Oui (build:model) |
ville_base.py |
Interface Python générée | Oui (build:model) |
ville.py |
Modèle manuel (vide au départ) | Non, préservé |
Personnaliser l'entité Ville¶
Éditez mvc/entities/ville/ville.json au format canonique (clé racine
name, types Forge, pas de champ id ni de type SQL brut) :
{
"schema_version": "1.0",
"name": "Ville",
"table": "villes",
"fields": [
{"name": "nom", "type": "string", "max_length": 100, "required": true},
{"name": "code_postal", "type": "string", "max_length": 10}
]
}
Le champ id est implicite
Forge génère la clé primaire id automatiquement : ne la déclarez pas dans
fields. Les types sont ceux de Forge (string, integer, slug,
boolean, date, email…), jamais du SQL brut comme VARCHAR(100).
4. Créer l'entité Contact¶
Fichiers créés dans mvc/entities/contact/, sur le même modèle que ville.
Personnaliser l'entité Contact¶
Éditez mvc/entities/contact/contact.json :
{
"schema_version": "1.0",
"name": "Contact",
"table": "contacts",
"fields": [
{"name": "nom", "type": "string", "max_length": 100, "required": true},
{"name": "prenom", "type": "string", "max_length": 100, "required": true},
{"name": "email", "type": "email", "required": true},
{"name": "ville_id", "type": "integer", "nullable": true}
]
}
Le champ ville_id est un entier ordinaire dans le JSON de Contact.
La contrainte de clé étrangère sera déclarée dans relations.json, pas dans
l'entité.
5. Déclarer la relation¶
La relation entre Contact et Ville est déclarée dans le fichier global
mvc/entities/relations.json.
forge make:relation est un assistant interactif. Il vous pose les questions
suivantes :
Type de relation : many_to_one
Entité source (from) : Contact
Entité cible (to) : Ville
Clé étrangère (foreign_key) : ville_id
Résultat dans mvc/entities/relations.json :
{
"$schema": "../../schemas/relations.schema.json",
"schema_version": "1.0",
"relations": [
{
"type": "many_to_one",
"from": "Contact",
"to": "Ville",
"name": "ville",
"foreign_key": "ville_id",
"nullable": true,
"on_delete": "set_null"
}
]
}
6. Régénérer le modèle¶
Après avoir édité les entités et déclaré la relation, régénérez tout d'une
seule commande :
forge build:model relit chaque *.json et régénère, pour toutes les entités :
- le schéma SQL (
ville.sql,contact.sql) ; - l'interface Python (
ville_base.py,contact_base.py) ; - le fichier global
relations.sql(contraintesALTER TABLEde la clé étrangère).
Les modèles manuels (ville.py, contact.py) sont préservés : Forge ne les
réécrit jamais. Vérifiez la cohérence à tout moment avec forge check:model.
7. Générer les CRUD¶
Fichiers créés pour Ville¶
| Fichier | Modifiable ? |
|---|---|
mvc/controllers/ville_controller.py |
Oui, préservé |
mvc/models/ville.py |
Oui, préservé |
mvc/forms/ville_form.py |
Oui, préservé |
mvc/views/ville/list.html |
Oui, préservé |
mvc/views/ville/show.html |
Oui, préservé |
mvc/views/ville/create.html |
Oui, préservé |
mvc/views/ville/edit.html |
Oui, préservé |
mvc/views/ville/delete.html |
Oui, préservé |
Les fichiers de Contact suivent le même schéma (contact_controller.py,
contact_form.py, mvc/views/contact/*.html).
make:crud et les relations
Quand Contact est la source (from) d'une relation many_to_one, forge make:crud
génère automatiquement un champ RelationField pour ville_id dans le formulaire,
et un LEFT JOIN dans la requête de liste pour afficher le nom de la ville.
Fichiers préservés
Ces fichiers ne sont jamais réécrasés par Forge.
Si forge make:crud est relancé sur une entité existante, il refuse
sans l'option --force. Votre code est en sécurité.
Les routes sont ajoutées automatiquement dans mvc/routes.py.
8. Comprendre les fichiers générés¶
Architecture des fichiers¶
mvc/entities/
├── contact/
│ ├── contact.json ← source de vérité (vous éditez ce fichier)
│ ├── contact.sql ← généré par build:model (régénérable)
│ ├── contact_base.py ← généré par build:model (régénérable)
│ └── contact.py ← modèle manuel (préservé)
├── ville/
│ ├── ville.json ← source de vérité (vous éditez ce fichier)
│ ├── ville.sql ← généré par build:model (régénérable)
│ ├── ville_base.py ← généré par build:model (régénérable)
│ └── ville.py ← modèle manuel (préservé)
├── relations.json ← source de vérité des relations (vous éditez ce fichier)
└── relations.sql ← généré par build:model (régénérable)
La règle centrale¶
JSON → build:model → SQL + _base.py + relations.sql (régénérable à tout moment)
JSON → make:crud → controller / model / form / views (préservé - jamais réécrasé)
Les fichiers SQL et _base.py sont des projections du JSON : régénérez-les
autant de fois que nécessaire, sans perte. Les fichiers de make:crud et les
modèles manuels sont les vôtres ; Forge n'y touche plus après la création.
Le Contrat de stabilité garantit cette règle.
9. Lancer l'application¶
Configurer env/dev¶
# Renseigner les variables MariaDB dans env/dev
DB_ADMIN_LOGIN=root
DB_ADMIN_PWD=<mot_de_passe_root>
DB_APP_LOGIN=carnet_contacts_app
DB_APP_PWD=<mot_de_passe_app>
DB_NAME=carnet_contacts
Initialiser la base¶
forge db:init crée la base, l'utilisateur applicatif et les tables issues des
fichiers SQL générés (ville.sql, contact.sql) puis applique relations.sql.
Ordre des tables
forge db:init applique d'abord les fichiers SQL des entités, puis
relations.sql. La table villes doit exister avant que la contrainte
de clé étrangère sur contacts soit ajoutée. Cet ordre est géré automatiquement.
Lancer l'application¶
L'application démarre sur https://localhost:8000 avec HTTPS de développement.
Les routes disponibles :
/ville → liste des villes
/ville/new → créer une ville
/contact → liste des contacts (avec ville affichée)
/contact/new → créer un contact (sélection de ville disponible)
10. Contrôles finaux¶
Un projet avec deux entités, une relation many_to_one, et les CRUD générés
doit passer les trois contrôles sans fail.
Les tests valident les générateurs, le runtime et les entités. La compilation
vérifie l'absence d'erreurs de syntaxe.
11. Limites du tutoriel¶
Ce tutoriel couvre une application simple. Il ne couvre pas :
| Limite | Documentation |
|---|---|
| Auth / connexion utilisateur | Auth/User |
| Rôles et permissions (RBAC) | Sécurité et RBAC, RBAC |
Relations many_to_many |
Relations entre entités |
| Déploiement en production | Déploiement |
| Sécurité en production | Sécurité en production |
forge make:relation est interactif. Pour les projets sans terminal interactif,
éditez directement mvc/entities/relations.json selon le format documenté
dans Relations entre entités.
forge db:init nécessite un MariaDB local configuré. Sans MariaDB, les
fichiers JSON, SQL, modèles et vues sont générés mais l'application ne peut
pas démarrer.
Récapitulatif des commandes¶
forge new carnet_contacts # créer le projet
cd carnet_contacts
source .venv/bin/activate
forge doctor # vérifier l'environnement
forge project:check # cohérence structurelle
forge make:entity Ville --no-input # créer l'entité Ville, puis éditer ville.json
forge make:entity Contact --no-input # créer l'entité Contact, puis éditer contact.json
forge make:relation # déclarer la relation Contact → Ville
forge build:model # régénérer SQL + _base.py + relations.sql
forge make:crud Ville # générer le CRUD Ville
forge make:crud Contact # générer le CRUD Contact
forge project:check # vérifier après génération
forge project:audit # rapport détaillé
forge db:init # initialiser la base (MariaDB requis)
forge run # lancer l'application
Voir aussi¶
- Bonjour Forge, premier contact, sans BDD
- Guide de démarrage, parcours complet avec MariaDB
- Relations entre entités, format
relations.jsoncomplet - Architecture des entités, rôle de chaque fichier généré
- Contrat de stabilité, garanties sur les fichiers préservés
- Référence API et CLI, toutes les commandes, dont les filtres de liste CRUD (
list.filter)
```