Pizzeria

L’objectif de l’activité est de créer une petite application Web s’appuyant sur une base de données concernant des pizzas, du point de vue d’un gérant de pizzeria : recettes, prix, ventes, notation, …

Il est conseillé d’avoir auparavant fait l’activité « Pizzeria » avec SQLite

Préparation

Après accord du professeur et attribution d’un Raspberry PI (de raspberrypinsi1 à raspberrypinsi4) et d’un utilisateur (de nsi1 à nsi4), accéder en SSH à l’un des Raspberry PI.

Voir l’article Raspberry Pi du lycée

 

Schéma relationnel de la base de données

Pizzas (id, nom, prix_vente)

Produits (id, nom, prix_kg, allergene)

Ingredients (id_produit, id_pizza, quantite_kg)

Ventes (id, date, id_pizza, note_consommateur)

On appelle « ingrédients » d’une « pizza » l’ensemble des « produits » qu’elle contient, ainsi que leurs quantités.

 

Analyse du schéma

Les clés primaires et les contraintes de clé étrangères ont été déterminés dans l’activité avec SQLite.

Avec le SGBD MySQL, les domaines possibles sont beaucoup plus variés : VARCHAR, TEXT, INT, FLOAT, BOOL, DATE, …

Redéfinir les domaines de chacun des attributs des relations de la base, en apportant autant de précision que possible (taille des VARCHAR, taille des INT, …).

 

Création des tables

Depuis l’application (sur le Raspberry Pi) phpMyAdmin (voir Raspberry Pi du lycée pour savoir comment y accéder) :

À l’aide de phpMyAdmin (sur le Raspberry Pi), créer une nouvelle base (nommée nsi1_pizzeria à nsi4_pizzeria selon les cas). ATTENTION ! le préfixe nsi1_ à nsi4_ est obligatoire !

 

Créer la structure de la base de données (dans l’ordre : tables, attributs, clés primaires, contraintes de clé étrangère !!).
Quelques méthodes sur phpMyAdmin


 

Afficher le schéma dans l’outil Concepteur de phpMyAdmin pour vérifier que la structure de la base est correcte.

Appeler le professeur

 

Remplissage des tables

Pour remplir une table, il faut utiliser la requête SQL INSERT INTO ... .

Le code SQL ci-dessous contient les 4 requêtes permettant de remplir chacune des 4 tables.

Requêtes SQL INSERT INTO ...
INSERT INTO `Ingredients` (`id_produit`, `id_pizza`, `quantite_kg`) VALUES
(5, 3, 0.8),
(6, 4, 300),
(6, 7, 100),
(7, 7, 56),
(8, 6, 65),
(9, 1, 75),
(9, 2, 95),
(9, 5, 50),
(9, 7, 95),
(9, 9, 90),
(10, 1, 50),
(10, 5, 125),
(10, 6, 0.5),
(11, 1, 220),
(11, 2, 90),
(11, 4, 250),
(11, 7, 185),
(12, 9, 80),
(13, 2, 120),
(14, 5, 49),
(14, 6, 50),
(14, 9, 85),
(15, 1, 100),
(15, 4, 150),
(15, 7, 200),
(15, 9, 160),
(15, 10, 125),
(16, 1, 125),
(16, 2, 75),
(16, 5, 200),
(16, 7, 333),
(16, 9, 120),
(17, 1, 10),
(17, 2, 10),
(17, 9, 40),
(18, 3, 0.01),
(19, 7, 70),
(21, 1, 60),
(21, 2, 150),
(22, 1, 185),
(22, 2, 75),
(22, 3, 80),
(22, 5, 200),
(22, 7, 25),
(22, 9, 50),
(22, 10, 200),
(24, 6, 18);



INSERT INTO `Pizzas` (`id`, `nom`, `prix_vente`) VALUES
(1, '4 Fromages', 7.00),
(2, 'Auvergnate', 7.00),
(3, 'Bling-Bling', 89.00),
(4, 'Calzone', 9.00),
(5, 'Chèvre', 9.60),
(6, 'Chèvre-miel', 10.20),
(7, 'Espagnole', 6.80),
(8, 'Hawaïenne', 11.00),
(9, 'Kebab', 8.30),
(10, 'Margherita', 6.00),
(11, 'Pepperoni', 8.50),
(12, 'Truffade', 9.40);




INSERT INTO `Produits` (`id`, `nom`, `prix_kg`, `allergene`) VALUES
(1, 'Ananas', 2.53, 0),
(2, 'Anchois', 48.00, 1),
(3, 'Boeuf hâché', 22.12, 0),
(4, 'Câpres', 49.00, 1),
(5, 'Caviar', 2000.00, NULL),
(6, 'Champignons', 3.60, 0),
(7, 'Chorizo', 14.00, 0),
(8, 'Crème fraiche', 14.00, 1),
(9, 'Emmental rapé', 0.45, 1),
(10, 'Fromage de chèvre', 3.50, 1),
(11, 'Jambon', 27.96, 0),
(12, 'Kebab', 8.05, 0),
(13, 'Lardons', 8.05, 0),
(14, 'Miel', 19.60, 0),
(15, 'Mozzarella', 11.00, 1),
(16, 'Oignons', 0.42, 0),
(17, 'Olives', 7.38, 0),
(18, 'Paillettes d\'or', 80000.00, NULL),
(19, 'Poivrons', 2.50, 0),
(20, 'Poulet', 12.70, 0),
(21, 'Saint Nectaire', 17.00, 1),
(22, 'Sauce tomate', 2.36, 0),
(23, 'Saumon fumé', 29.00, 1),
(24, 'Sel', 18.00, 0),
(25, 'Tome fraiche', 9.30, 1);



INSERT INTO `Ventes` (`id`, `date`, `id_pizza`, `note_consommateur`) VALUES
(1, '2018-09-11', 5, 1),
(2, '2018-09-14', 5, 3),
(3, '2018-09-14', 10, 4),
(4, '2018-09-15', 9, 2),
(5, '2018-09-19', 10, 5),
(6, '2018-09-20', 1, 5),
(7, '2018-09-28', 5, 4),
(8, '2019-10-08', 10, 5),
(9, '2018-10-11', 9, 3),
(10, '2018-10-12', 12, 5),
(11, '2018-10-13', 9, 4),
(12, '2018-10-16', 7, 5),
(13, '2018-10-19', 10, 4),
(14, '2018-10-19', 4, 4),
(15, '2018-10-23', 9, 3),
(16, '2018-10-24', 7, 5),
(17, '2018-10-29', 11, 1),
(18, '2018-10-29', 5, 3),
(19, '2018-10-30', 7, 4),
(20, '2018-10-31', 2, 5),
(21, '2018-11-01', 1, 4),
(22, '2018-11-01', 12, 5),
(23, '2018-11-01', 2, 5),
(24, '2019-11-03', 6, 3),
(25, '2018-11-08', 1, 4),
(26, '2018-11-11', 5, 2),
(27, '2018-11-14', 7, 5),
(28, '2018-11-14', 11, 5),
(29, '2018-11-15', 1, 3),
(30, '2018-11-19', 12, 5),
(31, '2018-11-20', 2, 5),
(32, '2018-11-20', 1, 3),
(33, '2018-11-22', 4, 2),
(34, '2018-11-23', 7, 3),
(35, '2018-11-27', 9, 4),
(36, '2018-11-27', 2, NULL),
(37, '2018-11-27', 4, 5),
(38, '2018-12-13', 1, NULL),
(39, '2018-12-14', 1, 4),
(40, '2018-12-17', 12, NULL),
(41, '2018-12-20', 10, 5),
(42, '2018-12-21', 11, 3),
(43, '2018-12-29', 7, 3),
(44, '2018-12-31', 2, 4),
(45, '2019-01-01', 6, 4),
(46, '2019-01-11', 10, 3),
(47, '2019-01-15', 9, NULL),
(48, '2019-01-16', 11, 4),
(49, '2019-01-20', 2, 5),
(50, '2019-01-25', 4, 4),
(51, '2019-01-28', 2, 2),
(52, '2019-01-28', 7, 5),
(53, '2019-01-29', 5, 3),
(54, '2019-02-05', 10, NULL),
(55, '2019-02-11', 10, 4),
(56, '2019-02-12', 10, 2),
(57, '2019-02-18', 5, 5),
(58, '2019-02-20', 2, 4),
(59, '2019-02-27', 2, 5),
(60, '2019-03-01', 12, 5),
(61, '2019-03-02', 12, 4),
(62, '2019-03-03', 6, 3),
(63, '2019-03-05', 1, 5),
(64, '2019-03-05', 8, 1),
(65, '2019-03-07', 10, 3),
(66, '2019-03-08', 1, 4),
(67, '2019-03-09', 1, 5),
(68, '2019-03-10', 4, 5),
(69, '2019-03-10', 11, 5),
(70, '2019-03-12', 8, 2),
(71, '2019-03-13', 4, 3),
(72, '2019-03-14', 2, NULL),
(73, '2019-03-17', 7, NULL),
(74, '2019-03-23', 11, 4),
(75, '2019-03-26', 4, NULL),
(76, '2019-04-03', 9, 4),
(77, '2019-04-03', 2, 4),
(78, '2019-04-07', 4, 4),
(79, '2019-04-10', 12, 5),
(80, '2019-04-12', 5, 4),
(81, '2019-04-12', 2, 4),
(82, '2019-04-16', 12, 5),
(83, '2019-05-03', 8, 1),
(84, '2019-05-04', 5, 4),
(85, '2019-05-06', 10, 3),
(86, '2019-05-06', 12, 5),
(87, '2019-05-06', 1, 3),
(88, '2019-05-18', 11, 2),
(89, '2019-05-27', 6, NULL),
(90, '2019-05-29', 4, NULL),
(91, '2019-06-01', 4, 3),
(92, '2019-06-03', 12, NULL),
(93, '2019-06-07', 8, 2),
(94, '2019-06-11', 9, 3),
(95, '2019-06-12', 7, NULL),
(96, '2019-06-19', 12, 5),
(97, '2019-06-23', 2, NULL),
(98, '2019-06-26', 8, 1),
(99, '2019-06-30', 9, 3),
(100, '2019-07-08', 12, 4),
(101, '2019-07-09', 9, 5),
(102, '2019-07-12', 10, 4),
(103, '2019-07-15', 2, NULL),
(104, '2019-07-21', 4, 5),
(105, '2019-07-22', 4, 3),
(106, '2019-07-27', 10, NULL),
(107, '2019-08-03', 1, 5),
(108, '2019-08-08', 12, 5),
(109, '2019-08-11', 2, 4),
(110, '2019-08-13', 8, 3),
(111, '2019-08-15', 8, 2),
(112, '2019-08-16', 8, NULL),
(113, '2019-08-17', 1, NULL),
(114, '2019-08-20', 12, 5),
(115, '2019-08-24', 5, 4),
(116, '2019-08-24', 4, 4),
(117, '2019-08-26', 7, 5),
(118, '2019-08-27', 9, NULL),
(119, '2019-09-01', 5, 3),
(120, '2019-09-04', 10, NULL),
(121, '2019-09-06', 6, 3),
(122, '2019-09-07', 6, 5),
(123, '2019-09-07', 8, 4),
(124, '2019-09-08', 5, 5),
(125, '2019-09-13', 7, 4),
(126, '2019-09-15', 9, NULL),
(127, '2019-09-22', 12, NULL),
(128, '2019-09-22', 10, 5),
(129, '2019-09-23', 9, NULL),
(130, '2019-09-25', 4, NULL),
(131, '2019-10-05', 11, 5),
(132, '2019-10-08', 6, 4),
(133, '2019-10-08', 9, NULL),
(134, '2019-10-11', 12, NULL),
(135, '2019-10-14', 12, 5),
(136, '2019-10-15', 10, NULL),
(137, '2019-10-16', 4, NULL),
(138, '2019-10-16', 1, 4),
(139, '2019-10-22', 2, 5),
(140, '2019-10-25', 2, NULL),
(141, '2019-10-26', 12, 5),
(142, '2019-11-05', 10, 5),
(143, '2019-11-05', 7, NULL),
(144, '2019-11-11', 1, NULL),
(145, '2019-11-13', 10, 4),
(146, '2019-11-14', 9, NULL),
(147, '2019-11-14', 6, NULL),
(148, '2019-11-16', 9, NULL),
(149, '2019-11-26', 8, 2),
(150, '2019-11-27', 2, 4),
(151, '2019-11-29', 2, 5),
(152, '2019-11-29', 1, NULL),
(153, '2019-12-09', 8, 3),
(154, '2019-12-14', 2, 5),
(155, '2019-12-22', 2, 3),
(156, '2019-12-23', 4, NULL),
(157, '2019-12-24', 11, NULL),
(158, '2019-12-29', 5, 5),
(159, '2019-12-31', 12, 5),
(160, '2019-12-31', 7, 5),
(161, '2019-12-31', 7, 4),
(162, '2020-01-03', 1, NULL),
(163, '2020-01-07', 2, 5),
(164, '2020-01-09', 8, NULL),
(165, '2020-01-21', 10, 4),
(166, '2020-01-22', 5, 4),
(167, '2020-02-01', 6, NULL),
(168, '2020-02-04', 1, NULL),
(169, '2020-02-04', 12, 5),
(170, '2020-02-04', 4, NULL),
(171, '2020-02-05', 5, 4),
(172, '2020-02-10', 8, 4),
(173, '2020-02-11', 9, 1),
(174, '2020-02-12', 7, 4),
(175, '2020-02-13', 12, 4),
(176, '2020-02-20', 9, 5),
(177, '2020-02-21', 10, NULL),
(178, '2020-02-26', 4, 5),
(179, '2020-02-27', 6, NULL),
(180, '2020-02-29', 1, 4),
(181, '2020-03-04', 7, 4),
(182, '2020-03-06', 4, 5),
(183, '2020-03-09', 12, NULL),
(184, '2020-03-15', 8, 3),
(185, '2020-03-17', 2, 4),
(186, '2020-03-18', 9, 3),
(187, '2020-03-26', 2, 5),
(188, '2020-03-28', 12, NULL),
(189, '2020-03-30', 6, 5),
(190, '2020-04-09', 6, 4),
(191, '2020-04-10', 10, NULL),
(192, '2020-04-13', 7, 4),
(193, '2020-04-16', 8, 4),
(194, '2020-04-16', 2, 5),
(195, '2020-04-18', 6, NULL),
(196, '2020-04-19', 2, 5),
(197, '2020-04-23', 12, 5),
(198, '2020-04-29', 11, NULL),
(199, '2020-05-08', 6, 5),
(200, '2020-05-09', 1, 4);
Depuis phpMyAdmin, exécuter l’une après l’autre chacune de ces requêtes. ATTENTION : l’ordre est important !!
[question_tri nom= »Dans quel ordre faut-il lancer les requêtes ? » signe= » » titre= » » random= »true »] [q_elem]Pizzas[/q_elem] [q_elem]Produits[/q_elem] [q_elem]Ventes[/q_elem] [q_elem]Ingredients[/q_elem] [/question_tri]

Appeler le professeur

 

Établissement des requêtes

La base de donnée étant remplie, il faut préparer les requêtes qui peuvent être nécessaires au gérant de la pizzeria.

Faire le Quiz ci-dessous, en notant bien chacune des réponses !
Aide

La fonction SQL  MONTH(date)  permet d’extraire le mois depuis une date.

Toutes les fonctions SQL de base sont documentées ici : https://sql.sh/fonctions

 

 

Réalisation du site WEB

Le gérant de la pizzeria souhaite utiliser cette base de données pour réaliser quelques tâches de manière automatique :

  • création et mise à jour des menus,
  • évolution des ventes,
  • évolution des bénéfices réalisés,
  • notation des recettes par les consommateurs,
  • …

Pour cela, on se propose de réaliser une application WEB, dotée d’un formulaire simple (quelques boutons et listes déroulantes), et affichant les résultats de requêtes préalablement définies.

 

 

Interrogation de la base de données

Pour interroger une base de données MySQL avec python, il faut utiliser une bibliothèque, comme mysql-connector par exemple (déjà installée sur les Raspberry Pi du lycée).

Voici un article sur l’utilisation de mysql-connector .

 

Le programme Python qui interroge la base de données se situe sur le Raspberry Pi ; la base de donnée se trouve également sur le Raspberry Pi.

Donner le nom de l’hôte à renseigner dans la méthode connect de mysql.connector.
×

 

 

Écrire et tester une fonction Python permettant de se connecter à la base de données pizzeria  et d’obtenir le résultat d’une requête SQL SELECT.
Comment exécuter du code Python sur le Raspberry Pi ??

Depuis le terminal :

  • Changer le dossier courant par celui qui contient le script Python.

Exemple : 

cd ~/nsi1/pizzeria

  • Exécuter le script avec Python.

Exemple :

python test_sql.py

 

Faire de même avec des requêtes d’écriture (UPDATE, INSERT INTO).

 

Structure de l’application Web

L’application Web est constituée d’un ensemble de fichiers placés dans une arborescence de dossiers spécifique du Raspberry Pi.

 

Construire l’arborescence des dossiers de l’application :

 

Test de la connexion Apache-WSGI-Flask

Pour tester si tout fonctionne bien, créer un fichier pizzeria.py avec le contenu suivant :
from flask import Flask

app = Flask(__name__)

@app.route("/")
def hello():
   return "Pizzeria !"

if __name__ == "__main__":
   app.run(debug = True)

 

Depuis un navigateur, taper dans la barre d’adresse : htp://raspberrypinsi1:81 (ou :82, :83, :84 selon le nom d’utilisateur nsi1, nsi2, nsi3, nsi4).

Le résultat devrait ressembler à ça :

 

ATTENTION

Après modification d’un des fichiers de l’application Web, il faut impérativement modifier également le fichier pizzeria.wsgi (ajout/suppression d’une ligne vide par exemple).

Sans cela, les fichiers Python ne sont pas recompilés et par conséquent les modifications ne sont pas prises en compte !!!

 

Structure des pages

Flask permet de construire des pages dynamiquement : elles sont construites coté serveur, à l’aide du langage Python et Flask (voir : Python Flask).

Voici une structure envisageable :

 

Le fichier base.html

Un fichier base.html  sert de base à toutes les pages du site.

<!DOCTYPE html>
<html lang="fr-FR">
<head>
	<meta charset="UTF-8" />
	<title>{% block title %}{% endblock %}</title>
</head>
<body>
	{% include "header.html" %}
	<div class="interieur">
	{% block content %}{%- endblock %}
	</div>
	{% include "footer.html" %}
</body>
</html>

Ce fichier comporte :

  • au format HTML, l’entête HTML et les balises <head>  et <body> .
  • dans le corps de la page (<body>) on inclue l’entête et le pied de page, enregistrés dans deux fichiers header.html  et footer.html , en utilisant dans le code HTML les instructions Flask (qui utilise le moteur de template Jinja) {% include "header.html" %}  et {% include "footer.html" %}
  • le titre de la page et son contenu sont inclus grâce aux instructions  {% block title %}{% endblock %}  et {% block content %}{% endblock %}

 

Entête et pied de page

Ils sont définis dans deux fichiers header.html  et footer.html

Ces fichiers peuvent comporter :

  • Des menus de navigation
  • Des informations légales
  • …

 

Les pages du site

Chaque page (xxx.html) aura la forme :

{% extends "base.html" %}
{% block title %}Titre de la page{% endblock %}

{% block content %}
	
... code HTML ...

{% endblock %}

 

Le fichier principal Python

Ce fichier (appelé ici pizzeria.py) est exécuté par le serveur (via wsgi) à chaque requête HTTP GET. Il définit  l’application Flask (objet qui doit gérer les réponses HTTP), et les routes du sites (les URL qui doivent renvoyer des ressources).

Modifier le fichier Python pizzeria.py en lui donnant la structure suivante :
# Le Framework (générateur de pages HTML)
from flask import Flask, render_template

# Application Flask
app = Flask(__name__)

# Pages HTML
pageACCUEIL = "accueil.html"

############################################################################################
@app.route("/")
def index():
   return render_template(pageACCUEIL)

# Script de débuggage
if __name__ == "__main__":
   app.run(host='0.0.0.0', debug = True)

 

Structure du dossier du site

Au final, le dossier du site aura cette forme :

  • pizzeria
    • logs
    • templates
      • base.html
      • header.html
      • footer.html
      • accueil.html
    • static
      • images …
      • css …
    • pizzeria.wsgi
    • pizzeria.py

 

Créer des fichiers vides  header.html  et footer.html, un fichier accueil.html et tester l’affichage correct de la page dans un navigateur.

 

 

Dans un fichier table.html , en utilisant les structures Jinja {% for ... %}...{% endfor %} , écrire le code permettant de construire un tableau HTML (balise <table> ).

Pour utiliser ce bout de code HTML dans un modèle (template), il suffit d’y insérer :

{% with t = ma_table %}
    {% include "table.html" %}
{% endwith %}

 

Créer alors une page page_pizzas.html, basée sur  base.html, et incluant table.html, de sorte d’afficher, comme sur un menu, la liste des pizzas, leurs ingrédients (avec une astérisque à côté de chaque ingrédient allergène), leurs prix, et la note moyenne des consommateurs (sous forme d’étoiles ⭐⭐⭐⭐⭐).
 
 
Faire un menu dans l’entête des pages (header.html) comportant un lien vers page_pizzas.html (utiliser url_for, voir documentation de Flask).
 

 

 

 

Vous aimerez aussi...

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *