1. Distinguez la lecture de la création
La route GET demande une liste et n’envoie aucun corps. La route POST reçoit au contraire un objet JSON. Le chemin reste /training/api/notes ; la méthode HTTP indique à Odoo laquelle des deux fonctions doit répondre.
cURL ── POST /training/api/notes ──▶ Odoo
── { "title": "...", "body": "..." }
Odoo ── ORM : training.note.create(...) ──▶ PostgreSQL
cURL ◀── 201 Created et la note créée ───── Odoo2. Ajoutez la route POST
Remplacez controllers/notes_api.py par cette version complète. Elle conserve la lecture ORM de l’étape précédente et ajoute une seconde route pour la création.
from odoo import http
from odoo.http import request
class TrainingNotesApiController(http.Controller):
@http.route(
"/training/api/notes",
type="http",
auth="public",
methods=["GET"],
)
def list_notes(self):
notes = request.env["training.note"].sudo().search_read(
fields=["id", "title", "body"],
order="id desc",
limit=20,
)
for note in notes:
note["body"] = note["body"] or ""
return request.make_json_response({
"notes": notes,
"count": len(notes),
})
@http.route(
"/training/api/notes",
type="http",
auth="public",
methods=["POST"],
csrf=False,
)
def create_note(self):
payload = request.get_json_data()
note = request.env["training.note"].sudo().create({
"title": payload["title"],
"body": payload.get("body", ""),
})
return request.make_json_response(
{
"note": {
"id": note.id,
"title": note.title,
"body": note.body or "",
}
},
status=201,
)request.get_json_data() lit le corps JSON. L’appel training.note.create(...) passe ensuite par l’ORM : le nouvel enregistrement est réellement écrit dans PostgreSQL. La réponse reprend les valeurs du record créé, y compris l’identifiant attribué par la base.
Rappel CSRF : un jeton CSRF empêche un autre site d’utiliser à votre insu la session ouverte dans votre navigateur pour envoyer un formulaire à Odoo. cURL n’utilise pas cette session ni ce formulaire ; csrf=False est donc nécessaire pour ce POST JSON local. Cette désactivation concerne uniquement cette route de démonstration locale.
3. Redémarrez Odoo
Action qui redémarre Odoo : arrêtez puis relancez votre processus Odoo. Attendez que les journaux indiquent que le serveur est prêt. Vous avez modifié du code Python ; une actualisation du navigateur ne suffit pas.
4. Envoyez la nouvelle note avec cURL
Exécutez la commande adaptée à votre terminal. L’en-tête annonce un corps JSON. L’option --data contient uniquement le titre et le contenu.
curl -i -X POST http://127.0.0.1:8069/training/api/notes \
-H "Content-Type: application/json" \
--data '{"title":"Note créée avec cURL","body":"Cette note vient de l’ORM Odoo."}'curl.exe -i -X POST http://127.0.0.1:8069/training/api/notes `
-H "Content-Type: application/json" `
--data '{"title":"Note créée avec cURL","body":"Cette note vient de l’ORM Odoo."}'La première ligne doit contenir 201 Created. Le corps reprend le titre et le contenu envoyés. La valeur de id dépend de votre base.
{
"note": {
"id": 13,
"title": "Note créée avec cURL",
"body": "Cette note vient de l’ORM Odoo."
}
}5. Retrouvez le même enregistrement
Répétez le GET de l’étape précédente. La note intitulée Note créée avec cURL doit apparaître en premier, car la route trie les identifiants du plus récent au plus ancien.
curl http://127.0.0.1:8069/training/api/notescurl.exe http://127.0.0.1:8069/training/api/notesOuvrez aussi Notes de formation → Notes. Vous devez y retrouver exactement le même titre, le même contenu et le même identifiant. Le navigateur Odoo et cURL ont utilisé deux interfaces différentes, mais l’ORM a écrit un seul record dans la même table PostgreSQL.
Cette route utilise temporairement auth="public" et sudo(). Toute personne pouvant joindre l’adresse pourrait donc lire ou créer des notes. Gardez cette version uniquement sur votre machine d’exercice. La section 3 la remplace par une route Bearer sans élévation de privilèges ; la section 4 ajoute ensuite la validation complète du corps.
Point de contrôle — vérifiez les trois interfaces
Le POST répond avec 201 Created. Le GET renvoie la nouvelle note, puis la liste Odoo montre le même enregistrement persisté dans PostgreSQL.