Starter 1 — Contacts¶
Starter Forge · Niveau 1
Application Contacts
Premier parcours Forge : une seule entité Contact, un CRUD généré, puis un câblage manuel des routes.
-
Objectif
Construire une petite application CRUD pour gérer des contacts.
-
Niveau
Débutant Forge. Aucune relation, aucune authentification métier spécifique.
-
Temps estimé
1 h à 2 h.
-
Résultat attendu
Liste, création, détail, modification, suppression et messages flash.
Ce que ce starter doit faire comprendre
Le but n'est pas seulement d'obtenir une page /contacts fonctionnelle. Ce starter sert surtout à voir les pièces réelles utilisées par Forge : le JSON canonique, le SQL généré, la classe Python générée, le contrôleur, le formulaire, le modèle SQL, les templates Jinja et les routes ajoutées manuellement.
Prérequis¶
Prérequis généraux¶
- Python 3.11 ou supérieur
- Git
pipx(recommandé) ou environnement virtuel Python- MariaDB installé et démarré
- Accès à un compte administrateur MariaDB (pour
forge db:init) - Fichier
env/devconfiguré avec les identifiants MariaDB
Prérequis spécifiques au starter¶
- Projet Forge vierge (créé via
forge newougit clone) - Commandes
forge make:entity,forge build:model,forge db:applyetforge make:cruddisponibles (incluses dans l'installation Forge)
Partie 1 — Installer Forge sur une VM Debian vierge¶
Si Forge est déjà installé et configuré sur votre machine, passez directement à la Partie 2 — Construire l'application starter.
La procédure complète est documentée sur la page Installation sur VM Debian vierge.
Elle couvre en 7 étapes : mise à jour du système, dépendances Python/MariaDB, Node.js optionnel, configuration de pipx, démarrage de MariaDB, vérification de l'accès administrateur et installation de Forge via pipx.
Une fois que forge --version s'affiche correctement, revenez ici pour construire l'application.
Partie 2 — Construire l'application starter¶
1. Présentation rapide¶
1.1 Objectif¶
Construire une petite application de gestion de contacts avec :
- une liste simple, enrichissable ensuite ;
- une page de création ;
- une page de détail ;
- une page de modification ;
- une suppression en
POST; - des messages flash après création, modification ou suppression.
Le starter sert à comprendre le flux Forge minimal : JSON canonique, SQL visible, modèle Python généré, CRUD MVC explicite et routes copiées manuellement.
1.2 Parcours général¶
flowchart TD
A([Navigateur]) -->|"GET /contacts, POST /contacts…"| B["mvc/routes.py"]
B --> C[ContactController]
C -->|"lit et valide"| D[ContactForm]
C -->|"lit / écrit"| E[contact_model.py]
E --> F[(MariaDB)]
C -->|"rend"| G[Vue Jinja2]
G --> H([HTML affiché])
Lecture du schéma
Une requête web ne va jamais directement en base. Elle passe par une route, un contrôleur, éventuellement un formulaire, puis un modèle SQL. La réponse revient ensuite sous forme de vue Jinja2 rendue en HTML.
2. Installation du projet Forge¶
Les deux méthodes arrivent au même résultat : un projet Forge local avec un environnement Python actif et une commande forge utilisable.
Si vous avez suivi la Partie 1
forge est déjà installé via pipx install forge-mvc. Dans l'onglet "Installation automatique" ci-dessous, ignorez la ligne pipx install ... et commencez directement par forge new Contacts.
CLI officielle
La documentation utilisateur suppose la CLI officielle forge, disponible après installation du package.
2.1 Schéma d'installation¶
flowchart LR
A1["Méthode A<br/>pipx install"] --> A2["forge new Contacts"] --> P["Projet Forge prêt"]
B1["Méthode B<br/>git clone"] --> B2["python -m venv .venv"] --> B3["pip install -r requirements.txt<br/>pip install -e ."] --> P
-
Contrôle à faire
-
Répertoire attendu
3. Préparation de la base¶
3.1 Configurer l'administrateur MariaDB du projet¶
Avant d'exécuter forge db:init, renseigner dans env/dev un compte MariaDB disposant des droits nécessaires pour :
- créer la base de données du projet ;
- créer l'utilisateur applicatif ;
- appliquer les privilèges nécessaires.
En développement local, on peut utiliser temporairement un compte administrateur MariaDB existant.
Ne pas confondre les deux comptes
DB_ADMIN_LOGIN prépare la base avec forge db:init.
DB_APP_LOGIN est utilisé ensuite par l'application pendant son fonctionnement normal.
Exemple pour une application nommée Contacts :
DB_ADMIN_HOST=localhost
DB_ADMIN_PORT=3306
DB_ADMIN_LOGIN=root
DB_ADMIN_PWD=<mot_de_passe_root_mariadb>
DB_NAME=contacts
DB_APP_HOST=localhost
DB_APP_PORT=3306
DB_APP_LOGIN=contacts_app
DB_APP_PWD=ContactsApp_2026!
Compte administrateur MariaDB
La procédure utilise root avec mot de passe comme compte administrateur MariaDB. Ce choix simplifie la procédure pour un environnement pédagogique.
Pour un environnement plus sécurisé, remplacer root par un compte dédié, par exemple forge_admin, dans DB_ADMIN_LOGIN / DB_ADMIN_PWD.
| Variable | Rôle | Moment d'utilisation |
|---|---|---|
DB_ADMIN_HOST |
Adresse du serveur MariaDB pour l'administration | Pendant forge db:init |
DB_ADMIN_PORT |
Port MariaDB pour l'administration | Pendant forge db:init |
DB_ADMIN_LOGIN |
Compte qui crée la base et les droits | Uniquement pendant forge db:init |
DB_ADMIN_PWD |
Mot de passe du compte administrateur | Uniquement pendant forge db:init |
DB_NAME |
Base de données du projet | Créée par forge db:init |
DB_APP_HOST |
Adresse du serveur MariaDB pour l'application | Exécution et forge db:apply |
DB_APP_PORT |
Port MariaDB pour l'application | Exécution et forge db:apply |
DB_APP_LOGIN |
Compte applicatif limité | Utilisé par l'application |
DB_APP_PWD |
Mot de passe du compte applicatif | Utilisé par l'application |
3.2 Schéma : rôle des comptes MariaDB¶
flowchart TD
A["forge db:init"] --> B["DB_ADMIN_LOGIN"]
B --> C["crée la base DB_NAME"]
B --> D["crée DB_APP_LOGIN"]
B --> E["donne les droits nécessaires"]
F["python app.py"] --> G["DB_APP_LOGIN"]
G --> H["lit et écrit uniquement<br/>dans la base du projet"]
3.3 Initialiser la base¶
Cette commande crée la base de données du projet, l'utilisateur applicatif et applique les droits.
Avant de continuer
Vérifier que MariaDB est installé, démarré, et que les variables DB_ADMIN_HOST, DB_ADMIN_PORT, DB_ADMIN_LOGIN, DB_ADMIN_PWD, DB_APP_HOST, DB_APP_PORT, DB_APP_LOGIN, DB_APP_PWD et DB_NAME sont bien renseignées dans env/dev.
4. Développement de l'application¶
Commande rapide
Pour générer directement ce starter depuis un projet Forge vierge :
Le reste de ce chapitre détaille ce que cette commande fait étape par étape.
4.1 Ce que l'on apprend¶
-
Modèle canonique
Créer une entité avec
forge make:entity, puis complétercontact.json. -
Génération contrôlée
Prévisualiser avec
--dry-run, puis générercontact.sqletcontact_base.py. -
Base de données
Appliquer le SQL avec
forge db:applysur une base de développement. -
CRUD explicite
Générer contrôleur, modèle SQL, formulaire et templates avec
forge make:crud Contact.
4.2 Parcours de développement¶
flowchart TD
A["forge make:entity"] --> B["édition de contact.json"]
B --> C["forge check:model"]
C --> D["forge build:model --dry-run"]
D --> E["forge build:model"]
E --> F["contact.sql + contact_base.py"]
F --> G["forge db:apply"]
G --> H["forge make:crud --dry-run"]
H --> I["forge make:crud"]
I --> J["contrôleur · modèle · formulaire · templates"]
J --> K["copie des routes → mvc/routes.py"]
Principe Forge
Forge ne saute pas directement à une application terminée. Il produit des fichiers lisibles, puis le développeur les câble explicitement.
5. Navigation de l'application¶
5.1 Routes fonctionnelles attendues¶
| Route | Méthode | Rôle |
|---|---|---|
/contacts |
GET |
Liste des contacts |
/contacts/new |
GET |
Formulaire de création |
/contacts |
POST |
Création d'un contact |
/contacts/{id} |
GET |
Détail d'un contact |
/contacts/{id}/edit |
GET |
Formulaire de modification |
/contacts/{id} |
POST |
Mise à jour d'un contact |
/contacts/{id}/delete |
POST |
Suppression d'un contact |
Ordre des routes
/contacts/new doit rester déclaré avant /contacts/{id} dans les routes afin d'éviter que new soit interprété comme un identifiant.
5.2 Schéma de navigation¶
flowchart TD
A["/contacts<br/>liste"] -->|"Nouveau contact"| B["/contacts/new<br/>formulaire de création"]
A -->|"Voir"| C["/contacts/{id}<br/>détail"]
A -->|"Modifier"| D["/contacts/{id}/edit<br/>formulaire de modification"]
C -->|"Supprimer en POST"| E["/contacts/{id}/delete"]
6. Charte graphique¶
Le starter utilise une charte volontairement simple. Les couleurs ci-dessous correspondent aux classes Tailwind utilisées dans les vues générées.
| Usage | Couleur | Code | Aperçu |
|---|---|---|---|
| Fond des pages de formulaire et de liste | Slate très clair | #F8FAFC |
|
Barre supérieure dans mvc/views/layouts/app.html |
Slate très foncé | #0F172A |
|
| Actions principales | Orange Forge | #EA580C |
|
| Survol des actions principales | Orange Forge foncé | #C2410C |
|
| Actions secondaires : retour, annulation | Gris clair | #E2E8F0 |
|
| Texte principal | Slate foncé | #0F172A |
|
| Texte secondaire | Slate moyen | #64748B |
|
| Cartes de formulaire et de détail | Blanc | #FFFFFF |
|
| Bordures des cartes | Slate clair | #E2E8F0 |
|
| Message flash de succès | Vert clair | #DCFCE7 |
|
| Message flash d'erreur | Rouge clair | #FEE2E2 |
Objectif de la charte
Le but n'est pas de créer un thème complet, mais d'obtenir une interface lisible et facile à modifier.
7. Modèle de données¶
7.1 Fichier canonique¶
Fichier à modifier :
{
"format_version": 1,
"entity": "Contact",
"table": "contact",
"description": "Contacts — starter niveau 1",
"fields": [
{
"name": "id",
"sql_type": "INT",
"primary_key": true,
"auto_increment": true
},
{
"name": "nom",
"sql_type": "VARCHAR(80)",
"constraints": {
"not_empty": true,
"max_length": 80
}
},
{
"name": "prenom",
"sql_type": "VARCHAR(80)",
"constraints": {
"not_empty": true,
"max_length": 80
}
},
{
"name": "email",
"sql_type": "VARCHAR(120)",
"unique": true,
"constraints": {
"not_empty": true,
"max_length": 120
}
},
{
"name": "telephone",
"sql_type": "VARCHAR(20)",
"nullable": true,
"constraints": {
"max_length": 20
}
}
]
}
7.2 Ce que Forge génère depuis ce JSON¶
flowchart TD
A["contact.json<br/>source canonique"] --> B["forge build:model"]
B --> C["contact.sql<br/>structure SQL visible"]
B --> D["contact_base.py<br/>classe Python régénérable"]
A -.-> E["contact.py<br/>logique métier manuelle préservée"]
Contrainte unique sur l'email
La contrainte unique: true empêche deux contacts d'utiliser le même email. Dans ce starter, cette contrainte est principalement portée par la base MariaDB. Si un doublon est saisi, la base peut refuser l'insertion ou la mise à jour.
Règle de modification
On modifie le JSON et le fichier métier manuel contact.py. On évite de modifier directement les fichiers régénérables comme contact.sql et contact_base.py.
Sous le capot — ce que Forge a produit¶
Vue synthétique¶
| Étape | Commande | Produit ou vérifie |
|---|---|---|
| 1 | forge make:entity Contact --no-input |
Structure de l'entité |
| 2 | Modifier contact.json |
Modèle canonique complet |
| 3 | forge check:model |
Cohérence des JSON |
| 4 | forge build:model --dry-run |
Prévisualisation du modèle généré |
| 5 | forge build:model |
contact.sql et contact_base.py |
| 6 | forge db:apply |
Table SQL dans MariaDB |
| 7 | forge make:crud Contact --dry-run |
Prévisualisation du CRUD |
| 8 | forge make:crud Contact |
Contrôleur, modèle SQL, formulaire et vues |
make:entity¶
Crée la structure de départ. Le fichier manuel contact.py n'est pas écrasé lors des régénérations.
mvc/entities/contact/
├── __init__.py
├── contact.json
├── contact.sql
├── contact_base.py
└── contact.py
check:model et build:model¶
forge check:model # vérifie sans écrire
forge build:model --dry-run # prévisualise
forge build:model # génère contact.sql et contact_base.py
SQL produit :
CREATE TABLE IF NOT EXISTS contact (
Id INT NOT NULL AUTO_INCREMENT,
Nom VARCHAR(80) NOT NULL,
Prenom VARCHAR(80) NOT NULL,
Email VARCHAR(120) NOT NULL,
UNIQUE KEY uk_contact_email (Email),
Telephone VARCHAR(20) NULL,
PRIMARY KEY (Id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
Fichier régénérable
contact_base.py est régénérable — ne pas y écrire de logique métier. La logique va dans contact.py.
db:apply¶
Applique contact.sql sur la base MariaDB configurée dans env/dev.
make:crud¶
flowchart TD
A["forge make:crud Contact"] --> B["contact_controller.py"]
A --> C["contact_model.py"]
A --> D["contact_form.py"]
A --> E["views/contact/*.html"]
B --> B1["reçoit les requêtes<br/>et choisit la réponse"]
C --> C1["contient les requêtes<br/>SQL explicites"]
D --> D1["lit et valide<br/>les données du formulaire"]
E --> E1["affiche la liste,<br/>le formulaire et le détail"]
Requêtes SQL générées dans contact_model.py :
SELECT_ALL = "SELECT * FROM contact ORDER BY Id"
SELECT_BY_ID = "SELECT * FROM contact WHERE Id = ?"
INSERT = "INSERT INTO contact (Nom, Prenom, Email, Telephone) VALUES (?, ?, ?, ?)"
UPDATE = "UPDATE contact SET Nom = ?, Prenom = ?, Email = ?, Telephone = ? WHERE Id = ?"
DELETE = "DELETE FROM contact WHERE Id = ?"
Responsabilité du développeur
Les routes restent à déclarer explicitement dans mvc/routes.py.
Copier dans mvc/routes.py après la génération du CRUD :
from mvc.controllers.contact_controller import ContactController
# Routes protégées par défaut.
# Pour un test local sans authentification :
# with router.group("/contacts", public=True, csrf=False) as g:
with router.group("/contacts") as g:
g.add("GET", "", ContactController.index, name="contact_index")
g.add("GET", "/new", ContactController.new, name="contact_new")
g.add("POST", "", ContactController.create, name="contact_create")
g.add("GET", "/{id}", ContactController.show, name="contact_show")
g.add("GET", "/{id}/edit", ContactController.edit, name="contact_edit")
g.add("POST", "/{id}", ContactController.update, name="contact_update")
g.add("POST", "/{id}/delete", ContactController.destroy, name="contact_destroy")
À ne pas inverser
/new doit rester déclaré avant /{id} pour éviter que new soit interprété comme un identifiant.
Fichiers canoniques et générés¶
| Fichier | Nature | Rôle |
|---|---|---|
mvc/entities/contact/contact.json |
Canonique | Source à modifier |
mvc/entities/contact/contact.sql |
Généré | SQL de création de la table |
mvc/entities/contact/contact_base.py |
Généré | Classe de base régénérable |
mvc/entities/contact/contact.py |
Manuel | Extension métier préservée |
mvc/entities/contact/__init__.py |
Manuel | Initialisation du module |
Fichiers CRUD créés s'ils sont absents¶
| Fichier | Rôle |
|---|---|
mvc/controllers/contact_controller.py |
Contrôleur HTTP du CRUD |
mvc/models/contact_model.py |
Requêtes SQL explicites |
mvc/forms/contact_form.py |
Formulaire et validation |
mvc/views/layouts/app.html |
Layout commun |
mvc/views/contact/index.html |
Liste des contacts |
mvc/views/contact/show.html |
Détail d'un contact |
mvc/views/contact/form.html |
Création et modification |
mvc/routes.py |
Fichier à modifier manuellement |
Arborescence¶
mvc/
├── entities/
│ └── contact/
│ ├── contact.json # source canonique
│ ├── contact.sql # SQL généré
│ ├── contact_base.py # classe générée
│ ├── contact.py # classe métier manuelle
│ └── __init__.py
│
├── controllers/
│ └── contact_controller.py # logique HTTP du CRUD
│
├── models/
│ └── contact_model.py # requêtes SQL explicites
│
├── forms/
│ └── contact_form.py # validation du formulaire
│
├── views/
│ ├── layouts/
│ │ └── app.html # layout commun
│ └── contact/
│ ├── index.html # liste
│ ├── form.html # création / modification
│ └── show.html # détail
│
└── routes.py # routes à compléter manuellement
| Classe | Origine | Rôle |
|---|---|---|
ContactBase |
Générée depuis le JSON | Propriétés, validations simples, conversion dictionnaire |
Contact |
Manuelle | Logique métier spécifique |
ContactForm |
Générée par le CRUD | Lecture et validation du formulaire |
ContactController |
Généré par le CRUD | Actions index, new, create, show, edit, update, destroy |
BaseController |
Core Forge | Rendu HTML, redirections, flash, erreurs de validation |
Cycle d'une création de contact¶
flowchart TD
A([Navigateur]) -->|"POST /contacts"| B["mvc/routes.py"]
B --> C["ContactController.create(request)"]
C --> D["ContactForm.from_request(request)"]
D --> E{"form.is_valid()"}
E -->|non| F["contact/form.html\navec les erreurs"]
E -->|oui| G["add_contact(form.cleaned_data)"]
G --> H[(MariaDB)]
H --> I["redirect_with_flash → /contacts"]
Exemple — création¶
form = ContactForm.from_request(request)
if not form.is_valid():
return BaseController.validation_error(
"contact/form.html",
context={"form": form, "action": "/contacts", "titre": "Nouveau contact"},
request=request,
)
add_contact(form.cleaned_data)
return BaseController.redirect_with_flash(request, "/contacts", "Contact créé.")
Fonctions SQL du modèle¶
À retenir
Le formulaire ne va pas directement en base. Il passe par le contrôleur, puis par le modèle SQL.
Quatre fichiers générés par forge make:crud :
mvc/views/layouts/app.html
mvc/views/contact/index.html
mvc/views/contact/form.html
mvc/views/contact/show.html
Héritage Jinja2¶
flowchart TD
A["layouts/app.html"] --> D["block content"]
E["contact/index.html"] --> D
F["contact/form.html"] --> D
G["contact/show.html"] --> D
index.html — liste¶
{% extends "layouts/app.html" %}
{% block content %}
<h1>Contacts</h1>
<a href="/contacts/new">Nouveau contact</a>
{% for contact in contacts %}
<article>
<h2>{{ contact.Nom }} {{ contact.Prenom }}</h2>
<p>{{ contact.Email }}</p>
<a href="/contacts/{{ contact.Id }}">Voir</a>
<a href="/contacts/{{ contact.Id }}/edit">Modifier</a>
</article>
{% endfor %}
{% endblock %}
Les noms contact.Nom, contact.Prenom… correspondent aux colonnes SQL retournées par cursor(dictionary=True).
form.html — création et modification¶
{% extends "layouts/app.html" %}
{% block content %}
<h1>{{ titre }}</h1>
<form method="post" action="{{ action }}">
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
<label>Nom</label>
<input type="text" name="nom" value="{{ form.value('nom') }}">
<label>Prénom</label>
<input type="text" name="prenom" value="{{ form.value('prenom') }}">
<label>Email</label>
<input type="email" name="email" value="{{ form.value('email') }}">
<label>Téléphone</label>
<input type="text" name="telephone" value="{{ form.value('telephone') }}">
<button type="submit">Enregistrer</button>
</form>
{% endblock %}
Les noms de champs (nom, prenom…) sont les noms Python du JSON canonique. Les colonnes SQL (Nom, Prenom…) s'utilisent dans les vues de liste et de détail.
show.html — détail¶
{% extends "layouts/app.html" %}
{% block content %}
<h1>{{ contact.Nom }} {{ contact.Prenom }}</h1>
<p>Email : {{ contact.Email }}</p>
<p>Téléphone : {{ contact.Telephone }}</p>
<a href="/contacts/{{ contact.Id }}/edit">Modifier</a>
<form method="post" action="/contacts/{{ contact.Id }}/delete">
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
<button type="submit">Supprimer</button>
</form>
{% endblock %}
Suppression en POST
La suppression utilise POST pour éviter une suppression accidentelle par navigation GET.
13. Test navigateur¶
13.1 Scénario nominal¶
| Étape | Action | Résultat attendu |
|---|---|---|
| 1 | Lancer python app.py |
Serveur HTTPS local lancé |
| 2 | Ouvrir /contacts |
Liste affichée |
| 3 | Cliquer sur "Nouveau contact" | Formulaire affiché |
| 4 | Soumettre le formulaire vide | Erreurs visibles |
| 5 | Créer un contact valide | Retour à la liste |
| 6 | Vérifier le message flash | Message de succès affiché |
| 7 | Ouvrir le détail du contact | Détail affiché |
| 8 | Modifier le contact | Données mises à jour |
| 9 | Supprimer le contact | Suppression effectuée |
| 10 | Revenir à la liste | Contact supprimé absent |
13.2 Limites du starter¶
Limites assumées
- Pas d'authentification dédiée.
- Pas de recherche avancée.
- Pas de pagination générée automatiquement.
- Pas de validation métier au-delà des contraintes simples.
- Pas de relation : ce starter est volontairement mono-entité.
- Pas d'ORM : les requêtes SQL restent visibles dans
mvc/models/contact_model.py.
14. Vérification finale du starter¶
La vérification finale sert à contrôler trois choses : l'environnement Forge, les routes et le comportement réel dans le navigateur.
14.1 Schéma de vérification¶
flowchart TD
A["forge doctor"] --> B["environnement du projet OK"]
B --> C["forge routes:list"]
C --> D["routes /contacts présentes"]
D --> E["python app.py"]
E --> F["serveur HTTPS local lancé"]
F --> G["navigateur"]
G --> H["CRUD complet vérifié"]
14.2 Vérifier l'environnement Forge¶
Cette commande permet de vérifier que le projet est correctement installé et que Forge trouve les éléments nécessaires à son fonctionnement.
14.3 Vérifier les routes¶
Les routes suivantes doivent apparaître ou être équivalentes selon l'affichage de Forge :
GET /contacts
GET /contacts/new
POST /contacts
GET /contacts/{id}
GET /contacts/{id}/edit
POST /contacts/{id}
POST /contacts/{id}/delete
Erreur classique
Si /contacts/new n'apparaît pas avant /contacts/{id}, il faut vérifier l'ordre des routes dans mvc/routes.py.
14.4 Lancer le serveur local¶
Ouvrir ensuite dans le navigateur :
14.5 Scénario de recette¶
1. Ouvrir /contacts
2. Cliquer sur "Nouveau contact"
3. Soumettre le formulaire vide
4. Vérifier l'affichage des erreurs
5. Créer un contact valide
6. Vérifier le retour à la liste
7. Vérifier le message flash
8. Ouvrir le détail du contact
9. Modifier le contact
10. Supprimer le contact
11. Vérifier que le contact supprimé n'apparaît plus dans la liste
14.6 Erreurs fréquentes¶
| Symptôme | Cause probable | Fichier ou commande à vérifier |
|---|---|---|
/contacts affiche une erreur 404 |
Routes non copiées | mvc/routes.py |
/contacts/new est interprété comme un identifiant |
Ordre des routes incorrect | Placer /new avant /{id} |
| Erreur de connexion MariaDB | Variables incorrectes | env/dev |
Table contact absente |
SQL non appliqué | forge db:apply |
Erreur sur contact.Nom dans la vue |
Colonnes SQL différentes | contact.sql, contact_model.py, template Jinja |
| Formulaire sans protection CSRF | Champ caché absent | contact/form.html |
| Doublon email refusé | Contrainte unique: true |
Vérifier la donnée saisie |
Reconstruction¶
Le starter peut être reconstruit de deux façons.
Génération automatique¶
Depuis un projet Forge vierge, après configuration de env/dev et initialisation de la base :
Alias disponibles :
Pour prévisualiser sans écrire :
Pour générer des routes publiques de test (sans authentification) :
Pour initialiser la base puis construire le starter en une seule commande :
Pour reconstruire un starter déjà présent :
Attention avec --force
L'option --force reconstruit uniquement les fichiers du starter Contacts : mvc/entities/contact/, mvc/controllers/contact_controller.py, mvc/models/contact_model.py, mvc/forms/contact_form.py, mvc/views/contact/ et le bloc de routes marqué. Elle ne touche pas les autres entités ni le reste de mvc/routes.py.
Reconstruction manuelle¶
Le fichier de reconstruction pas à pas est disponible dans starters/01-contact-simple/rebuild.md.
Dépannage rapide¶
| Erreur | Cause probable | Correction |
|---|---|---|
forge: command not found |
pipx n'est pas dans le PATH |
pipx ensurepath puis exec $SHELL -l |
No module named venv |
python3-venv absent |
sudo apt install python3-venv |
mariadb_config not found |
dépendances MariaDB dev absentes | sudo apt install libmariadb-dev pkg-config |
Access denied for user 'root'@'localhost' |
mauvais mot de passe root ou root configuré en unix_socket |
vérifier le mot de passe, ou tester sudo mariadb |
mariadb: command not found |
client MariaDB absent | sudo apt install mariadb-client |
| erreur de compilation Python | outils de build absents | sudo apt install build-essential pkg-config libmariadb-dev |
| erreur certificat HTTPS | openssl absent |
sudo apt install openssl |