Skip to content
Snippets Groups Projects
Commit be7acb9d authored by Valentine Lejeune's avatar Valentine Lejeune
Browse files

Initial commit

parents
No related branches found
No related tags found
No related merge requests found
README.md 0 → 100644
![FLASK](./readme_img/Flask.png)
Rezozio. Le retour
===
Ceux d'entre vous qui etaient present en L2, gardent sûrement le douloureux souvenir de ce projet de TW2.
Nous avions comme projet, de réaliser un super réseau social totalement innovant (et pas du tout inspiré de twitter)
à l'aide de nos maigres connaissances en web. Jusqu'ici tout vas bien, à ceci près que ce dernier devait etre developé
en php ...
![PHP1](./readme_img/my_first_project_with_php.jpeg)
---
Il est maintenant temps de prendre notre revanche et de le redévelopper, mais cette fois-ci, de manière très simple
et très rapide !
## Installer flask
Cette simple commande vous permettra d'installer Flask !
```sh
pip install Flask
```
## Saluons le monde !
Commencez par créer un fichier python appelé `app.py`.
```python
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
return "Hello World!"
if __name__ == "__main__":
app.run()
```
Enfin executez le script !
```sh
python app.py
```
Et vous verrez un magnifique "Hello World" s'afficher sur votre page si vous vous rendez à l'adresse
http://localhost:5000/
Voila, sur ce, merci à vous pour ce TP, et bonne soirée !
Non ? Bon alors continuons !
## De l'html ! youpi !
Tout ça c'est bien beau mais ça manque un peu d'html non ?
Modifiez legerement la valeur de retour de votre fonction `hello` afin de retourner des balises html,
par exemple des balises `<h1>`.
Pour que la modification soit repercutée sur le serveur il suffit de kill le serveur, de le relancer et de refresh
la page, pratique non ? ... Comment ça non ?
Bon très bien, si vous voulez que le serveur se rafraichisse après chaque sauvegarde du code, vous n'avez qu'à
activer le mode **DEBUG**. Une fois le mode **DEBUG** activé, un simple rafraichissement de la page web suffira.
Pour ce faire, il vous suffit de rajouter `debug=True` dans le lancement de votre appli :
```python
app.run(debug=True)
```
Très bien, maintenant que c'est fait, vous vous dites bien evidemment que cela est très bien, que Flask
est vraiment un Framework genial mais que mettre de l'html dans le code python c'est vraiment pas fou !
Et vous avez raison, c'est pourquoi Flask intègre jinja2, un moteur de template html plutôt puissant et
pratique à utiliser ( [voir la doc](https://jinja.palletsprojects.com/) ).
Pour utiliser ces fameux templates, la première chose à faire est de creer un dossier nommé `templates`
( pourquoi être original après tout ) à la racine de votre projet, au meme niveau que votre `app.py` donc.
Dans ce dossier `templates`, creez votre premier template, `home.html`.
Ensuite, de retour dans votre `app.py`, remplacez votre hideuse chaine de caractre html par une magnifique
invocation de votre template.
( N'oubliez pas d'importer `render_template` depuis le module flask )
```python
render_template('home.html')
```
## Plus de routes !
C'est le moment de faire grandir votre application en lui ajoutant plus de routes !
Avant d'aller plus loin, afin de faire fonctionner l'appli correctement, il est necessaire d'ajouter une
clé secrete à notre application. Elle nous servira à encoder un tas de chose pour des raisons de securité.
Elle sera aussi utilisée de façon interne par flask, il faut donc la specifier :
```python
app.config['SECRET_KEY'] = 'YOUR_RANDOM_STRING'
```
Une fois cela fait, nous pouvons continuer
D'abord, renommez votre method `hello` en `home` (pour plus de coherence) et associez lui, en plus de `/`, la route `/home`
Ensuite, ajoutez à votre application une page `About` ( avec le template html associé ) qui contiendra (ou pas)
certaines informations à propos des développeurs du nouveau reseau social à la mode.
Vous êtes très doués et nous sommes sûrs que vous y arriverez seuls.
Si vous avez tout suivi jusqu'a maintenant, vous devriez avoir vos deux pages `home.html` et `about.html`,
qui ne contiennent pas grand chose.
Essayons d'etoffer un peu nos pages html et d'y inclure un peu de style.
Dans notre infinie bonté, nous allons vous donner un magnifique template, incluant un header qui vous simplifiera
quelque peu la vie :
Remplacez donc votre le contenu de votre `home.html` par le celui du fichier `template.html` present dans le
dossier `snippets`( en n'oubliant pas de le personaliser )
Ensuite, ajoutons un peu de css.
Creez un nouveau dossier `static` contenant un fichier `main.css`.
Et parce que le css c'est trop cool vous allez devoir tout faire vous meme ! (ou alors, allez le chercher dans le
dossier `snippets`)
Ensuite, liez cette super feuille de style à votre template ( tips : utilisez la fonction `url_for` )
Voila, votre page principale ressemble enfin à quelque chose ! Maintenant, visitez votre page `about`
Mince, le header et le style ont disparus !
Tout simplement car vos deux pages html sont differentes. La solution la plus rapide serait de copier-coller
l'html dans tout vos templates.
Mais si vous etiez attentifs lors de tous ces cours qui vous ont été prodigués avec soin par notre corps enseignant
hyper qualifié, alors vous savez que ce n'est pas une bonne chose.
La solution est donc d'exploiter la mécanique d'heritage !
Je vous laisse donc creer un template parent `layout.html` dans lequel vous placerez le code html precedent.
Ensuite vous le surchargerez dans vos templates `home.html` et `about.html`.
## Ajoutons les posts !
Que serait notre cher Rezozio sans ses messages !
```python
dummyDatas = [
{
"author": "Bob",
"title": "First Post",
"content": "Awesome content",
"date": "November 24, 2019"
},
{
"author": "John",
"title": "Second Post",
"content": "Awesome content",
"date": "November 25, 2019"
},
{
"author": "Eugene",
"title": "Third Post",
"content": "Awesome content",
"date": "November 26, 2019"
}
]
```
Ajoutons donc ces dummyDatas a notre appli. Mettez les simplement dans votre `app.py` et passez les en paramètre à
votre template `home.html` dans lequel vous ferez une super boucle pour afficher tous vos articles !
(en vous aidant du snippet `article.html`).
Maintenant que vous avez votre liste d'articles affichés. Passons a la suite !
## Des formulaires !!! Oh yeah !
Nous aimerions maintenant nous pouvoir nous connecter.
Pour cela, nous devons créer deux nouvelles page, `register.html` et `login.html` ( qui héritent elles aussi
de `layout.html`) et les remplir avec des formulaires.
Pour vous faire gagner un peu de temps, nous vous avons mis à disposition un formulaire présent dans
le dossier `snippets`.
Et la vous vous dites qu'en faite, Flask, ce n'est ni plus ni moins que du html ... Jusqu'à maintenant c'est
presque vrai, alors essayons de gerer ces fameux formulaires en python !
Pour manipuler ces formulaires, nous allons utiliser une petite librairie tout droit sorti de derriere les fagots :
`flask_wtf` ! (c'est son vrai nom, je vous assure )
Avant de pouvoir commencer, il faut donc importer ladite librairie :
```bash
pip install flask_wtf
```
Ensuite créez un nouveau fichier python : `forms.py`, dans lequel vous écrirez votre premier formulaire Flask !
Pour le formulaire d'enregistrement, vous devrez mettre en place plusieurs validation :
<ul>
<li>Tout les champs doivent être requis </li>
<li>L'adresse mail doit être une adresse mail valide</li>
<li>Le login doit faire entre 2 et 20 caracteres </li>
<li>La confirmation du mot de mot doit evidemment être égale au mot de passe. </li>
</ul>
Pour le formulaire de connexion :
<ul>
<li>Tous les champs doivent être requis </li>
<li>L'adresse mail doit etre une adresse mail valide</li>
</ul>
Une fois vos magnifiques classes de formulaires créées, vous devrez les instancier dans les routes concernées,
et les mettre en page dans vos templates html associés. Pour ce faire, vous n'avez qu'a modifier votre formulaire html
pour y inclure votre formulaire python (cf présentation).
Parfait, maintenant vous avez vos formulaires, avec validation de champ. Cependant si vous soumettez le formulaire,
vous recevez un magnifique `Method Not Allowed`
Et oui, car comme nous l'avons dit precedement lors de notre presentation, les routes sont definies par defaut pour
la méthode GET. Vous devez donc rajouter la methodes POST aux methodes autorisées.
Une fois cette modification effectuée, vous vous rendrez compte que vous ne recevez aucun feedback de la part de votre
formulaire. Ce qui est bien dommage !
Pour corriger le tir, vous devrez faire trois choses :
<ul>
<li>La première, déclencher la validation du formulaire ( et des ses inputs ) </li>
<li>La deuxième, modifier l'affichage du formulaire en fonction des erreurs reçues
( si l'addresse mail est invalide par exemple ) </li>
<li>La troisième, notifier l'utilisateur (en utilisant flash) lorsqu'il est correctement authentifié
, puis le rediriger vers la page d'acceuil </li>
</ul>
## Mesdames et messieurs, faites place à la BDD !
Il est temps de cesser d'utiliser ces dummyDatas. Nous allons donc mettre un place une petite base de données grâce
à SQLAlchemy ! (Et plus particulierement sa version adaptée à Flask donc voici
[la doc](https://flask-sqlalchemy.palletsprojects.com/en/2.x/))
Comme d'habitude, il est necessaire d'installer `flask-sqlalchemy` via pip.
Ensuite, pour set up la bdd, rien de plus simple :
Ajoutez cette ligne afin de specifier l'uri permettant d'acceder à la BDD
```python
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///site.db'
```
<ul>
<li>`sqlite` permet d'indiquer que la bdd sera en fait set up a partir d'un fichier.</li>
<li>`site.db` est le nom du fichier qui sera créé pour la db (le triple / sert a indiquer un path relatif,
c'est à dire que le fichier sera créé à la racine du projet)</li>
</ul>
Puis, créez une instance de la base de données grâce à :
```python
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy(app)
```
Ensuite, vous devez créer vos tables. Pour se faire, rien de plus simple, il suffit de definir de nouvelles classes
heritant de `db.Model` !
Creez donc la classe `Post`, qui contiendras les mêmes champs que nos dummyDatas.
Rajoutez y un id en clé primaire et faites en sorte que la date soit generée par defaut ( utilisez la fonction `utcnow` du module
`datetime`)
Créez ensuite un formulaire, et la route associée pour ajouter un post à notre blog !
(pour la premiere version, vous devrez specifier l'auteur de chaque poste )
N'oubliez pas de créer les tables comme nous vous avons montré lors de la présentation !
Si tout c'est bien passé, vous devriez déjà pouvoir ajouter et consulter des posts !!!!
## Pour aller plus loin ...
Si vous êtes arrivés jusque là, c'est que vous êtes maintenant un expert en Flask
(ou alors que Flask c'est hyper facile et mega rapide ...)
Votre mission est donc d'implémenter la gestion des utilisateurs.
Vous devrez donc
<ul>
<li> Créer la table User et la lier a vos formulaire d'enregistrement et de login</li>
<li> Gerer les sessions utilisateurs </li>
<li> Lier les tables Post et User </li>
</ul>
(pour les sessions utilisateurs => voir [flask_login](https://flask-login.readthedocs.io/en/latest/) (à installer via pip ))
## Pour aller ENCORE plus loin ...
Bon, cette fois, si vous êtes arrivés jusque là, c'est que vous êtes VRAIMENT un expert en Flask
(ou alors qu'on a mal dosé la durée du TP ...)
Enfin bref, pour terminer essayez d'ajouter la possibilité de modifier et de supprimer un POST
(seulement si l'utilisateur connecté en est l'auteur ...)
readme_img/Flask.png

59.8 KiB

readme_img/my_first_project_with_php.jpeg

10.4 KiB

<article class="media content-section">
<div class="media-body">
<div class="article-metadata">
<a class="mr-2" href="#"> # AUTHOR # </a>
<small class="text-muted"> # DATE # </small>
</div>
<h2><a class="article-title" href="#"> # TITLE # </a></h2>
<p class="article-content"> # CONTENT # </p>
</div>
</article>
\ No newline at end of file
<div class="content-section">
<form method="POST" action="">
<!-- Obligatoire (a decommenter quand vous aurez implementé le formulaire python -->
<!-- {{ form.hidden_tag() }} -->
<fieldset class="form-group">
<legend class="border-bottom mb-4"> Join Today</legend>
<div class="form-group">
<label class="form-control-label" for="username">Username</label>
<input class="form-control form-control-lg" id="username" name="username" required type="text" value="">
</div>
<div class="form-group">
<label class="form-control-label" for="email">Email</label>
<input class="form-control form-control-lg" id="email" name="email" required type="text" value="">
</div>
<div class="form-group">
<label class="form-control-label" for="password">Password</label>
<input class="form-control form-control-lg" id="password" name="password" required type="password" value="">
</div>
<div class="form-group">
<label class="form-control-label" for="confirm_password">Confirm Password</label>
<input class="form-control form-control-lg" id="confirm_password" name="confirm_password" required type="password" value="">
</div>
</fieldset>
<div class="form-group">
<input class="btn btn-outline-info" id="submit" name="submit" type="submit" value="Sign Up">
</div>
</form>
</div>
\ No newline at end of file
body {
background: #fafafa;
color: #333333;
margin-top: 5rem;
}
h1, h2, h3, h4, h5, h6 {
color: #444444;
}
.bg-steel {
background-color: #5f788a;
}
.site-header .navbar-nav .nav-link {
color: #cbd5db;
}
.site-header .navbar-nav .nav-link:hover {
color: #ffffff;
}
.site-header .navbar-nav .nav-link.active {
font-weight: 500;
}
.content-section {
background: #ffffff;
padding: 10px 20px;
border: 1px solid #dddddd;
border-radius: 3px;
margin-bottom: 20px;
}
.article-title {
color: #444444;
}
a.article-title:hover {
color: #428bca;
text-decoration: none;
}
.article-content {
white-space: pre-line;
}
.article-metadata {
padding-bottom: 1px;
margin-bottom: 4px;
border-bottom: 1px solid #e3e3e3
}
.article-metadata a:hover {
color: #333;
text-decoration: none;
}
.article-svg {
width: 25px;
height: 25px;
vertical-align: middle;
}
<!doctype html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<title> Rezozio </title>
</head>
<body>
<!-- Navbar -->
<header class="site-header">
<nav class="navbar navbar-expand-md navbar-dark bg-steel fixed-top">
<div class="container">
<a class="navbar-brand mr-4" href="/"> Rezozio </a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarToggle" aria-controls="navbarToggle" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarToggle">
<div class="navbar-nav mr-auto">
<a class="nav-item nav-link" href="/home">Home</a>
<a class="nav-item nav-link" href="/about">About</a>
</div>
<div class="navbar-nav">
<a class="nav-item nav-link" href="/register">Register</a>
<a class="nav-item nav-link" href="/login">Register</a>
</div>
</div>
</div>
</nav>
</header>
<!-- Vous devrez ecrire le corps de votre page ici -->
<main role="main" class="container">
A PERSONALISER
</main>
<!-- Optional JavaScript -->
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
</body>
</html>
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment