8 | {% if lieux %}
9 | Il y a {{ lieux|length }} enregistrés , voici le premier : {{lieux[0]}}
10 | {% else %}
11 | La base de données est en cours de constitution
12 | {% endif %}
13 |
8 | {% if lieux %}
9 | Il y a {{ lieux|length }} enregistrés , voici le premier : {{lieux[0].nom}}
10 | {% else %}
11 | La base de données est en cours de constitution
12 | {% endif %}
13 |
15 | {% else %}
16 | La base de données est en cours de constitution
17 | {% endif %}
18 |
19 |
20 |
--------------------------------------------------------------------------------
/cours-packages/exemple-04/gazetteer/routes.py:
--------------------------------------------------------------------------------
1 | from flask import render_template
2 |
3 |
4 | from .app import app
5 | from .modeles.donnees import Place
6 |
7 |
8 | @app.route("/")
9 | def accueil():
10 | # On a bien sûr aussi modifié le template pour refléter le changement
11 | lieux = Place.query.all()
12 | return render_template("pages/accueil.html", nom="Gazetteer", lieux=lieux)
13 |
14 |
15 | @app.route("/place/")
16 | def lieu(place_id):
17 | # On a bien sûr aussi modifié le template pour refléter le changement
18 | unique_lieu = Place.query.get(place_id)
19 | return render_template("pages/place.html", nom="Gazetteer", lieu=unique_lieu)
20 |
--------------------------------------------------------------------------------
/cours-flask/exemple2/app.py:
--------------------------------------------------------------------------------
1 | from flask import Flask
2 |
3 | app = Flask("Application")
4 |
5 |
6 | @app.route("/")
7 | def index():
8 | return "Hello world !"
9 |
10 |
11 | @app.route("/places/")
12 | def chemin_place(place_id):
13 | return "On est sur " + place_id
14 |
15 | # Ce if permet de vérifier que ce fichier est celui qui est courrament exécuté. Cela permet par exemple d'éviter
16 | # de lancer une fonction quand on importe ce fichier depuis un autre fichier.
17 | # En python, lorsque l'on exécute un script avec la commande `python script.py`
18 | # Le fichier `script.py` a en __name__ la valeur __main__.
19 | if __name__ == "__main__":
20 | app.run()
21 |
--------------------------------------------------------------------------------
/cours-flask/exemple3/app.py:
--------------------------------------------------------------------------------
1 | from flask import Flask
2 |
3 | app = Flask("Application")
4 |
5 |
6 | @app.route("/")
7 | def index():
8 | return "Hello world !"
9 |
10 |
11 | @app.route("/places/")
12 | def chemin_place(place_id):
13 | return "On est sur " + str(place_id)
14 |
15 | # Ce if permet de vérifier que ce fichier est celui qui est courrament exécuté. Cela permet par exemple d'éviter
16 | # de lancer une fonction quand on importe ce fichier depuis un autre fichier.
17 | # En python, lorsque l'on exécute un script avec la commande `python script.py`
18 | # Le fichier `script.py` a en __name__ la valeur __main__.
19 | if __name__ == "__main__":
20 | app.run()
21 |
--------------------------------------------------------------------------------
/modules_cours/gazetteer/app.py:
--------------------------------------------------------------------------------
1 | from flask import Flask
2 | from flask_sqlalchemy import SQLAlchemy
3 | from flask_login import LoginManager
4 | import os
5 | from .constantes import SECRET_KEY
6 |
7 | chemin_actuel = os.path.dirname(os.path.abspath(__file__))
8 | app = Flask(
9 | "Application"
10 | )
11 | # On configure le secret
12 | app.config['SECRET_KEY'] = SECRET_KEY
13 | # On configure la base de données
14 | app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://gazetteer_user:password@localhost/gazetteer'
15 | app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
16 | # On initie l'extension
17 | db = SQLAlchemy(app)
18 |
19 | # On met en place la gestion d'utilisateur-rice-s
20 | login = LoginManager(app)
21 |
22 |
--------------------------------------------------------------------------------
/cours-flask/exemple6/templates/place.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Gazetteer {%if lieu %}| Lieu : {{lieu.nom}} {% endif %}
4 |
5 |
6 | {% if lieu %}
7 |
20 | {% endblock %}
--------------------------------------------------------------------------------
/cours-flask/exemple5/app.py:
--------------------------------------------------------------------------------
1 | from flask import Flask, render_template
2 |
3 | app = Flask("Application")
4 |
5 |
6 | @app.route("/")
7 | @app.route("/exemple/")
8 | def accueil(exemple=None):
9 | lieux = []
10 | if exemple:
11 | lieux = ["Col. Lugdunum", "Augustomagus"]
12 | return render_template("accueil.html", nom="Gazetteer", lieux=lieux)
13 |
14 |
15 |
16 | # Ce if permet de vérifier que ce fichier est celui qui est courrament exécuté. Cela permet par exemple d'éviter
17 | # de lancer une fonction quand on importe ce fichier depuis un autre fichier.
18 | # En python, lorsque l'on exécute un script avec la commande `python script.py`
19 | # Le fichier `script.py` a en __name__ la valeur __main__.
20 | if __name__ == "__main__":
21 | app.run()
22 |
--------------------------------------------------------------------------------
/cours-flask/exemple7/templates/place.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Gazetteer {%if lieu %}| Lieu : {{lieu.nom}} {% endif %}
4 |
5 |
6 | {% if lieu %}
7 |
19 |
20 |
--------------------------------------------------------------------------------
/cours-flask/exemple18/gazetteer/constantes.py:
--------------------------------------------------------------------------------
1 | from warnings import warn
2 |
3 | LIEUX_PAR_PAGE = 2
4 | SECRET_KEY = "JE SUIS UN SECRET !"
5 | API_ROUTE = "/api"
6 |
7 | if SECRET_KEY == "JE SUIS UN SECRET !":
8 | warn("Le secret par défaut n'a pas été changé, vous devriez le faire", Warning)
9 |
10 |
11 | class _TEST:
12 | SECRET_KEY = SECRET_KEY
13 | # On configure la base de données
14 | SQLALCHEMY_DATABASE_URI = 'sqlite:///test_db.sqlite'
15 | SQLALCHEMY_TRACK_MODIFICATIONS = False
16 |
17 |
18 | class _PRODUCTION:
19 | SECRET_KEY = SECRET_KEY
20 | # On configure la base de données
21 | SQLALCHEMY_DATABASE_URI = 'mysql://gazetteer_user:password@localhost/gazetteer'
22 | SQLALCHEMY_TRACK_MODIFICATIONS = False
23 |
24 | CONFIG = {
25 | "test": _TEST,
26 | "production": _PRODUCTION
27 | }
--------------------------------------------------------------------------------
/cours-flask/exemple16/gazetteer/app.py:
--------------------------------------------------------------------------------
1 | from flask import Flask
2 | from flask_sqlalchemy import SQLAlchemy
3 | from flask_login import LoginManager
4 | import os
5 | from .constantes import SECRET_KEY
6 |
7 | chemin_actuel = os.path.dirname(os.path.abspath(__file__))
8 | templates = os.path.join(chemin_actuel, "templates")
9 | statics = os.path.join(chemin_actuel, "static")
10 |
11 | app = Flask(
12 | "Application",
13 | template_folder=templates,
14 | static_folder=statics
15 | )
16 | # On configure le secret
17 | app.config['SECRET_KEY'] = SECRET_KEY
18 | # On configure la base de données
19 | app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///../db.sqlite'
20 | # On initie l'extension
21 | db = SQLAlchemy(app)
22 |
23 | # On met en place la gestion d'utilisateur-rice-s
24 | login = LoginManager(app)
25 |
26 |
27 | from . import routes
--------------------------------------------------------------------------------
/cours-flask/exemple17/gazetteer/app.py:
--------------------------------------------------------------------------------
1 | from flask import Flask
2 | from flask_sqlalchemy import SQLAlchemy
3 | from flask_login import LoginManager
4 | import os
5 | from .constantes import SECRET_KEY
6 |
7 | chemin_actuel = os.path.dirname(os.path.abspath(__file__))
8 | templates = os.path.join(chemin_actuel, "templates")
9 | statics = os.path.join(chemin_actuel, "static")
10 |
11 | app = Flask(
12 | "Application",
13 | template_folder=templates,
14 | static_folder=statics
15 | )
16 | # On configure le secret
17 | app.config['SECRET_KEY'] = SECRET_KEY
18 | # On configure la base de données
19 | app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///../db.sqlite'
20 | app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
21 | # On initie l'extension
22 | db = SQLAlchemy(app)
23 |
24 | # On met en place la gestion d'utilisateur-rice-s
25 | login = LoginManager(app)
26 |
27 |
28 | from .routes import generic
29 | from .routes import api
--------------------------------------------------------------------------------
/data/json/brecht.json:
--------------------------------------------------------------------------------
1 | {
2 | "titre": {"fre": "La Solution", "ger": "Die Lösung"},
3 | "auteur": "Bertold Brecht",
4 | "annee": 1953,
5 | "source": "https://fr.wikipedia.org/wiki/Die_L%C3%B6sung",
6 | "vers": [
7 | {"n": 1, "texte": "Après l'insurrection du 17 juin,"},
8 | {"n": 2, "texte": "Le secrétaire de l'Union des Écrivains"},
9 | {"n": 3, "texte": "Fit distribuer des tracts dans la Stalinallée."},
10 | {"n": 4, "texte": "Le peuple, y lisait-on, a par sa faute"},
11 | {"n": 5, "texte": "Perdu la confiance du gouvernement"},
12 | {"n": 6, "texte": "Et ce n'est qu'en redoublant d'efforts"},
13 | {"n": 7, "texte": "Qu'il peut la regagner."},
14 | {"n": 8, "texte": "Ne serait-il pas"},
15 | {"n": 9, "texte": "Plus simple alors pour le gouvernement"},
16 | {"n": 10, "texte": "De dissoudre le peuple"},
17 | {"n": 11, "texte": "Et d'en élire un autre ?"}
18 | ]
19 | }
--------------------------------------------------------------------------------
/data/lanuitdelamort.michel.txt:
--------------------------------------------------------------------------------
1 | Dies irœ, Dies illa
2 | Solvet scelum in favilla.
3 | Jamais ne viendra donc la fin ?
4 | Dorment-ils tous, les meurt-de-faim ?
5 | Jamais, jamais le dernier jour
6 | Ne les jettera-t-il à leur tour
7 | Dans les angoisses de la mort,
8 | Ces bandits que la rage mord ?
9 |
10 | Toujours, esclaves et bourreaux,
11 | Pâtiront-ils leurs échafauds ?
12 | Amis, dans l’ombre entendez-vous
13 | Gronder la mer aux noirs remous ?
14 | Elle monte et les couvrira.
15 | Dies irae, Dies illa...
16 | Elle couvre, pourpre de sang,
17 | L’Elysée et le Vatican.
18 | Compagnons, arrachons nos cœurs,
19 | Ne soyons plus que des vengeurs.
20 |
21 | Passons, effrayants et maudits,
22 | Afin que les maux soient finis.
23 | Comblons l’abîme avec nos corps.
24 | Amis, n’oubliez pas les morts...
25 | La légende des temps nouveaux
26 | Fleurira parmi les tombeaux.
27 | C’est le destin ; le maître est dur.
28 | C’est pourquoi le fer sera pur.
29 |
30 | Dies irae, Dies illa,
31 | Solvet scelum, in favina.
32 |
--------------------------------------------------------------------------------
/cours-flask/exemple18/tests/test_user.py:
--------------------------------------------------------------------------------
1 | from .base import Base
2 | from gazetteer.modeles.utilisateurs import User
3 |
4 |
5 | class TestUser(Base):
6 | """ Unit tests for Users """
7 | def test_creation(self):
8 | with self.app.app_context():
9 | statut, utilisateur = User.creer("joh", "johanna.johanna@enc-sorbonne.fr", "Johanna", "azerty")
10 | query = User.query.filter(User.user_email == "johanna.johanna@enc-sorbonne.fr").first()
11 | self.assertEqual(query.user_nom, "Johanna")
12 | self.assertEqual(query.user_login, "joh")
13 | self.assertNotEqual(query.user_password, "azerty")
14 | self.assertTrue(statut)
15 |
16 | def test_login_et_creation(self):
17 | with self.app.app_context():
18 | statut, cree = User.creer("joh", "johanna.johanna@enc-sorbonne.fr", "Johanna", "azerty")
19 | connecte = User.identification("joh", "azerty")
20 |
21 | self.assertEqual(cree, connecte)
22 | self.assertTrue(statut)
23 |
--------------------------------------------------------------------------------
/data/Ballade.XXVIII.dePisan.txt:
--------------------------------------------------------------------------------
1 | Mon doulz ami, vueilliez moy pardonner,
2 | Se je ne puis, si tost com je vouldroye,
3 | Parler a vous, car ainçois ordener
4 | Me fault comment sera, ne par quel voye.
5 | Car mesdisans me vont gaitant
6 | Qui du meschief et du mal me font tant,
7 | Que je ne puis joye ne bien avoir,
8 | Pour le desir que j’ay de vous veoir.
9 |
10 | Si pry a Dieu qu’il leur vueille donner
11 | La mort briefment ; car leur vie m’anoye,
12 | Pour ce qu’en dueil me font mes jours finer
13 | Sanz vous veoir, ou est toute ma joye
14 | Car ilz se vont entremettant
15 | De moy gaitier nuit et jour, mais pourtant
16 | Ne vous oubli, ce pouez vous savoir,
17 | Pour le desir que j’ay de vous veoir.
18 |
19 | Mais ne sçaront ja eulx si fort pener,
20 | Que, maugré tous, bien briefment ne vous voie.
21 | Car tant feray, se g’y puis assener,
22 | Que vous verray, quoy qu’avenir m’en doye,
23 | Et vous feray savoir quant.
24 | Mon doulz ami, deportez vous atant.
25 | Car g’y mettray peine, sachiez de voir,
26 | Pour le desir que j’ay de vous veoir.
--------------------------------------------------------------------------------
/cours-flask/exemple18/gazetteer/app.py:
--------------------------------------------------------------------------------
1 | from flask import Flask
2 | from flask_sqlalchemy import SQLAlchemy
3 | from flask_login import LoginManager
4 | import os
5 | from .constantes import CONFIG
6 |
7 | chemin_actuel = os.path.dirname(os.path.abspath(__file__))
8 | templates = os.path.join(chemin_actuel, "templates")
9 | statics = os.path.join(chemin_actuel, "static")
10 |
11 | # On initie l'extension
12 | db = SQLAlchemy()
13 | # On met en place la gestion d'utilisateur-rice-s
14 | login = LoginManager()
15 |
16 | app = Flask(
17 | __name__,
18 | template_folder=templates,
19 | static_folder=statics
20 | )
21 |
22 |
23 | from .routes import generic
24 | from .routes import api
25 |
26 |
27 | def config_app(config_name="test"):
28 | """ Create the application """
29 | app.config.from_object(CONFIG[config_name])
30 |
31 | # Set up extensions
32 | db.init_app(app)
33 | # assets_env = Environment(app)
34 | login.init_app(app)
35 |
36 | # Register Jinja template functions
37 |
38 | return app
39 |
40 |
--------------------------------------------------------------------------------
/cours-flask/exemple13/gazetteer/templates/conteneur.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Gazetteer {%block titre %}{%endblock%}
6 | {% include "partials/css.html" %}
7 | {% include "partials/metadata.html" %}
8 |
9 |
10 |
11 |
12 |
19 |
8 |
26 | {% endblock %}
--------------------------------------------------------------------------------
/supports/chapitre-6/template.omeka.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
23 |
24 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/cours-flask/exemple18/tests/test_api.py:
--------------------------------------------------------------------------------
1 | from .base import Base
2 | from json import loads
3 |
4 |
5 | class TestApi(Base):
6 | def test_single_place(self):
7 | """ Vérifie qu'un lieu est bien traité """
8 | self.insert_all()
9 | response = self.client.get("/api/places/1")
10 | # Le corps de la réponse est dans .data
11 | # .data est en "bytes". Pour convertir des bytes en str, on fait .decode()
12 | content = response.data.decode()
13 | self.assertEqual(
14 | response.headers["Content-Type"], "application/json"
15 | )
16 | json_parse = loads(content)
17 | self.assertEqual(json_parse["type"], "place")
18 | self.assertEqual(
19 | json_parse["attributes"],
20 | {'name': 'Hippana', 'latitude': 13.4357804, 'longitude': 37.7018481, 'category': 'settlement',
21 | 'description': 'Ancient settlement in the western part of Sicily, probably '
22 | 'founded in the seventh century B.C.'}
23 | )
24 | self.assertEqual(json_parse["links"]["self"], 'http://localhost/place/1')
25 |
26 | # On vérifie que le lien est correct
27 | seconde_requete = self.client.get(json_parse["links"]["self"])
28 | self.assertEqual(seconde_requete.status_code, 200)
29 |
--------------------------------------------------------------------------------
/data/scripts/download_pleiades.py:
--------------------------------------------------------------------------------
1 | """ Ce script a pour but de générer un ensemble de données tests pour le cours sur Flask
2 |
3 | Les données originelles sont toutes issues de https://pleiades.stoa.org
4 |
5 | """
6 | from requests import get
7 | from csv import writer
8 | import os
9 |
10 |
11 | dir_path, _ = os.path.split(os.path.realpath(__file__)) # On utilise la variable nommée "_" par convention
12 | # pour des données d'un tuple que l'on ne veut pas
13 | target_path = os.path.join(dir_path, "..", "csv", "pleiades.csv")
14 |
15 | places_to_retrieve = [462247, 511337, 59687, 187410, 462283, 874299107,
16 | 264408879, 423052, 79368, 599578, 727090, 570180, 138369, 695491849, 589981]
17 | csv_list = [
18 | ["place_id", "place_nom", "place_description", "place_longitude", "place_latitude", "place_type"]
19 | ]
20 |
21 | for index, place in enumerate(places_to_retrieve):
22 | response = get("https://pleiades.stoa.org/places/{}/json".format(place))
23 | data = response.json()
24 | lat, long = tuple(data["reprPoint"])
25 | description = data["description"]
26 | nom = data["title"]
27 | place_type = data["placeTypes"][0]
28 | csv_list.append([index, nom, description, long, lat, place_type])
29 |
30 | with open(target_path, "w") as f:
31 | csv_writer = writer(f)
32 | for row in csv_list:
33 | csv_writer.writerow(row)
34 |
--------------------------------------------------------------------------------
/cours-flask/exemple13/gazetteer/routes.py:
--------------------------------------------------------------------------------
1 | from flask import render_template, request
2 |
3 |
4 | from .app import app
5 | from .modeles.donnees import Place
6 |
7 |
8 | @app.route("/")
9 | def accueil():
10 | # On a bien sûr aussi modifié le template pour refléter le changement
11 | lieux = Place.query.all()
12 | return render_template("pages/accueil.html", nom="Gazetteer", lieux=lieux)
13 |
14 |
15 | @app.route("/place/")
16 | def lieu(place_id):
17 | # On a bien sûr aussi modifié le template pour refléter le changement
18 | unique_lieu = Place.query.get(place_id)
19 | return render_template("pages/place.html", nom="Gazetteer", lieu=unique_lieu)
20 |
21 |
22 | @app.route("/recherche")
23 | def recherche():
24 | # On préfèrera l'utilisation de .get() ici
25 | # qui nous permet d'éviter un if long (if "clef" in dictionnaire and dictonnaire["clef"])
26 | motclef = request.args.get("keyword", None)
27 | # On crée une liste vide de résultat (qui restera vide par défaut
28 | # si on n'a pas de mot clé)
29 | resultats = []
30 | # On fait de même pour le titre de la page
31 | titre = "Recherche"
32 | if motclef:
33 | resultats = Place.query.filter(
34 | Place.place_nom.like("%{}%".format(motclef))
35 | ).all()
36 | titre = "Résultat pour la recherche `" + motclef + "`"
37 | return render_template("pages/recherche.html", resultats=resultats, titre=titre)
38 |
--------------------------------------------------------------------------------
/cours-flask/exemple14/gazetteer/routes.py:
--------------------------------------------------------------------------------
1 | from flask import render_template, request
2 |
3 |
4 | from .app import app
5 | from .modeles.donnees import Place
6 |
7 |
8 | @app.route("/")
9 | def accueil():
10 | # On a bien sûr aussi modifié le template pour refléter le changement
11 | lieux = Place.query.all()
12 | return render_template("pages/accueil.html", nom="Gazetteer", lieux=lieux)
13 |
14 |
15 | @app.route("/place/")
16 | def lieu(place_id):
17 | # On a bien sûr aussi modifié le template pour refléter le changement
18 | unique_lieu = Place.query.get(place_id)
19 | return render_template("pages/place.html", nom="Gazetteer", lieu=unique_lieu)
20 |
21 |
22 | @app.route("/recherche")
23 | def recherche():
24 | # On préfèrera l'utilisation de .get() ici
25 | # qui nous permet d'éviter un if long (if "clef" in dictionnaire and dictonnaire["clef"])
26 | motclef = request.args.get("keyword", None)
27 | # On crée une liste vide de résultat (qui restera vide par défaut
28 | # si on n'a pas de mot clé)
29 | resultats = []
30 | # On fait de même pour le titre de la page
31 | titre = "Recherche"
32 | if motclef:
33 | resultats = Place.query.filter(
34 | Place.place_nom.like("%{}%".format(motclef))
35 | ).all()
36 | titre = "Résultat pour la recherche `" + motclef + "`"
37 | return render_template("pages/recherche.html", resultats=resultats, titre=titre)
38 |
--------------------------------------------------------------------------------
/cours-flask/exemple17/gazetteer/templates/pages/browse.html:
--------------------------------------------------------------------------------
1 | {% extends "conteneur.html" %}
2 |
3 | {% block titre %}| Navigation : Page {{resultats.page}}{%endblock%}
4 |
5 | {% block corps %}
6 |
7 |
Navigation
8 | {% if resultats %}
9 |
Il y a {{resultats.total}} lieux qui répondent à votre requête :
17 |
41 | {% endif %}
42 | {% endblock %}
--------------------------------------------------------------------------------
/cours-flask/exemple6/app.py:
--------------------------------------------------------------------------------
1 | from flask import Flask, render_template
2 |
3 | app = Flask("Application")
4 |
5 | lieux = [
6 | {
7 | "nom": "Col. Lugdunum",
8 | "moderne": "Lyon",
9 | "latlong": [45.762095775, 4.822438025],
10 | "type": "ville",
11 | "description": "Col. Lugdunum was a Roman military colony from 43 BC and a major center in Gaul. Marcus "
12 | "Agrippa was involved in its expansion and two Roman emperors, Claudius and Caracalla, "
13 | "were born there."
14 | },
15 | {
16 | "nom": "Samarobriva Ambianorum",
17 | "moderne": "Amiens",
18 | "type": "ville",
19 | "description": "An ancient place, cited: BAtlas 11 C3 Samarobriva Ambianorum ",
20 | "latlong": [49.8936075, 2.297948]
21 | }
22 | ]
23 |
24 |
25 | @app.route("/")
26 | def accueil():
27 | return render_template("accueil.html", nom="Gazetteer", lieux=lieux)
28 |
29 |
30 | @app.route("/place/")
31 | def lieu(place_id):
32 | return render_template("place.html", nom="Gazetteer", lieu=lieux[place_id])
33 |
34 |
35 | # Ce if permet de vérifier que ce fichier est celui qui est courrament exécuté. Cela permet par exemple d'éviter
36 | # de lancer une fonction quand on importe ce fichier depuis un autre fichier.
37 | # En python, lorsque l'on exécute un script avec la commande `python script.py`
38 | # Le fichier `script.py` a en __name__ la valeur __main__.
39 | if __name__ == "__main__":
40 | app.run()
41 |
--------------------------------------------------------------------------------
/cours-flask/exemple7/app.py:
--------------------------------------------------------------------------------
1 | from flask import Flask, render_template
2 |
3 | app = Flask("Application")
4 |
5 | lieux = {
6 | 0: {
7 | "nom": "Col. Lugdunum",
8 | "moderne": "Lyon",
9 | "latlong": [45.762095775, 4.822438025],
10 | "type": "ville",
11 | "description": "Col. Lugdunum was a Roman military colony from 43 BC and a major center in Gaul. Marcus "
12 | "Agrippa was involved in its expansion and two Roman emperors, Claudius and Caracalla, "
13 | "were born there."
14 | },
15 | 1: {
16 | "nom": "Samarobriva Ambianorum",
17 | "moderne": "Amiens",
18 | "type": "ville",
19 | "description": "An ancient place, cited: BAtlas 11 C3 Samarobriva Ambianorum ",
20 | "latlong": [49.8936075, 2.297948]
21 | }
22 | }
23 |
24 |
25 | @app.route("/")
26 | def accueil():
27 | return render_template("accueil.html", nom="Gazetteer", lieux=lieux)
28 |
29 |
30 | @app.route("/place/")
31 | def lieu(place_id):
32 | return render_template("place.html", nom="Gazetteer", lieu=lieux[place_id])
33 |
34 |
35 | # Ce if permet de vérifier que ce fichier est celui qui est courrament exécuté. Cela permet par exemple d'éviter
36 | # de lancer une fonction quand on importe ce fichier depuis un autre fichier.
37 | # En python, lorsque l'on exécute un script avec la commande `python script.py`
38 | # Le fichier `script.py` a en __name__ la valeur __main__.
39 | if __name__ == "__main__":
40 | app.run()
41 |
--------------------------------------------------------------------------------
/cours-flask/exemple10/app.py:
--------------------------------------------------------------------------------
1 | from flask import Flask, render_template
2 |
3 | app = Flask("Application")
4 |
5 | lieux = {
6 | 0: {
7 | "nom": "Col. Lugdunum",
8 | "moderne": "Lyon",
9 | "latlong": [45.762095775, 4.822438025],
10 | "type": "ville",
11 | "description": "Col. Lugdunum was a Roman military colony from 43 BC and a major center in Gaul. Marcus "
12 | "Agrippa was involved in its expansion and two Roman emperors, Claudius and Caracalla, "
13 | "were born there."
14 | },
15 | 1: {
16 | "nom": "Samarobriva Ambianorum",
17 | "moderne": "Amiens",
18 | "type": "ville",
19 | "description": "An ancient place, cited: BAtlas 11 C3 Samarobriva Ambianorum ",
20 | "latlong": [49.8936075, 2.297948]
21 | }
22 | }
23 |
24 |
25 | @app.route("/")
26 | def accueil():
27 | return render_template("pages/accueil.html", nom="Gazetteer", lieux=lieux)
28 |
29 |
30 | @app.route("/place/")
31 | def lieu(place_id):
32 | return render_template("pages/place.html", nom="Gazetteer", lieu=lieux[place_id])
33 |
34 |
35 | # Ce if permet de vérifier que ce fichier est celui qui est courrament exécuté. Cela permet par exemple d'éviter
36 | # de lancer une fonction quand on importe ce fichier depuis un autre fichier.
37 | # En python, lorsque l'on exécute un script avec la commande `python script.py`
38 | # Le fichier `script.py` a en __name__ la valeur __main__.
39 | if __name__ == "__main__":
40 | app.run(debug=True)
41 |
--------------------------------------------------------------------------------
/cours-flask/exemple8/app.py:
--------------------------------------------------------------------------------
1 | from flask import Flask, render_template
2 |
3 | app = Flask("Application")
4 |
5 | lieux = {
6 | 0: {
7 | "nom": "Col. Lugdunum",
8 | "moderne": "Lyon",
9 | "latlong": [45.762095775, 4.822438025],
10 | "type": "ville",
11 | "description": "Col. Lugdunum was a Roman military colony from 43 BC and a major center in Gaul. Marcus "
12 | "Agrippa was involved in its expansion and two Roman emperors, Claudius and Caracalla, "
13 | "were born there."
14 | },
15 | 1: {
16 | "nom": "Samarobriva Ambianorum",
17 | "moderne": "Amiens",
18 | "type": "ville",
19 | "description": "An ancient place, cited: BAtlas 11 C3 Samarobriva Ambianorum ",
20 | "latlong": [49.8936075, 2.297948]
21 | }
22 | }
23 |
24 |
25 | @app.route("/")
26 | def accueil():
27 | return render_template("pages/accueil.html", nom="Gazetteer", lieux=lieux)
28 |
29 |
30 | @app.route("/place/")
31 | def lieu(place_id):
32 | return render_template("pages/place.html", nom="Gazetteer", lieu=lieux[place_id])
33 |
34 |
35 | # Ce if permet de vérifier que ce fichier est celui qui est courrament exécuté. Cela permet par exemple d'éviter
36 | # de lancer une fonction quand on importe ce fichier depuis un autre fichier.
37 | # En python, lorsque l'on exécute un script avec la commande `python script.py`
38 | # Le fichier `script.py` a en __name__ la valeur __main__.
39 | if __name__ == "__main__":
40 | app.run(debug=True)
41 |
--------------------------------------------------------------------------------
/cours-flask/exemple9/app.py:
--------------------------------------------------------------------------------
1 | from flask import Flask, render_template
2 |
3 | app = Flask("Application")
4 |
5 | lieux = {
6 | 0: {
7 | "nom": "Col. Lugdunum",
8 | "moderne": "Lyon",
9 | "latlong": [45.762095775, 4.822438025],
10 | "type": "ville",
11 | "description": "Col. Lugdunum was a Roman military colony from 43 BC and a major center in Gaul. Marcus "
12 | "Agrippa was involved in its expansion and two Roman emperors, Claudius and Caracalla, "
13 | "were born there."
14 | },
15 | 1: {
16 | "nom": "Samarobriva Ambianorum",
17 | "moderne": "Amiens",
18 | "type": "ville",
19 | "description": "An ancient place, cited: BAtlas 11 C3 Samarobriva Ambianorum ",
20 | "latlong": [49.8936075, 2.297948]
21 | }
22 | }
23 |
24 |
25 | @app.route("/")
26 | def accueil():
27 | return render_template("pages/accueil.html", nom="Gazetteer", lieux=lieux)
28 |
29 |
30 | @app.route("/place/")
31 | def lieu(place_id):
32 | return render_template("pages/place.html", nom="Gazetteer", lieu=lieux[place_id])
33 |
34 |
35 | # Ce if permet de vérifier que ce fichier est celui qui est courrament exécuté. Cela permet par exemple d'éviter
36 | # de lancer une fonction quand on importe ce fichier depuis un autre fichier.
37 | # En python, lorsque l'on exécute un script avec la commande `python script.py`
38 | # Le fichier `script.py` a en __name__ la valeur __main__.
39 | if __name__ == "__main__":
40 | app.run(debug=True)
41 |
--------------------------------------------------------------------------------
/data/cid.v1071.1682.txt:
--------------------------------------------------------------------------------
1 | Il n'est pas temps encor de chercher le trépas :
2 | Ton prince et ton pays ont besoin de ton bras.
3 | La flotte qu'on craignait, dans ce grand fleuve entrée,
4 | Croit surprendre la ville et piller la contrée.
5 | Les Mores vont descendre, et le flux et la nuit
6 | Dans une heure à nos murs les amène sans bruit.
7 | La Cour est en désordre, et le peuple en alarmes :
8 | On n'entend que des cris, on ne voit que des larmes.
9 | Dans ce malheur public mon bonheur a permis
10 | Que j'ai trouvé chez moi cinq cents de mes amis,
11 | Qui sachant mon affront, poussés d'un même zèle,
12 | Se venaient tous offrir à venger ma querelle.
13 | Tu les as prévenus ; mais leurs vaillantes mains
14 | Se tremperont bien mieux au sang des Africains.
15 | Va marcher à leur tete où l'honneur te demande :
16 | C'est toi que veut pour chef leur généreuse bande.
17 | De ces vieux ennemis va soutenir l'abord :
18 | Là, si tu veux mourir, trouve une belle mort ;
19 | Prends-en l'occasion, puisqu'elle t'est offerte ;
20 | Fais devoir à ton roi son salut à ta perte ;
21 | Mais reviens-en plutôt les palmes sur le front.
22 | Ne borne pas ta gloire à venger un affront ;
23 | Porte-la plus avant : force par ta vaillance
24 | Ce monarque au pardon, et Chimène au silence ;
25 | Si tu l'aimes, apprends que revenir vainqueur,
26 | C'est l'unique moyen de regagner son coeur.
27 | Mais le temps est trop cher pour le perdre en paroles ;
28 | Je t'arrete en discours, et je veux que tu voles.
29 | Viens, suis-moi, va combattre, et montrer à ton roi
30 | Que ce qu'il perd au comte il le recouvre en toi.
--------------------------------------------------------------------------------
/cours-flask/exemple11/app.py:
--------------------------------------------------------------------------------
1 | from flask import Flask, render_template
2 | from flask_sqlalchemy import SQLAlchemy
3 |
4 | app = Flask("Application")
5 | # On configure la base de données
6 | app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///../db.sqlite'
7 | # On initie l'extension
8 | db = SQLAlchemy(app)
9 |
10 |
11 | # On crée notre modèle
12 | class Place(db.Model):
13 | place_id = db.Column(db.Integer, unique=True, nullable=False, primary_key=True, autoincrement=True)
14 | place_nom = db.Column(db.Text)
15 | place_description = db.Column(db.Text)
16 | place_longitude = db.Column(db.Float)
17 | place_latitude = db.Column(db.Float)
18 | place_type = db.Column(db.String(45))
19 |
20 |
21 | @app.route("/")
22 | def accueil():
23 | # On a bien sûr aussi modifié le template pour refléter le changement
24 | lieux = Place.query.all()
25 | return render_template("pages/accueil.html", nom="Gazetteer", lieux=lieux)
26 |
27 |
28 | @app.route("/place/")
29 | def lieu(place_id):
30 | # On a bien sûr aussi modifié le template pour refléter le changement
31 | unique_lieu = Place.query.get(place_id)
32 | return render_template("pages/place.html", nom="Gazetteer", lieu=unique_lieu)
33 |
34 |
35 | # Ce if permet de vérifier que ce fichier est celui qui est courrament exécuté. Cela permet par exemple d'éviter
36 | # de lancer une fonction quand on importe ce fichier depuis un autre fichier.
37 | # En python, lorsque l'on exécute un script avec la commande `python script.py`
38 | # Le fichier `script.py` a en __name__ la valeur __main__.
39 | if __name__ == "__main__":
40 | app.run(debug=True)
41 |
--------------------------------------------------------------------------------
/cours-flask/README.md:
--------------------------------------------------------------------------------
1 | Ce dossier contient des exemples d'application Flask
2 |
3 | 1. [Ma première application Flask : créer une URL](exemple1/app.py)
4 | 2. [Ma première application Flask : créer une route avec paramètre](exemple2/app.py)
5 | 3. [Ma première application Flask : créer une route avec paramètre typé](exemple3/app.py)
6 | 4. [Ma première application Flask : les templates](exemple4/app.py) [Template](exemple4/templates/accueil.html)
7 | 5. [Ma première application Flask : les conditions](exemple5/app.py) [Template](exemple5/templates/accueil.html)
8 | 6. [Ma première application Flask : les dictionnaire](exemple6/app.py) [Template](exemple6/templates/accueil.html) [Template de /place/](exemple6/templates/accueil.html)
9 | 7. [Ma première application Flask : les boucles et les liens ](exemple7/app.py) [Template](exemple7/templates/accueil.html) [Template de /place/](exemple7/templates/accueil.html)
10 | 8. [Ma première application Flask : les conteneurs](exemple8/app.py) [Template Conteneur](exemple8/templates/conteneur.html) [Template Accueil](exemple8/templates/pages/accueil.html) [Template Place](exemple8/templates/pages/place.html)
11 | 9. [Ma première application Flask : les conteneurs avec includes](exemple9/app.py) [Template Conteneur](exemple9/templates/conteneur.html) [Template Metadata](exemple9/templates/partials/metadata.html) [Template Accueil](exemple9/templates/pages/accueil.html) [Template Place](exemple9/templates/pages/place.html)
12 | 9. [Ma première application Flask : les assets](exemple10/app.py) [Static](exemple10/static) [Templates](exemple10/templates) [Template CSS (inclut dans conteneur)](exemple10/templates/partials/css.html)
13 |
--------------------------------------------------------------------------------
/cours-flask/exemple16/gazetteer/templates/pages/inscription.html:
--------------------------------------------------------------------------------
1 | {% extends "conteneur.html" %}
2 |
3 | {% block titre %}| Inscription{%endblock%}
4 |
5 | {% block corps %}
6 |
7 |
Inscription
8 |
Complétez le formulaire et cliquez sur "S'inscrire".
Complétez le formulaire et cliquez sur "S'inscrire".
9 |
38 | {% endblock %}
--------------------------------------------------------------------------------
/biliopat.csv:
--------------------------------------------------------------------------------
1 | Titre Lien Date
2 | Ouverture des inscriptions aux Journées BiblioPat 2017 http://www.bibliopat.fr/actualite-BiblioPat/ouverture-des-inscriptions-aux-journees-bibliopat-2017 Mon, 25 Sep 2017 14:43:04 +0000
3 | TEAM @BiblioPat_fr : ça gazouille http://www.bibliopat.fr/actualite-BiblioPat/team-bibliopatfr-ca-gazouille Wed, 08 Feb 2017 15:14:34 +0000
4 | Voeux de l'association http://www.bibliopat.fr/actualite-BiblioPat/voeux-de-lassociation Mon, 16 Jan 2017 16:51:02 +0000
5 | "Visites guidées de l'exposition ""Des livres et des lettres"" (Bib. Mazarine)" http://www.bibliopat.fr/actualite-BiblioPat/visites-guidees-de-lexposition-des-livres-et-des-lettres-bib-mazarine Sat, 19 Nov 2016 13:57:53 +0000
6 | Participez aux concours pour les 10 ans de BiblioPat http://www.bibliopat.fr/actualite-BiblioPat/participez-aux-concours-pour-les-10-ans-de-bibliopat Tue, 25 Oct 2016 09:16:23 +0000
7 | Ouverture des inscriptions aux Journées BiblioPat 2016 http://www.bibliopat.fr/actualite-BiblioPat/ouverture-des-inscriptions-aux-journees-bibliopat-2016 Mon, 10 Oct 2016 12:41:54 +0000
8 | Meilleurs voeux 2016 http://www.bibliopat.fr/actualite-BiblioPat/meilleurs-voeux-2016 Fri, 29 Jan 2016 07:15:59 +0000
9 | Journées BiblioPat 2015 en images http://www.bibliopat.fr/actualite-BiblioPat/journees-bibliopat-2015-en-images Fri, 13 Nov 2015 10:12:43 +0000
10 | Fin de l'ouverture des contenus aux abonnés http://www.bibliopat.fr/actualite-BiblioPat/fin-de-louverture-des-contenus-aux-abonnes Thu, 30 Apr 2015 16:40:11 +0000
11 | "Visite guidée de l'exposition ""De l'argile au nuage : une archéologie des catalogues""" http://www.bibliopat.fr/actualite-BiblioPat/visite-guidee-de-lexposition-de-largile-au-nuage-une-archeologie-des-catalogues Tue, 14 Apr 2015 15:05:28 +0000
12 |
--------------------------------------------------------------------------------
/data/lettre.louisemichel.txt:
--------------------------------------------------------------------------------
1 | [non daté]
2 |
3 | (Entre le 10 et le 23) octobre 1850
4 |
5 | Monsieur,
6 |
7 | Je ne sais ce que je vous dirai mais je suis au désespoir et il faut que je vous écrive pour souffrir moins. Je ne m’inquiète pas si ma lettre doit vous paraître étrange car vous ne me connaissez pas et tout ce qui me tourmente ne peut vous toucher, mais il faut que je vous le dise pour me calmer un instant.
8 |
9 | Mme Dehamis, ma grand-mère que je ne n’ai jamais quittée, est dangereusement malade et je me trouve sans force et sans courage contre cette affreuse inquiétude. Je suis comme folle, je ne sais ce que je fais ni ce que je dis. L’idée de la perdre est horrible pour moi et je n’en ai pas d’autre. Je vois bien qu’il n’y a plus d’espoir et que tout ce qu’on me dit de rassurant n’est que pour me consoler et cependant, malgré son âge, je ne puis m’imaginer qu’il me soit possible de vivre sans elle. J’oublie presque qu’il me resterait ma mère à consoler. Depuis que je suis au monde, je n’ai jamais quitté mon aïeule. Elle a été ma seule institutrice. Nous ne vivions que l’une pour l’autre et maintenant tout cela va finir. Je ne sais ce que je vous dis. Mes idées se brouillent mais vous me pardonnerez et vous m’écrirez quelques lignes pour me donner un peu de courage car je n’en ai plus. On dit que je suis pieuse, eh bien, si je la perdais, il me semble que je ne croirais plus rien. Dieu serait trop cruel.
10 |
11 | Je trouve sous ma main je ne sais quels brouillons ; je vous les envoie. Ce sont peut-être les derniers que vous recevrez de moi. Si je la perdais, je ne ferais plus rien ou bien cela me ferait mourir. Alors, frère, vous feriez quelques vers sur ma tombe. Adieu, pardon de cette lettre, je suis folle de douleur, je ne sais que devenir, tout me semble mort, écrivez-moi.
--------------------------------------------------------------------------------
/cours-flask/exemple15/gazetteer/routes.py:
--------------------------------------------------------------------------------
1 | from flask import render_template, request
2 |
3 |
4 | from .app import app
5 | from .modeles.donnees import Place
6 |
7 |
8 | LIEUX_PAR_PAGES = 2
9 |
10 |
11 | @app.route("/")
12 | def accueil():
13 | # On a bien sûr aussi modifié le template pour refléter le changement
14 | lieux = Place.query.order_by(Place.place_id.desc()).limit(5).all()
15 | return render_template("pages/accueil.html", nom="Gazetteer", lieux=lieux)
16 |
17 |
18 | @app.route("/place/")
19 | def lieu(place_id):
20 | # On a bien sûr aussi modifié le template pour refléter le changement
21 | unique_lieu = Place.query.get(place_id)
22 | return render_template("pages/place.html", nom="Gazetteer", lieu=unique_lieu)
23 |
24 |
25 | @app.route("/recherche")
26 | def recherche():
27 | # On préfèrera l'utilisation de .get() ici
28 | # qui nous permet d'éviter un if long (if "clef" in dictionnaire and dictonnaire["clef"])
29 | motclef = request.args.get("keyword", None)
30 | page = request.args.get("page", 1)
31 |
32 | if isinstance(page, str) and page.isdigit():
33 | page = int(page)
34 | else:
35 | page = 1
36 |
37 | # On crée une liste vide de résultat (qui restera vide par défaut
38 | # si on n'a pas de mot clé)
39 | resultats = []
40 |
41 | # On fait de même pour le titre de la page
42 | titre = "Recherche"
43 | if motclef:
44 | resultats = Place.query.filter(
45 | Place.place_nom.like("%{}%".format(motclef))
46 | ).paginate(page=page, per_page=LIEUX_PAR_PAGES)
47 | titre = "Résultat pour la recherche `" + motclef + "`"
48 |
49 | return render_template(
50 | "pages/recherche.html",
51 | resultats=resultats,
52 | titre=titre,
53 | keyword=motclef
54 | )
55 |
--------------------------------------------------------------------------------
/exercices/Fichiers.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "## Boucles\n",
8 | "\n",
9 | "Sachant que la fonction et les paramètres `glob(\"../data/*.txt\")` dans la première cellule retourne l'ensemble des fichiers disponibles finissant par `*.txt` dans `../data`:\n",
10 | "\n",
11 | "1. Comptez le nombre de chaque mot dans chaque texte\n",
12 | "2. Combien de mots ne sont présents que dans un texte ?"
13 | ]
14 | },
15 | {
16 | "cell_type": "code",
17 | "execution_count": null,
18 | "metadata": {},
19 | "outputs": [],
20 | "source": [
21 | "# Exécuter mais ne pas modifier.\n",
22 | "from glob import glob"
23 | ]
24 | },
25 | {
26 | "cell_type": "code",
27 | "execution_count": null,
28 | "metadata": {},
29 | "outputs": [],
30 | "source": [
31 | "glob(\"../data/*.txt\")"
32 | ]
33 | },
34 | {
35 | "cell_type": "markdown",
36 | "metadata": {},
37 | "source": [
38 | "## De plein texte à TEI\n",
39 | "\n",
40 | "À partir de la variage `text`, créer un fichier `lesdeuxamants.xml` qui soit de la TEI valide. Le corps du texte doit contenir une `div`, un `head`, des `lg`s et des `l`s. Les `l`s seront numérotées via l'attribut `n`."
41 | ]
42 | },
43 | {
44 | "cell_type": "code",
45 | "execution_count": null,
46 | "metadata": {},
47 | "outputs": [],
48 | "source": [
49 | "# Exécuter mais ne pas modifier\n",
50 | "with open(\"../data/lesdeuxamants.txt\") as f:\n",
51 | " text = f.read()"
52 | ]
53 | }
54 | ],
55 | "metadata": {
56 | "kernelspec": {
57 | "display_name": "Python 3",
58 | "language": "python",
59 | "name": "python3"
60 | },
61 | "language_info": {
62 | "codemirror_mode": {
63 | "name": "ipython",
64 | "version": 3
65 | },
66 | "file_extension": ".py",
67 | "mimetype": "text/x-python",
68 | "name": "python",
69 | "nbconvert_exporter": "python",
70 | "pygments_lexer": "ipython3",
71 | "version": "3.6.9"
72 | }
73 | },
74 | "nbformat": 4,
75 | "nbformat_minor": 2
76 | }
77 |
--------------------------------------------------------------------------------
/cours-flask/exemple17/gazetteer/modeles/donnees.py:
--------------------------------------------------------------------------------
1 | from flask import url_for
2 | import datetime
3 |
4 | from .. app import db
5 |
6 |
7 | class Authorship(db.Model):
8 | __tablename__ = "authorship"
9 | authorship_id = db.Column(db.Integer, nullable=True, autoincrement=True, primary_key=True)
10 | authorship_place_id = db.Column(db.Integer, db.ForeignKey('place.place_id'))
11 | authorship_user_id = db.Column(db.Integer, db.ForeignKey('user.user_id'))
12 | authorship_date = db.Column(db.DateTime, default=datetime.datetime.utcnow)
13 | user = db.relationship("User", back_populates="authorships")
14 | place = db.relationship("Place", back_populates="authorships")
15 |
16 | def author_to_json(self):
17 | return {
18 | "author": self.user.to_jsonapi_dict(),
19 | "on": self.authorship_date
20 | }
21 |
22 |
23 | # On crée notre modèle
24 | class Place(db.Model):
25 | place_id = db.Column(db.Integer, unique=True, nullable=False, primary_key=True, autoincrement=True)
26 | place_nom = db.Column(db.Text)
27 | place_description = db.Column(db.Text)
28 | place_longitude = db.Column(db.Float)
29 | place_latitude = db.Column(db.Float)
30 | place_type = db.Column(db.String(45))
31 | authorships = db.relationship("Authorship", back_populates="place")
32 |
33 | def to_jsonapi_dict(self):
34 | """ It ressembles a little JSON API format but it is not completely compatible
35 |
36 | :return:
37 | """
38 | return {
39 | "type": "place",
40 | "id": self.place_id,
41 | "attributes": {
42 | "name": self.place_nom,
43 | "description": self.place_description,
44 | "longitude": self.place_longitude,
45 | "latitude": self.place_latitude,
46 | "category": self.place_type
47 | },
48 | "links": {
49 | "self": url_for("lieu", place_id=self.place_id, _external=True),
50 | "json": url_for("api_places_single", place_id=self.place_id, _external=True)
51 | },
52 | "relationships": {
53 | "editions": [
54 | author.author_to_json()
55 | for author in self.authorships
56 | ]
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/cours-flask/exemple18/gazetteer/modeles/donnees.py:
--------------------------------------------------------------------------------
1 | from flask import url_for
2 | import datetime
3 |
4 | from .. app import db
5 |
6 |
7 | class Authorship(db.Model):
8 | __tablename__ = "authorship"
9 | authorship_id = db.Column(db.Integer, nullable=True, autoincrement=True, primary_key=True)
10 | authorship_place_id = db.Column(db.Integer, db.ForeignKey('place.place_id'))
11 | authorship_user_id = db.Column(db.Integer, db.ForeignKey('user.user_id'))
12 | authorship_date = db.Column(db.DateTime, default=datetime.datetime.utcnow)
13 | user = db.relationship("User", back_populates="authorships")
14 | place = db.relationship("Place", back_populates="authorships")
15 |
16 | def author_to_json(self):
17 | return {
18 | "author": self.user.to_jsonapi_dict(),
19 | "on": self.authorship_date
20 | }
21 |
22 |
23 | # On crée notre modèle
24 | class Place(db.Model):
25 | place_id = db.Column(db.Integer, unique=True, nullable=False, primary_key=True, autoincrement=True)
26 | place_nom = db.Column(db.Text)
27 | place_description = db.Column(db.Text)
28 | place_longitude = db.Column(db.Float)
29 | place_latitude = db.Column(db.Float)
30 | place_type = db.Column(db.String(45))
31 | authorships = db.relationship("Authorship", back_populates="place")
32 |
33 | def to_jsonapi_dict(self):
34 | """ It ressembles a little JSON API format but it is not completely compatible
35 |
36 | :return:
37 | """
38 | return {
39 | "type": "place",
40 | "id": self.place_id,
41 | "attributes": {
42 | "name": self.place_nom,
43 | "description": self.place_description,
44 | "longitude": self.place_longitude,
45 | "latitude": self.place_latitude,
46 | "category": self.place_type
47 | },
48 | "links": {
49 | "self": url_for("lieu", place_id=self.place_id, _external=True),
50 | "json": url_for("api_places_single", place_id=self.place_id, _external=True)
51 | },
52 | "relationships": {
53 | "editions": [
54 | author.author_to_json()
55 | for author in self.authorships
56 | ]
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/data/misanthrope.acte3.scene4.txt:
--------------------------------------------------------------------------------
1 | Madame, j'ai beaucoup de grâces à vous rendre :
2 | un tel avis m'oblige, et loin de le mal prendre,
3 | j'en prétends reconnoître, à l'instant, la faveur,
4 | par un avis aussi qui touche votre honneur ;
5 | et comme je vous vois vous montrer mon amie
6 | en m'apprenant les bruits que de moi l'on publie,
7 | je veux suivre, à mon tour, un exemple si doux,
8 | en vous avertissant de ce qu'on dit de vous.
9 | En un lieu, l'autre jour, où je faisois visite,
10 | je trouvai quelques gens d'un très-rare mérite,
11 | qui, parlant des vrais soins d'une âme qui vit bien,
12 | firent tomber sur vous, madame, l'entretien.
13 | Là, votre pruderie et vos éclats de zèle
14 | ne furent pas cités comme un fort bon modèle :
15 | cette affectation d'un grave extérieur,
16 | vos discours éternels de sagesse et d'honneur,
17 | vos mines et vos cris aux ombres d'indécence
18 | que d'un mot ambigu peut avoir l'innocence,
19 | cette hauteur d'estime où vous êtes de vous,
20 | et ces yeux de pitié que vous jetez sur tous,
21 | vos fréquentes leçons, et vos aigres censures
22 | sur des choses qui sont innocentes et pures,
23 | tout cela, si je puis vous parler franchement,
24 | madame, fut blâmé d'un commun sentiment.
25 | à quoi bon, disoient-ils, cette mine modeste,
26 | et ce sage dehors que dément tout le reste ?
27 | Elle est à bien prier exacte au dernier point ;
28 | mais elle bat ses gens, et ne les paye point.
29 | Dans tous les lieux dévots elle étale un grand zèle ;
30 | mais elle met du blanc et veut paroître belle.
31 | Elle fait des tableaux couvrir les nudités ;
32 | mais elle a de l'amour pour les réalités.
33 | Pour moi, contre chacun je pris votre défense,
34 | et leur assurai fort que c'étoit médisance ;
35 | mais tous les sentiments combattirent le mien ;
36 | et leur conclusion fut que vous feriez bien
37 | de prendre moins de soin des actions des autres,
38 | et de vous mettre un peu plus en peine des vôtres ;
39 | qu'on doit se regarder soi-même un fort long temps,
40 | avant que de songer à condamner les gens ;
41 | qu'il faut mettre le poids d'une vie exemplaire
42 | dans les corrections qu'aux autres on veut faire ;
43 | et qu'encor vaut-il mieux s'en remettre, au besoin,
44 | à ceux à qui le ciel en a commis le soin.
45 | Madame, je vous crois aussi trop raisonnable,
46 | pour ne pas prendre bien cet avis profitable,
47 | et pour l'attribuer qu'aux mouvements secrets
48 | d'un zèle qui m'attache à tous vos intérêts.
--------------------------------------------------------------------------------
/exercices/CSV.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "attachments": {},
5 | "cell_type": "markdown",
6 | "metadata": {},
7 | "source": [
8 | "# Exercices CSV\n",
9 | "\n",
10 | "À partir du fichier `data/csv/stages.csv` :\n",
11 | "\n",
12 | "1. Comptez le nombre de stage en France, à l'Étranger.\n",
13 | "2. Quelle est la durée moyenne de stage proposée ?\n",
14 | "3. Classez les livrables (Données\tCahier des charges\tPrototype\tRecommandation\tValorisation) en fonction de leur présence\n",
15 | "4. Faire de même pour les mots-clefs et les technologies\n",
16 | "5. De même pour les institutions\n",
17 | "6. Classez les livrables par type d'institution.\n",
18 | "\n",
19 | "Pour bien profiter de l'exercice, utilisez une cellule par mission.\n",
20 | "\n",
21 | "7. Créer un fichier conservant les classements 3, 4, 5 et 6."
22 | ]
23 | },
24 | {
25 | "cell_type": "code",
26 | "execution_count": null,
27 | "metadata": {},
28 | "outputs": [],
29 | "source": []
30 | },
31 | {
32 | "cell_type": "code",
33 | "execution_count": null,
34 | "metadata": {},
35 | "outputs": [],
36 | "source": []
37 | },
38 | {
39 | "cell_type": "code",
40 | "execution_count": null,
41 | "metadata": {},
42 | "outputs": [],
43 | "source": []
44 | },
45 | {
46 | "cell_type": "code",
47 | "execution_count": null,
48 | "metadata": {},
49 | "outputs": [],
50 | "source": []
51 | },
52 | {
53 | "cell_type": "code",
54 | "execution_count": null,
55 | "metadata": {},
56 | "outputs": [],
57 | "source": []
58 | },
59 | {
60 | "cell_type": "code",
61 | "execution_count": null,
62 | "metadata": {},
63 | "outputs": [],
64 | "source": []
65 | },
66 | {
67 | "cell_type": "code",
68 | "execution_count": null,
69 | "metadata": {},
70 | "outputs": [],
71 | "source": []
72 | }
73 | ],
74 | "metadata": {
75 | "kernelspec": {
76 | "display_name": "Python 3",
77 | "language": "python",
78 | "name": "python3"
79 | },
80 | "language_info": {
81 | "codemirror_mode": {
82 | "name": "ipython",
83 | "version": 3
84 | },
85 | "file_extension": ".py",
86 | "mimetype": "text/x-python",
87 | "name": "python",
88 | "nbconvert_exporter": "python",
89 | "pygments_lexer": "ipython3",
90 | "version": "3.8.0"
91 | }
92 | },
93 | "nbformat": 4,
94 | "nbformat_minor": 2
95 | }
96 |
--------------------------------------------------------------------------------
/cours-flask/exemple17/gazetteer/routes/api.py:
--------------------------------------------------------------------------------
1 | from flask import render_template, request, url_for, jsonify
2 | from urllib.parse import urlencode
3 |
4 | from ..app import app
5 | from ..constantes import LIEUX_PAR_PAGE, API_ROUTE
6 | from ..modeles.donnees import Place
7 |
8 |
9 | def Json_404():
10 | response = jsonify({"erreur": "Unable to perform the query"})
11 | response.status_code = 404
12 | return response
13 |
14 |
15 | @app.route(API_ROUTE+"/places/")
16 | def api_places_single(place_id):
17 | try:
18 | query = Place.query.get(place_id)
19 | return jsonify(query.to_jsonapi_dict())
20 | except:
21 | return Json_404()
22 |
23 |
24 | @app.route(API_ROUTE+"/places")
25 | def api_places_browse():
26 | """ Route permettant la recherche plein-texte
27 |
28 | On s'inspirera de http://jsonapi.org/ faute de pouvoir trouver temps d'y coller à 100%
29 | """
30 | # q est très souvent utilisé pour indiquer une capacité de recherche
31 | motclef = request.args.get("q", None)
32 | page = request.args.get("page", 1)
33 |
34 | if isinstance(page, str) and page.isdigit():
35 | page = int(page)
36 | else:
37 | page = 1
38 |
39 | if motclef:
40 | query = Place.query.filter(
41 | Place.place_nom.like("%{}%".format(motclef))
42 | )
43 | else:
44 | query = Place.query
45 |
46 | try:
47 | resultats = query.paginate(page=page, per_page=LIEUX_PAR_PAGE)
48 | except Exception:
49 | return Json_404()
50 |
51 | dict_resultats = {
52 | "links": {
53 | "self": request.url
54 | },
55 | "data": [
56 | place.to_jsonapi_dict()
57 | for place in resultats.items
58 | ]
59 | }
60 |
61 | if resultats.has_next:
62 | arguments = {
63 | "page": resultats.next_num
64 | }
65 | if motclef:
66 | arguments["q"] = motclef
67 | dict_resultats["links"]["next"] = url_for("api_places_browse", _external=True)+"?"+urlencode(arguments)
68 |
69 | if resultats.has_prev:
70 | arguments = {
71 | "page": resultats.prev_num
72 | }
73 | if motclef:
74 | arguments["q"] = motclef
75 | dict_resultats["links"]["prev"] = url_for("api_places_browse", _external=True)+"?"+urlencode(arguments)
76 |
77 | response = jsonify(dict_resultats)
78 | return response
79 |
--------------------------------------------------------------------------------
/cours-flask/exemple18/gazetteer/routes/api.py:
--------------------------------------------------------------------------------
1 | from flask import render_template, request, url_for, jsonify
2 | from urllib.parse import urlencode
3 |
4 | from ..app import app
5 | from ..constantes import LIEUX_PAR_PAGE, API_ROUTE
6 | from ..modeles.donnees import Place
7 |
8 |
9 | def Json_404():
10 | response = jsonify({"erreur": "Unable to perform the query"})
11 | response.status_code = 404
12 | return response
13 |
14 |
15 | @app.route(API_ROUTE+"/places/")
16 | def api_places_single(place_id):
17 | try:
18 | query = Place.query.get(place_id)
19 | return jsonify(query.to_jsonapi_dict())
20 | except:
21 | return Json_404()
22 |
23 |
24 | @app.route(API_ROUTE+"/places")
25 | def api_places_browse():
26 | """ Route permettant la recherche plein-texte
27 |
28 | On s'inspirera de http://jsonapi.org/ faute de pouvoir trouver temps d'y coller à 100%
29 | """
30 | # q est très souvent utilisé pour indiquer une capacité de recherche
31 | motclef = request.args.get("q", None)
32 | page = request.args.get("page", 1)
33 |
34 | if isinstance(page, str) and page.isdigit():
35 | page = int(page)
36 | else:
37 | page = 1
38 |
39 | if motclef:
40 | query = Place.query.filter(
41 | Place.place_nom.like("%{}%".format(motclef))
42 | )
43 | else:
44 | query = Place.query
45 |
46 | try:
47 | resultats = query.paginate(page=page, per_page=LIEUX_PAR_PAGE)
48 | except Exception:
49 | return Json_404()
50 |
51 | dict_resultats = {
52 | "links": {
53 | "self": request.url
54 | },
55 | "data": [
56 | place.to_jsonapi_dict()
57 | for place in resultats.items
58 | ]
59 | }
60 |
61 | if resultats.has_next:
62 | arguments = {
63 | "page": resultats.next_num
64 | }
65 | if motclef:
66 | arguments["q"] = motclef
67 | dict_resultats["links"]["next"] = url_for("api_places_browse", _external=True)+"?"+urlencode(arguments)
68 |
69 | if resultats.has_prev:
70 | arguments = {
71 | "page": resultats.prev_num
72 | }
73 | if motclef:
74 | arguments["q"] = motclef
75 | dict_resultats["links"]["prev"] = url_for("api_places_browse", _external=True)+"?"+urlencode(arguments)
76 |
77 | response = jsonify(dict_resultats)
78 | return response
79 |
--------------------------------------------------------------------------------
/cours-flask/exemple16/gazetteer/templates/conteneur.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Boatlas {%block titre %}{%endblock%}
6 | {% include "partials/css.html" %}
7 | {% include "partials/metadata.html" %}
8 |
18 |
19 |
20 |
21 |
43 | {% block afternav %}{%endblock%}
44 |
45 | {% with messages = get_flashed_messages(with_categories=true) %}
46 | {% if messages %}
47 |