Académique Documents
Professionnel Documents
Culture Documents
Badiou OURO-BANG’NA
COURS DE
DEVELOPPE-
MENT PY-
THON AVEC LE
FRAMEWORK
FLASK
MISE EN PLACE DES API (APPLICATION PROGRAM-
MING INERFACE) AVEC UN FRAMEWORK PYTHON
(Flask)
OURO-BANG’NA Badiou
Le volume horaire pour terminer ce cours est de 24h – 30h
Contenu du cours
Code de démarrage..................................................................................................................... 30
Installation de Flask-Migrate ......................................................................................................... 34
Exemple de migration de données ................................................................................................. 34
Ce que peut faire une api concrètement ............................................................................. 37
1- Structure d’une requête http ................................................................................................ 38
2- Liste des méthodes .............................................................................................................. 38
3- Liste des réponses http (Status Code).................................................................................. 39
4- Les Status code les plus connus : ........................................................................................ 39
1- Commande curl ................................................................................................................... 40
2- Utilisation de Postman......................................................................................................... 40
Partie I :
SQL et Modélisation de
données pour le Web
Besoin d'un rafraîchissement sur ceux-ci? Découvrez ces cours et les programmes Nanodegree.
1. Introduction à la programmation Python
2. Atelier Shell (ligne de commande) ou principes de base de la ligne de commande Linux
3. SQL pour l'analyse de données et introduction aux bases de données relationnelles
Outils requis
Avant de commencer, assurons-nous que tous les outils nécessaires sont installés. Elles sont:
1. Un éditeur de code
2. Une interface de ligne de commande (CLI) comme Terminal ou GitBash.
3. Python v3.7+ et gestionnaire de packages Python pip
4. Un navigateur Internet
1. Éditeur de code
Vous avez probablement déjà un éditeur de code installé sur votre ordinateur ; sinon, vous aurez besoin
d'en obtenir un maintenant pour suivre avec nous pour le reste de ce cours. Je préfère Visual Studio
Code (VS Code)
2. Interface de ligne de commande (CLI)
Les vidéos de démonstration de ce cours utilisent quelques commandes Linux et Git. Vous devez donc
disposer d'une interface de ligne de commande (CLI) capable d'exécuter des commandes Linux et Git.
a- Utilisateurs Linux/Mac
Linux et Mac OS ont une CLI intégrée appelée "Terminator" ou "Terminal", respectivement, qui prend
en charge la plupart des commandes Linux et Git. Vous n'avez pas besoin d'installer d'autre CLI.
b- Utilisateurs Windows
La CLI par défaut dans Windows est CMD (Invite de commandes). Par défaut, CMD ne peut exécuter ni
Linux ni aucune commande Git. Par conséquent, vous avez besoin d'un moyen d'activer l’environne-
ment Linux sur Windows. L'une des options consiste à utiliser l’outils de ligne de commande Git Bash,
fourni par Git. Git Bash est installé lorsque vous installez Git pour Windows .
Il est difficile de donner une définition exacte de la notion de base de données. Une définition très générale
pourrait être : Un ensemble organisé d'informations avec un objectif commun.
Peu importe le support utilisé pour rassembler et stocker les données (papier, fichiers, etc.), dès lors que
des données sont rassemblées et stockées d'une manière organisée dans un but spécifique, on parle de base
de données.
Plus précisément, on appelle base de données un ensemble structuré et organisé permettant le stockage de
grandes quantités d'informations afin d'en faciliter l'exploitation (ajout, mise à jour, recherche de don-
nées). Bien entendu, dans le cadre de ce cours, nous nous intéressons aux bases de données informatisées.
Une base de données relationnelle est une base de données structurée suivant les principes de l'algèbre
relationnelle.
Le père des bases de données relationnelles est Edgar Frank Codd. Chercheur chez IBM à la fin des années
1960.
3- Clé primaire
- La clé primaire est l'identifiant unique de toute la ligne, faisant référence à une ou plusieurs co-
lonnes.
- S'il existe plusieurs colonnes pour la clé primaire, l'ensemble de colonnes de clé primaire est ap-
pelé clé composite.
4- Clé étrangère
- Une clé primaire dans une autre table (étrangère).
- Les clés étrangères sont utilisées pour mapper les relations entre les tables.
Questions :
- Un serveur est un programme centralisé qui communique sur un réseau (comme Internet)
pour servir les clients.
- Un client est un programme (comme le navigateur Web de votre ordinateur) qui peut de-
mander des données à un serveur. Lorsque vous accédez à une page Web dans votre naviga-
teur, votre navigateur (le client) fait une demande au serveur, qui renvoie ensuite les don-
nées de cette page.
-
Requêtes et réponses
- Un client envoie une requête au serveur
- Le travail du serveur est de répondre à la demande avec une réponse qu'il renvoie au client.
- Les demandes et les réponses sont servies via un protocole de communication, qui définit les
attentes et les règles relatives à la manière dont la communication se produit entre les serveurs et
les clients.
Un client de base de données est tout programme qui envoie des requêtes à une base de données
Dans certains cas, le client de base de données est un serveur Web ! Lorsque votre navigateur fait une
demande, le serveur Web agit en tant que serveur (répondant à cette demande), mais lorsque le serveur
Web demande des données à la base de données, il agit en tant que client pour cette base de données—et
la base de données est le serveur (car elle répond à la demande).
Ne laissez pas cela vous embrouiller. Fondamentalement, nous appelons les choses des clients lorsqu'ils
font une demande et des serveurs lorsqu'ils répondent à une demande. Étant donné qu'un serveur Web
peut faire les deux, il agit parfois en tant que serveur et parfois en tant que client.
C- TCP/IP
TCP/IP désigne communément une architecture réseau, mais cet acronyme désigne en fait 2 protocoles
étroitement liés : un protocole de transport, TCP (Transmission Control Protocol) qu’on utilise « par-des-
sus » un protocole réseau, IP (Internet Protocol). Ce qu’on entend par « modèle TCP/IP », c’est en fait
une architecture réseau en 4 couches dans laquelle les protocoles TCP et IP jouent un rôle prédominant,
car ils en constituent l’implémentation la plus courante. Par abus de langage, TCP/IP peut donc désigner
deux choses : le modèle TCP/IP et la suite de deux protocoles TCP et IP.
TCP/IP utilise :
1. TCP/IP est basé sur la connexion, ce qui signifie que toutes les communications
entre les parties sont organisées via une connexion. Une connexion est établie avant
le début de toute transmission de données.
2. Sur TCP/IP, nous aurons toujours besoin d’établir une connexion entre les clients et
les serveurs afin de permettre les communications. De plus:
3. Les livraisons via la connexion font l'objet d’un contrôle d'erreur : si des paquets
arrivent endommagés ou perdus, ils sont alors renvoyés (appelé retransmission).
4. La connexion démarre une session. Mettre fin à la connexion met fin à la session.
5. Dans une session de base de données, de nombreuses transactions peuvent se pro-
duire au cours d'une session donnée. Chaque transaction fonctionne pour valider les
modifications apportées à la base de données (mise à jour, insertion ou suppression
d'enregistrements).
D- Installation de PostgreSQL
Avant de pouvoir utiliser Postgres, nous devons l'installer. Vous avez peut-être déjà Postgres, par
exemple si vous êtes un utilisateur de MacOS, il est déjà installé sur votre machine. Mais juste au
cas où, voici quelques étapes pour le télécharger et l'installer.
Aller à la Postgres Télécharger la page et télécharger Postgres pour votre machine.
1. Pour MacOS, Postgres est déjà téléchargé. Homebrew est une voie populaire pour
installer Postgres. Voir cet aperçu sur l'installation de Postgres via Brew .
E- DBAPI
Nous voudrons parfois interagir avec notre base de données et utiliser ses résultats dans un langage
de programmation spécifique. Par exemple pour construire des applications Web ou des pipelines
de données dans un langage spécifique (Ruby, Python, Javascript, etc.). C'est là qu'interviennent les
DBAPI.
Une DBAPI :
- Fournit une interface standard pour un langage de programmation (comme Python) pour
parler à un serveur de base de données relationnelle.
- Est une bibliothèque de bas niveau pour écrire des instructions SQL qui se connectent à une
base de données
- Est également connu sous le nom d'adaptateurs de base de données.
- Installation de pyscopg2
python –version
Si l'installation normale ne fonctionne pas, vous pouvez également simplement installer la version
binaire à la place :
cursor = conn.cursor()
cur.close()
conn.close()
import psycopg2
connection = psycopg2.connect('dbname=example')
cursor = connection.cursor()
cursor.execute('''
CREATE TABLE table2 (
id INTEGER PRIMARY KEY,
completed BOOLEAN NOT NULL DEFAULT False
);
''')
cursor.execute('INSERT INTO table2 (id, completed) VALUES (%s, %s);', (1, True))
data = {
'id': 2,
'completed': False
}
cursor.execute(SQL, data)
connection.commit()
connection.close()
cursor.close()
SQLAlchemy est la bibliothèque open source la plus populaire pour travailler avec les bases de
données relationnelles de Python.
C'est un type de bibliothèque ORM , AKA une bibliothèque de Object-Relational Mapping, qui
fournit une interface pour utiliser la programmation orientée objet pour interagir avec une base de
données.
D’autres lanages de programmation utilisent aussi des ORM comme Eloquent pour Laravel PHP,
EntityFramework pour ASP.NET etc….
SQL SQLAlchemy
CREATE TABLE tweets ( Class Tweet :
id INTEGER PRIMARY KEY, def __init__(self,content) :
content VARCHAR(140) NOT NULL self.content=content
);
Alors :
- Les tables correspondent aux classes (SQLAlchemy)
- Les enregistrements de tables sont mappés sur les objets
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI']='postgresql://postgres:@localhost:5432/mabase
'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db=SQLAlchemy(app)
class Person(db.Model):
__tablename__ = 'persons'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(), nullable=False)
db.create_all()
@app.route('/')
def index():
return 'Je suis dans la joie!'
app.config['SQLALCHEMY_DATABASE_URI'] = database_path
- Initialisation de l'application
app = Flask(__name__) définit le nom de votre application sur le nom de votre module ("app" si
"app.py" est le nom de votre fichier).
- Utilisation de @app.route
@app.route('/')
def index():
...
Sous Windows :
set FLASK_APP=app.py
set FLASK_ENV=development
flask run
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://toto@localhost:5432/example'
db = SQLAlchemy(app)
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://test@localhost:5432/example'
db = SQLAlchemy(app)
class Person(db.Model):
__tablename__ = 'persons'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(), nullable=False)
db.create_all()
@app.route('/')
def index():
person = Person.query.first()
return 'Hello ' + person.name
$ python3
>>> from flask_hello_app import Person, db
>>> Person.query.all()
>>> Person.query.first()
>>> query = Person.query.filter(Person.name == 'OURO-BANG\’NA Badiou')
>>> query.first()
>>> query.all()
Ensuite, créez une instance de person, en définissant ses attributs et en lui donnant la valeur d'une
variable person
>>> db.session.add(person)
Cela mettra en file d'attente une INSERT INTO persons (name) VALUES ('Badiou');
instruction dans une transaction gérée par db.session .
On peut alors appeler db.session.commit()
>>> db.session.commit()
et cet enregistrement de personne existera désormais dans notre persons table, dans notre base de
données ! Vous pouvez vérifier cela dans psql en exécutant une SELECT * from persons; com-
mande à partir de psql.
En résumé
Nous pouvons insérer de nouveaux enregistrements dans la base de données en utilisant
SQLAlchemy en exécutant :
person = Person(name='Amy')
db.session.add(person)
db.session.commit()
qui construira une transaction à insérer dans une instance de person de notre modèle/table et la vali-
dera l’enregistrement dans la base de données lors de l'appel de commit() .
Méthodes de requête
Voici quelques méthodes de requête utiles à connaître.
all()
MyModel.query.all()
Même chose que faire un SELECT * , récupérer tous les enregistrements de la table du modèle. Ren-
voie une liste d'objets.
first()
MyModel.query.first()
Récupère uniquement le premier résultat. Renvoie l'un None ou l' autre ou un objet s'il est trouvé
Filter_by
MyModel.query.filter_by(my_table_attribute='some value')
Similaire à l'exécution d'une SELECT * from ... WHERE instruction SQL pour selectionner les don-
nées par attributs nommés.
filter
Exemples:
MyModel.query.filter(MyOtherModel.some_attr='some value')
OrderItem.query.filter(Product.id=3)
Similaire à filter_by , vous spécifiez des attributs sur un modèle donné. Il est plus flexible que
l'utilisation filter_by lui-même et est particulièrement utile lors d'une requête à partir d'une table
jointe où vous souhaitez filtrer par attributs qui s'étendent sur plusieurs modèles.
Vous pouvez filtrer sur l'égalité, l'inégalité, comme le filtrage (correspondance de chaîne "fuzzy"),
IN, NOT IN, NULL, NOT NULL, etc. Assurez-vous de consulter la référence de la documentation
SQLAlchemy sur les opérateurs de filtrage courants ici .
Commande
Order_by
MyModel.order_by(MyModel.created_at)
MyModel.order_by(db.desc(MyModel.created_at))
Pour ordonner les résultats par un attribut donné. Utilisez db.desc pour ordonner par ordre décrois-
sant.
limit
Order.query.limit(100).all()
limit(max_num_rows) limite le nombre d'enregistrements renvoyés par la requête. ala LIMIT en SQL.
Agrégats
count()
Exemple:
query = Task.query.filter(completed=True)
query.count()
Renvoie un entier défini sur le nombre d'enregistrements qui auraient été renvoyés en exécutant la
requête.
get()
Obtenir l'objet par ID
model_id = 3
MyModel.query.get(model_id)
Renvoie l'objet suite à l'interrogation du modèle par sa clé primaire.
Exemple:
query = Task.query.filter_by(category='Archived')
query.delete()
delete() effectue une opération de suppression en bloc qui supprime chaque enregistrement corres-
pondant à la requête donnée.
Requêtes de jointure
Exemple:
Driver.query.join('vehicules')
La requête a une méthode join(<table_name>) pour joindre un modèle à une autre table.
Récapitulatif :
I- ARCHITECTURE MVC
Modèle-vue-contrôleur ou MVC est un pattern d’architecture logicielle destiné aux interfaces gra-
phiques lancé en 1978 et très populaire pour les applications web. Le motif est composé de trois
types de modules ayant trois responsabilités différentes : les modèles, les vues et les contrôleurs.
app = Flask(__name__)
@app.route('/')
def index():
return render_template('index.html', data=[{
'description': 'Todo 1'
}, {
'description': 'Todo 2'
}, {
'description': 'Todo 3'
}])
Créer todoapp/templates/index.html
<html>
<head>
<title>Todo App</title>
</head>
<body>
<ul>
{% for d in data %}
<li>{{ d.description }}</li>
{% endfor %}
</ul>
</body>
</html>
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgres://udacitystudios@localhost:5432/todoa
pp'
db = SQLAlchemy(app)
class Todo(db.Model):
__tablename__ = 'todos'
id = db.Column(db.Integer, primary_key=True)
description = db.Column(db.String(), nullable=False)
def __repr__(self):
return f'<Todo {self.id} {self.description}>'
db.create_all()
@app.route('/')
def index():
return render_template('index.html', data=Todo.query.all())
todoapp/templates/index.html
<html>
<head>
<title>Todo App</title>
</head>
<body>
<ul>
{% for d in data %}
<li>{{ d.description }}</li>
{% endfor %}
</ul>
</body>
</html>
Données de formulaire
request.form.get('<name>') lit le value à partir d'un champ de saisie de formulaire (saisie de
texte, saisie de nombre, saisie de mot de passe, etc.) par l’attribut name sur l'élément HTML d'entrée.
JSON
request.data récupère JSON sous forme de chaîne . Ensuite, nous prendrions cette chaîne et la trans-
formerions en python en appelant json.loads la request.data chaîne pour la transformer en listes
et dictionnaires en Python.
Formulaire de base
<html>
<head>
<title>Todo App</title>
</head>
<body>
<form method="post" action="/todos/create">
<input type="text" name="description" />
<input type="submit" value="Create" />
</form>
<ul>
{% for d in data %}
<li>{{ d.description }}</li>
{% endfor %}
</ul>
</body>
</html>
Il faut modifier app.py de façon à pouvoir enregistrer les données dans la base de données :
Le résultat final doit ressembler à ceci :
import sys
try:
todo = Todo(description=description)
db.session.add(todo)
db.session.commit()
except:
db.session.rollback()
error=True
print(sys.exc_info())
finally:
db.session.close()
# ...
@app.route('/todos/create', method=['POST'])
def create_todo():
error = False
body = {}
try:
description = request.get_json()['description']
todo = Todo(description=description)
db.session.add(todo)
db.session.commit()
body['description'] = todo.description
except:
error = True
db.session.rollback()
print(sys.exc_info())
finally:
db.session.close()
if error:
abort (400)
else:
return jsonify(body)
S'entraîner
Implémentez ce modèle try-except-finally dans notre gestionnaire de route d'élément de création de
tâches.
Code de démarrage
app.py
from flask import Flask, render_template
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgres://udacitystudios@localhost:5432/todoa
pp'
db = SQLAlchemy(app)
class Todo(db.Model):
__tablename__ = 'todos'
id = db.Column(db.Integer, primary_key=True)
def __repr__(self):
return f'<Todo {self.id} {self.description}>'
db.create_all()
@app.route('/todos/create', method=['POST'])
def create_todo():
description = request.get_json()['description']
todo = Todo(description=description)
db.session.add(todo)
db.session.commit()
return jsonify({
'description': todo.description
})
@app.route('/')
def index():
return render_template('index.html', data=Todo.query.all())
modèles/index.html
<html>
<head>
<title>Todo App</title>
<style>
#error {
display: none;
}
</style>
</head>
<body>
<div id="error" class="hidden">Something went wrong!</div>
<form id="form" method="post" action="/todos/create">
<input type="text" id="description" name="description" />
<input type="submit" value="Create" />
</form>
<ul id="todos">
{% for d in data %}
<li>{{ d.description }}</li>
{% endfor %}
</ul>
<script>
const descInput = document.getElementById('description');
document.getElementById('form').onsubmit = function(e) {
e.preventDefault();
const desc = descInput.value;
descInput.value = '';
fetch('/todos/create', {
method: 'POST',
body: JSON.stringify({
'description': desc,
}),
headers: {
'Content-Type': 'application/json',
}
})
.then(response => response.json())
.then(jsonResponse => {
console.log('response', jsonResponse);
li = document.createElement('li');
li.innerText = desc;
document.getElementById('todos').appendChild(li);
document.getElementById('error').className = 'hidden';
})
.catch(function() {
document.getElementById('error').className = '';
})
}
</script>
</body>
</html>
Les erreurs à notre schéma de base de données sont très coûteuses. L'ensemble de l'application peut tom-
ber en panne, nous voulons donc annuler rapidement les modifications, et tester les modifications avant
de les faire.
Une migration est un fichier qui garde une trace des modifications apportées à notre schéma de base de
données (structure de notre base de données).
Offre un contrôle de version sur notre schéma.
Installation de Flask-Migrate
Voici un exemple d'application qui gère les migrations de bases de données via Flask-Migrate :
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///app.db'
db = SQLAlchemy(app)
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(128))
Avec l'application ci-dessus, vous pouvez créer un référentiel de migration avec la commande sui-
vante :
$ flask db init
Cela ajoutera un dossier de migrations à votre application. Le contenu de ce dossier doit être ajouté
au contrôle de version avec vos autres fichiers source.
Le script de migration doit être examiné et modifié, car Alembic ne détecte actuellement pas toutes
les modifications que vous apportez à vos modèles. En particulier, Alembic est actuellement inca-
pable de détecter les changements de nom de table, les changements de nom de colonne ou les con-
traintes nommées anonymement. Un résumé détaillé des limitations peut être trouvé dans la docu-
mentation de génération automatique d'Alembic . Une fois finalisé, le script de migration doit égale-
ment être ajouté au contrôle de version.
$ flask db upgrade
Ensuite, chaque fois que les modèles de base de données changent, répétez les commandes migrate
et upgrade.
Pour synchroniser la base de données dans un autre système, actualisez simplement le dossier migra-
tions à partir du contrôle de source et exécutez la commande upgrade.
Pour voir toutes les commandes qui sont disponibles cette exécution commande:
$ flask db --help
Notez que le script d'application doit être défini dans la FLASK_APP variable d'environnement pour
que toutes les commandes ci-dessus fonctionnent, comme requis par le flaskscript de ligne de com-
mande.
Partie 2 :
Utiliser une API permet donc d’utiliser un programme existant plutôt que de le re-développer. C’est
donc un grand gain de temps à la clé.
Exemples d’API :
- PayPal
- Strike API
NB : Les protocoles utilisés par l’API pour envoyer des requêtes et recevoir les réponses sont le
TCP et HTTP.
C- RESTful
1. La particularité de cette architecture est que la partie serveur et la partie client communiquent
sans que le client ne connaisse la structure et le contenu des informations stockées sur le ser-
veur.
2. Une API est RESTful quand elle respecte le principe d'architecture REST. Ce principe d'ar-
chitecture s'applique aux services Web. La particularité principale de cette architecture est que
la partie serveur (l'API) et la partie client communiquent sans que le client ne connaisse la
structure et le contenu des informations stockées sur le serveur. La seule chose que les deux
parties de l'application connaissent est le média qu'elles utilisent pour communiquer.
3. Les applications REST s'appuient sur les verbes fournis par le protocole HTTP. Ce sont des
mots-clés qui définissent l'action que l'on souhaite effectuer sur une ressource. Les deux
principaux sont GET et POST mais il existe également PUT, DELETE et PATCH. Le média
peut être par exemple un fichier JSON ou XML.
4. Pour commencer la communication, le client va appeler l'URL racine de l'API, /. Requête :
GET /
Accept: application/json
200 : OK
201 : Created
304 : Not Modified
400 : Bad Request
401 : Unauthorized
404 : Not Found
405 : Method Not Allowed
500 : Internal Server Error
Ensuite, j'inclurai comment configurer l'application pour gérer une configuration spécialisée.
@app.route('/')
def hello_world():
return 'Hello, World!'
return app
Au lieu de renvoyer du texte, utilisez jsonify pour envoyer un objet contenant le message
return jsonify({'message':'Hello, World!'})
Pour Windows cmd, utilisez set au lieu d'export :
2- Utilisation de Postman
Postman est une application permettant d’envoyer des requêtes vers les API. Pour l’installer,
télécharger sur le lien suivant : https://www.postman.com/downloads/ . Actuellement, il existe une
version à intégrer avec le navigateur chrome.
Prenons un exemple de requête multi-origine : une page HTML est servie depuis http://domaine-
a.com contient un élément <img> src ciblant http://domaine-b.com/image.jpg. Aujourd'hui, de nom-
breuses pages web chargent leurs ressources (feuilles CSS, images, scripts) à partir de domaines sé-
parés (par exemple des CDN (Content Delivery Network en anglais ou « Réseau de diffusion de con-
tenu »).
def create_app(test_config=None):
app = Flask(__name__, instance_relative_config=True)
setup_db(app)
#CORS(app, resources={r"*/api/*" : {origins: '*'}})
CORS(app)
@app.after_request
def after_request(response):
response.headers.add('Access-Control-Allow-Headers', 'Content-Type, Autho
rization')
#@cross_origin
@app.route('/')
def hello_world():
return jsonify({'message':'HELLO, WORLD!'})
return app
I- Cas pratique
- Regarder l’API Plants sur https://github.com/badiou/plants_api.git
- Montrer le CORS
- Montrer le modèle
import unittest
import json
import os
from flask_sqlalchemy import SQLAlchemy
from flaskr import create_app
from models import setup_db, Plant
class PlanttestCase(unittest.TestCase):
"""This class represents the plant test case"""
def setUp(self):
"""Define test variables and initialize app."""
self.app = create_app()
self.client = self.app.test_client
self.database_name = "plants_database_test"
self.database_path = "postgresql://{}:{}@{}/{}".format(
'postgres', 'badiou', 'localhost:5432', self.database_name)
setup_db(self.app, self.database_path)
with self.app.app_context():
self.db = SQLAlchemy()
self.db.init_app(self.app)
# create all tables
self.db.create_all()
self.new_plant = {
'name': 'Champignon vénimeux',
'is_poisonous': True,
'scientific_name': 'Champi - Kilo Adansonia DIGITATA',
'primary_color': 'Green',
'state': 'TOGO'
}
def tearDown(self):
"""Executed after reach test"""
pass
"""
TODO
Write at least one test for each test for successful operation and for expected
errors.
"""
def test_get_all_plants(self):
res = self.client().get('/plants')
def test_paginate_plants(self):
res = self.client().get('/plants')
data = json.loads(res.data)
self.assertEqual(res.status_code, 200)
self.assertTrue(data['current_plants'])
self.assertTrue(data['current_plants'])
def test_delete_plant(self):
res=self.client().delete('/plants/101')
data=json.loads(res.data)
plant=Plant.query.filter(Plant.id == 101).one_or_none()
self.assertEqual(res.status_code, 200)
self.assertEqual(data['success'], True)
self.assertEqual(data['deleted'], 101)
self.assertTrue(data['plants'], True)
self.assertTrue(data['totals_plants'])
def test_plant_which_does_not_exist(self):
res=self.client().delete('/plants/1000')
data=json.loads(res.data)
plant=Plant.query.filter(Plant.id == 1000).one_or_none()
self.assertEqual(res.status_code, 422)
self.assertEqual(data['success'], False)
self.assertEqual(data['message'], 'unprocessable')
def test_create_new_plant(self):
res=self.client().post('/plants', json = self.new_plant)
data=json.loads(res.data)
self.assertEqual(res.status_code, 200)
self.assertTrue(data['success'], True)
self.assertTrue(data['created'])
self.assertTrue(data['plants'])
self.assertEqual(len(data['plants']))
def test_404_requesting_beyond_the_value_page(self):
res=self.client().get('/plants?page=1000')
data=json.loads(res.data)
self.assertEqual(res.status_code, 404)
self.assertEqual(data['success'], False)
self.assertEqual(data['message'], 'Not found')
def test_404_requesting_select_on_plant(self):
res=self.client().get('/plants/1000')
data=json.loads(res.data)
self.assertEqual(res.status_code, 404)
self.assertEqual(data['success'], False)
self.assertEqual(data['message'], 'Not found')
def test_update_plant_primary_color(self):
res=self.client().patch('/plants/102',json={'primary_color':'Gray'})
data=json.loads(res.data)
plant=Plant.query.filter(Plant.id == 102).one_or_none()
self.assertEqual(res.status_code,200)
self.assertEqual(data['success'],True)
self.assertEqual(plant.format()['primary_color'],'Gray')
def test_get_plant_search_with_result(self):
res=self.client().post('/plants',json={'search':'Baobab'})
self.assertEqual(res.status_code,200)
self.assertEqual(data['success'],True)
self.assertEqual(len(data['total_plants']))
self.assertEqual(len(data['plants']),4)
Partie 3 :
https://auth0.com/blog/using-python-flask-and-angular-to-build-modern-web-apps-part-2/
Partie 4 :
Déploiement de l’API
Cette partie est résumé dans la vidéo ci-dessous. La vidéo doit être suivie par l’étudiant. L’ensei-
gnant fait une brève présentation du contenu de la vidéo
https://www.youtube.com/watch?v=23sp3cj5Pnc&t=33s