Session du 01 mai 2024 à 21h00
Développement Web & Frameworks
Programmation Orientée Objet (POO)
Initiation à Django
Initiation au framework Django (gestion comptes utilisateurs, formulaire d'inscription, login/logout, CBV/FBV, gestion mots de passe...)
00:00:00 :Bon, du coup, habituellement ce que j'ai fait les autres fois, c'était beaucoup coder en public,mais ce n'est pas ce qui est forcément plus intéressant, je pense.
00:00:12 :Du coup, là, j'ai préparé un projet pour montrer un peu comment gérer ce qui est l'utilisateur.Pas seulement du login, ça va être beaucoup comme on fait pour envoyer un lien d'activation à l'utilisateur.
00:00:29 :Pour qu'il active son compte et aussi comment faire pour qu'il puisse lui tout seul changer son mot de passeet demander pareil tout seul un lien pour réinitialiser son mot de passe,comme on peut voir souvent sur certaines applis ou certains sites.
00:00:45 :Voilà, je pensais que c'était intéressant parce qu'il y a plusieurs personnes qui se posaient la question.Dans moi, au début, je me posais la question.
00:00:53 :Et des liens d'activation par email, par exemple, ce n'est pas forcément extrêmement compliqué à faire.Du coup, ce que j'ai préparé, c'est un projet très basique.
00:01:10 :Il y a le dossier du projet, il y a une application account pour l'utilisateur, c'est tout, et un template de base.Pour les... on va commencer par les requirements qui sont la tête.
00:01:24 :J'utilise Crispy Bootstrap et Django CrispyForm.Ça, c'est indispensable à chaque fois parce que sinon ça pique les yeux, les formulaires.Mais ça, on fera une session sur les formulaires, justement, on en parlera de ça.
00:01:38 :Django, c'est la version 1.Et puis après, j'ai Python Viron qui me sert pour une variable.C'est pas ce qui est le plus utile, mais c'est pour planquer mon mot de passe.
00:01:49 :Donc voilà, le projet.Il n'y a rien de spécial dans les settings.J'ai juste mis en français, c'est tout.Juste, par contre, j'utilise Bootstrap 5 pour mes formulaires.
00:02:03 :Et donc, Crispy Bootstrap, qu'il faut préciser ici.Ça, on le verra après.Et quand vous voulez envoyer des mails avec votre projet Django,il y a plusieurs constantes à définir.
00:02:20 :Je vais revenir dessus après.Salut, David.On reviendra dessus après.Sinon, c'est un projet plus que basique.Comme je disais, il y a une application.
00:02:33 :Account.Là, on va parler de gestion utilisateur.On va zoomer un petit peu.Bon, je vais me débrouiller comme ça.Est-ce que je vais ouvrir un...
00:02:50 :Ça va comme ça ou pas ?C'est bien, bon.Ouais, Simon, c'est bon ou pas ?Je crois que c'est Simon qui...Non, mais non.
00:03:02 :Là, c'est bien, merci.OK, super.Du coup, on va commencer...On va commencer par le système d'activation des trucs par email.Vous pensez le voir à la fin et de manière optionnelle à la base,mais en fait, je pense que c'est le plus intéressant à faire.
00:03:24 :Quand vous avez votre application Account,je commence toujours par me définir un modèle utilisateur custom.Je ne sais pas s'il y a beaucoup d'habitués le Django ici.
00:03:38 :Parce que le Django, en fait, de base,a un modèle utilisateur qui est fourni avec.Mais moi, perso, j'utilise toujours un modèle custom.Parce que le problème, c'est que...
00:03:51 :Je vais le dire à la fois, mais je me répète un peu.Ça, c'est vraiment important.C'est que quand vous allez avoir des modifs à faire sur votre utilisateur,ça va être une grosse galère si vous faites ça sur un...
00:04:00 :Alors que si vous rajoutez un custom par la suite,alors vous utilisiez le système qui était dans le Django de base.Donc c'est bien, même si vous ne faites pas grand-chose de plus,toujours définir un utilisateur custom.
00:04:13 :Ici, il n'y a pas forcément tous les attributs parce que j'en hérite.Il y a les firstname, lastname, voilà.Toujours pensez au manager qui va avec.
00:04:28 :Et pointe vers le custom manager.Je passe très vite parce qu'on l'a déjà vu la dernière fois.Et donc là, on a nos commandes pour créer notre utilisateur et notre super utilisateur.
00:04:40 :Axel, Django... Ah, OK, Axel.OK, OK, je termine un peu vite cette partie-là.Mais il y a les autres sessions qui ont été enregistrées qui sont un peu plus basiquesoù je commence un projet de zéro.
00:04:53 :Mais si tu veux, Axel, ce que je disais, c'est qu'avec Django,tu as ton modèle utilisateur.Donc modèle, c'est comment il modélise ta base de données, en fait.
00:05:06 :Donc ton utilisateur, il est de base dedans.Mais moi, je préfère toujours en faire un custom, voilà.Comme ça, en cas de modification, tu n'es pas embêté, tu fais tes modifs dessus sans souci.
00:05:17 :Et tu n'as pas plein de manip à faire parce qu'il y a,oui, mince, j'aurais dû utiliser un utilisateur custom, voilà.Donc, on a notre modèle utilisateur qui est là, dans Models.
00:05:29 :Ensuite, on va parler du système d'activation par email.Donc moi, ce que je fais, c'est que je me crée un petit package dans l'applicationque j'appelle... Je vais prendre le train en route, pas de souci, mais bref...
00:05:43 :qui s'appelle Vérification, c'est ce qu'elle fait dans l'anglais, voilà.Donc moi, j'aime beaucoup organiser en package mes fonctionsque je veux réutiliser dans mes fichiers Python.
00:05:56 :Donc en fait, ce que je vais faire, c'est que je vais utiliser...On va commencer par ce fichier-là.Je commence par là, je me crée ce fichier-là,et en fait, je vais importer password, reset, token generator.
00:06:13 :Ne vous inquiétez pas, je vais vous filer un repo GitHub après avec tout ce que j'ai fait là.Donc j'importe cette place-là, qui est dans les fichiers sourds de Django,et je vais surcharger une méthode qui s'appelle makeHValue.
00:06:27 :Voilà. Alors, je vais vous montrer un peu ce qui se passe.Enfin, je vais vous déborder de ce que fait cette méthode-là.En fait, vous allez envoyer votre utilisateur et le timestamp.
00:06:38 :En fait, le timestamp, c'est un indice temporel.Voilà, définition exacte.C'est quand est-ce que le token a été généré.C'est redaté, on va dire.Voilà, et votre utilisateur.
00:06:52 :Ensuite, vous retournez dans votre chaîne, votre chaîne de caractère.User is active.Le pk-utilisateur et le timestamp.Donc, on hérite de cette place-là.Et cette place-là, en fait, fait plein de choses pour nous.
00:07:07 :Donc, ça, c'est le code sourds de Django.Je vous rassure, je n'ai rien codé ici.On va aller voir ce qui nous intéresse,parce que sinon, on va y passer la soirée.
00:07:17 :On va parler de ce...On va parler après de cette méthode-là.Gabby, excuse-moi de te déranger.Il y a un ami à moi qui aimerait rejoindre le truc,mais il ne voit pas. Comment il peut faire ?
00:07:32 :Il a rejoint le serveur et tout.Il a rejoint le serveur, il a fait sa présentation,et il a posté du code.Il faut qu'il poste du code dans...
00:07:48 :dans Entraînement.Il y a un salon Entraînement, il faut qu'il poste du code formaté dedans.OK, normalement, ça serait bon.Parce que je lui ai envoyé le lien et ça ne rejoint pas.
00:07:58 :OK, je vais aller le lui dire.Voilà, il n'y a pas de souci.Merci.Désolé.Il n'y a pas de souci.Du coup, on va s'intéresser un peu à ces méthodes-là rapidement,parce que le but, ce n'est pas de reprendre le code source de Django.
00:08:14 :Il est où ? Voilà.Donc là, j'ai hérité de toute cette classe-là.Je vais re-dessiner, je vais re-surcharger qu'une seule méthode,makeHValue,parce qu'en fait, celle-là, makeHValue, à chaque fois...
00:08:30 :Ce qu'elle fait, en fait, c'est qu'elle va utiliser le PK,le mot de passe, le LoginTimestamp, le Timestamp, l'email.On n'avait pas besoin de tout ça.
00:08:40 :C'est pour ça qu'en fait, j'ai repris la classe, j'ai surchargé.On a besoin de savoir que si l'utilisateur est actif,son PK et le Timestamp.
00:08:48 :Notre check token, on va le faire après.Donc, j'ai instancié ici cette classe.Voilà.Je l'ai instancié juste en dessous.Et ensuite, ce qu'on va faire, c'est qu'on va créer une fonctionavec tous les imports qu'il y a.
00:09:07 :Vous voyez, il y a une fonction qui fait pas mal de choses.On va lui passer la requête et l'utilisateur.Il y a du monde qui rejoint.
00:09:20 :Avec Django, du coup, là, on va récupérer ce qu'on appelle le GetCurrentSite.On l'importe ici.Ça va nous permettre de récupérer notre domaine.Là, ça va être le sujet, du mail.
00:09:36 :Et ici, ça va être le corps.Parce qu'on va utiliser un fichier HTML pour envoyer le mail.Dans le contexte, on va envoyer le domaine.
00:09:47 :C'est le GetCurrentSite.Donc, ça va être notre domaine.Simplement, ça porte bien son nom.L'UID, on va encoder le PK de l'utilisateur.Et on va créer notre token, du coup,avec la classe qu'on a vu tout à l'heure, qui est là.
00:10:03 :Notre classe qu'on a faite ici, qu'on a instantiée.On va l'utiliser.Et on va faire un makeToken de l'utilisateur.Et ensuite, on envoie le mail.
00:10:15 :Donc, makeToken.Il est où le makeToken ?MakeToken, voilà.Donc, en fait, on fait un token.Simplement, c'est le Django.Cette méthode-là va nous créer un token.
00:10:30 :Voilà.Simplement.Il n'y a rien de plus simple.Il n'y a rien de plus compliqué, je veux dire.Ensuite, le template, il va nous montrer.
00:10:42 :Email.Attends, est-ce que j'ai agrandi l'écran ?Voilà.Et en fait, votre email, c'est un fichier qui s'appelleverification.html.Je l'ai défini ici.Et comme je vous le disais, je passe le domaine.
00:10:57 :Je vais passer la...On va le voir après.Ça, c'est la vue, qui va nous permettre d'activer le compte.L'unité, ça, c'est pour l'utilisateur.Et là, ici, c'est le token.
00:11:07 :Et après, vous mettez ce que vous voulez comme message.J'en ai rajouté un petit peu, mais il n'y a pas de version dans tout ça.
00:11:13 :Il n'y a pas de version dans tout ça.C'est pour notre cas.Ensuite, on va aller voir ce qui se passe dans les vues.Alors, je ne sais pas s'il y en a qui sont un peu Django.
00:11:24 :J'ai tendance, mes vues, moi, ce n'est pas un fichier views.Je les coupe en packages.J'ai bien souvent plusieurs fichiers views.Voilà.Alors, qu'est-ce qui se passe dans...
00:11:36 :dans mes vues ?Je vais ouvrir un navigateur en même temps.On va agrossir ça.Alors, j'ai fait un template.Je ne sais pas si vous voyez assez.
00:11:52 :Moi, c'est bon.Si jamais ce n'est pas assez, vous me le dites.Dans le fond, j'ai fait un template plus que basique.C'était pour l'exemple.
00:12:06 :Donc, on ne se moque pas.Je ne me suis pas embêté.Franchement, j'ai fait un tout basique.Là, on va voir, du coup,quand l'utilisateur veut s'enregistrer.
00:12:16 :Donc, il clique sur Sign Up.Il va signer son mail, son mot de passe.Et quand il va envoyer, ça va envoyer un email.Alors, ça, on l'a...
00:12:24 :Bon, on l'a vu dans ZEXAL ici.C'est juste un template HTML que je retourne sans rien de...Il n'y a rien de fou.Pour faire, du coup, le Sign Up.
00:12:34 :Donc, là, je passe du token à la vue.C'est normal. C'est parce que c'est lié ensemble.Il fallait bien que je crée un système de token avantpour ensuite parler de la vue qui va envoyer le token.
00:12:45 :Pour mon Sign Up, quand on regarde ce qui se passe dans la vue,on va arriver avec une méthode get.Donc, ce bloc-là, ici, tout ça, pour l'instant, il ne compte pas.
00:12:54 :On pourrait l'effacer.Ça fonctionnerait quand même.Mais je ne vais pas l'effacer parce que j'ai l'impression de le refaire.En fait, on va arriver avec un formulaire, le Sign Up Form,que je repasse à mon contexte.
00:13:06 :Le Sign Up Form, il est...Je l'ai fait tout à l'heure.Pour faire un Sign Up Form avec Django,de manière assez...Ça s'intitule, en fait, j'érite,le User Action Form qui est dans django.contrib.auth.forms.
00:13:21 :Et ça, ça vous permet d'avoir un formulairepour la création d'un compte qui est quasi tout fait.Vous avez juste à définir une classe méta,votre modèle utilisateur.
00:13:32 :C'est la fonction django.contrib.auth.getUserModel.Ça, ça va chercher le modèle utilisateurqui est utilisé par votre projet Django.Et ça, comment Django le sait ?Eh bien, ce n'est pas compliqué.
00:13:48 :Il faut lui dire dans Project Settings.Dans les Settings, ça, on en a déjà parlé aussi,il définissait ici AuthUserModel.Vous mettez votre applicationavec le nom du modèle utilisateur, simplement.
00:14:04 :Donc là, on sait bien Account,l'application, avec les modèles,CustomUser qui est ici.Donc voilà, c'est comme ça que Django saitquel modèle utiliser.J'arrête là.
00:14:22 :Donc voilà, tout simplement, en fait,ici, je ne vais pas servir le mot de passeparce qu'il le fait automatiquement.Je dis juste que je veux un emailparce que tout ce qui est FirstName, LastName,je l'ai mis en optionnel.
00:14:34 :On ne va pas s'embêter pour l'exemple.Donc ici, on va avoir l'emailet le mot de passe pour l'inscription.Donc ce formulaire-là, du coup,on l'utilise dans notre sign-up.
00:14:44 :On l'utilise ici.Donc c'est ce qu'on a vu.On est arrivé là.Et ce qui va se passer quand on vaêtre en méta de poste,c'est qu'on va soumettre le formulaire.
00:14:58 :On va replacer notre formulaire icien lui mettant le corps de la requête.S'il est valide, on va faire un userégal form.save.Est-ce que, juste pour savoir,vous savez tous ce que fait commitégal false ici ?
00:15:12 :Si vous l'avez déjà vu, utilisé ou pas ?Non.Moi, je n'ai jamais entendu parler.J'ai une petite idée.OK.En fait, vous pouvez le faire avec des formulaires,pas que pour l'utilisateur.
00:15:25 :En fait, ici,je ne le sauvegarde pas tout de suite en base de données.Je fais un form.save, comme ça, pour moi, je l'ai en mémoire.
00:15:31 :Je fais un commit égal falsepour ne pas l'enregistrer en base de données.Et ensuite, comme ça, on peut travaillersur l'instance qu'on est en trainde créer avec le formulaire.
00:15:41 :On peut travailler tout de suite sur la sauvegardeuse.Moi, c'est juste pour faire un userpour les actives, pour le passer à false.Comme ça, l'utilisateur, il n'est pas activé par défaut.
00:15:49 :Et ensuite, je leur fais mon save ici.Voilà.Mais ça, de toute façon, on fera une sessionsur les formulaires en poussant un peu le trucet on verra ça.
00:16:00 :On verra ça.Ensuite, j'utilise un bloctry except.Donc là.Donc là, ce qu'on va faire, c'est qu'on va faire notre scèned'email de vérification. Donc ça.
00:16:12 :Ça, ça, ça.C'est ce qu'on a vu tout à l'heure avec le token.C'est qu'on va envoyer justement un email à l'utilisateur.OK.Ça, c'est l'email qu'on envoie avecl'UID, le token, le token.
00:16:23 :Vous allez le voir par la suite. Ce sera plus simple quand on fera l'exemple.Et ensuite, j'utilisele, ils appellent ça framework carrément,le framework message de Django.
00:16:31 :Voilà.Pour dire, en gros, mail envoyé pour activation.Bon, là, c'est pas très cordial, maisc'est pour l'exemple.Et ce qui est bien, c'est de capturer les exceptions.
00:16:41 :Si vous avez un problème avec lesserveurs mail, genre, je sais pas, j'ai mail, il n'a pas envie,ça plante, et du coup, bah,tout le monde sait, SNKlib,qui disait, pour l'envoi d'email, galère.
00:16:51 :Ce qui est bien, c'est de faire un,de capturer l'exception et de faire quelque chose.Sur un projet, moi, par exemple, j'ai mis en place un système delog. Donc, si jamais le,
00:16:59 :j'avais fait en sorteque, là, j'aurais pu le faire, c'est dommage.Si le mail n'était pas envoyé,ça m'éteint le message du utilisateur.Ça ne lui faisait pas un bug, en fait.
00:17:09 :Ça le redirigeait vers l'index.Moi, ça m'enregistrait dans un log.Et, voilà, l'utilisateur, en gros,il a un message.Il est arrivé, un admin va,va s'en occuper.
00:17:21 :Bref,en gros, on va partir du principe que tout fonctionne bien.Donc, on est ici.On envoie le mail, hop,et on est redirigé vers l'index.
00:17:31 :Avec notre message.Est-ce que le framework message,vous l'avez déjà utilisé pour sélectionner le Django ?Ou pas ?Ouais.C'est super bien.Parce qu'en gros,ça va enregistrer des messagesque vous allez pouvoir ensuite envoyerdans le template de l'utilisateur.
00:17:53 :Et pour envoyer ces messages,il faut les afficher dans le template.Moi, je les ai affichés HTML.Voilà.Et donc, si vous avez des messages,vous bouclez sur vos messageset vous les affichez.
00:18:07 :Et en fait, avec Django,quand vous bouclez sur vos messages,après, ils s'effacent tout seuls.Ils disparaissent.Donc, ça ne se cumule pas.Si après, vous avez d'autres messages,ils ne vont pas se cumuler que ceux-là.
00:18:21 :Petite question par rapport au message.Après, c'est peut-être un peu en dehors du cadre.Mais,quand les messages s'affichent,la texte, ça disparaît.C'est quand tu as un nouveau messagequi prend le dessus, c'est ça ?
00:18:35 :Non, même pas.Quand tu vas...Quand je l'utilise,en l'utilisant, j'ai le message qui apparaît.Et si je ne le ferme pas,il reste tout le temps affiché.
00:18:47 :Oui, mais si tu quittes la pageet que tu reviens sur une pageoù tu affiches le message,normalement, il n'apparaît pas deux fois.D'accord.
00:18:57 :Je ne sais pas ce que je peux retrouver.C'est intéressant,mais par rapport au message,je ne sais plus. C'est une application qui n'est pas finie.
00:19:09 :RPG...Je leur ai mis dans quoi ? Dans les vues ?Dans les fonctions ?Dans ma classe Battle, je ne sais plus.Ah, voilà !
00:19:19 :C'est ça.Par exemple, ici,il y aun cas oùj'ai envoyéun message, mais selon ce qui se passe,je ne veux pas forcément que le message soit vu.
00:19:33 :C'est un peu bête,mais je ne veux pas passer sur l'application,celle-là, c'est un jeu drôle.Ce que je faisais, c'est que je bouclaissur le système de messagesde Django.
00:19:45 :Je bouclais sans rien faire, avec un pass.Voilà.Comme ça, après, je leur envoyaisun message perdu. Tu peux recommencer,mais tout ce qui est un message,comme ton point de vue, je les effaçais.
00:19:57 :Dès que tu boucles au-dessus,ça les efface.D'accord.Hop là !Je ne vous l'ai pas dit,j'ai un template de basepour le projet,où j'ai ma navbar. C'est du Bootstrap,
00:20:13 :j'ai une navbar basique,avec un endroit où j'affiche mes messages.C'était juste ça.Du coup, voilà.On va faire le test.On va s'inscrire.On va voir si mon mail est bien envoyé.
00:20:29 :Pour ça,avant, il faut s'assurer quevous ayez définitoutes cesconstantes dans vos settings.Voilà. Si ça ne s'est pasdéfini,Django ne pourra pas envoyer le mail.
00:20:45 :Il ne pourra pas savoirse connecter.Et surtout, vos mots de passe,pour ceux qui commencent avec Django,ne tombent jamais dans le mur.Tout ce qui estinfosensible,toujours dansdes fichiers externes,qui ne sont pas dans des repos Git.
00:21:05 :Une fois que vous avez toutes ces constantes-là,vous êtes prêtsà pouvoir enjoguer des mailsavec Django.Là, vous allez voir.On va lancer le serveur.
00:21:17 :J'ai arrivé ici.Je vais m'inscrire avecOutlook, par exemple.Si ça bug, je vais l'écouter.Ça devrait aller.On va envoyer ça.Je vais le supprimer.
00:21:39 :Voilà. Du coup,on s'inscrit. On n'a pas de compte.On veut s'inscrire.Je me suis faisé pourpas de template de base.Voilà.On envoie.
00:22:01 :Là, j'ai un message. Je l'affiche de manière basique.C'est pas le but.Il y a marqué Mail envoyé par activation.J'ai bien reçu un mailsur Outlook.
00:22:13 :C'est ici.Là, on a bien notre mailavec leCache current site.Ensuite, on a notrevue.Après, on envoie notre token.Ici,on clique dessus.
00:22:35 :Votre compte est désormais actif.Vous pouvez vous connecter.Maintenant, je teste.C'est l'adresse Outlook.Je vais essayer.Je crois que c'est ça.Je vais essayer.
00:22:57 :C'est bon. Je suis connecté.Je vais me remettre là,dans l'admin.Pour l'instant, je vais l'effacer. On va faire un test après.Vous voyez que là, il est bien actif.
00:23:13 :Il n'y a pas de soucis.Je vais revenirà mon projet.Vas-y.Le lien, il est avecun délai d'expirationparamétré ?Tu m'as devancé.
00:23:33 :C'est bien.C'est cool.C'est exactement ça.Là, ce qu'on a fait, c'est qu'on s'est inscrit.On a été dans cette vue-là.Cette vue d'activation.Quand tu cliques sur le lien, tu arrives surl'activation ducompte. J'ai fait un truc
00:23:55 :qui n'est pas élégant. Je m'en rends compte.J'ai utilisé user pour récupérerle modèle utilisateur.Ensuite, j'utilise user pourdéfinir un utilisateur. Ce n'est pas
00:24:05 :top de faire ça.C'est pour l'exemple.Ce qui se passe dans cette vue,je n'oublie pas ta question.On va en parler juste après.Parce qu'on va revenir surle Django après.
00:24:19 :En fait, ce qui fait cette vue,avec le lienqu'on envoie.Attends, il est où ?Voilà.Mon email est là.C'est bon.Dans le template, il est là.
00:24:35 :On avait le domaine,la vue,lui, il était là, et le token.Donc,ici, on va repasserdans la vue d'activation,on va repasser l'UID et le token.
00:24:49 :Parce que ça, on l'a bien définidans nos URL.Ici, la vue d'activation,on a activate,UIDB, token.Ce qu'on va faire, c'est qu'on varécupérer le modèle utilisateur de Django.
00:25:03 :On va utiliserl'UIDB ici.Et on varécupérer l'UIDB ici.Donc là, ce qu'on fait, c'est qu'on vale décoder.On va décoderce qu'on a envoyé dans notre lien.
00:25:19 :Et commeon avait encodé çalà,on l'avait encodéavec le...Attendez, je suis perdu.Régistration...Voilà, c'est ça.On avait encodé icile PQAM utilisateur.
00:25:43 :Et en fait, ici, on va le décoder.Et grâce à ça,on va récupérerun utilisateur.S'il y a un problème,forcément, on ne le récupère pas,donc on prévoit les exceptions qu'il faut,qui vont avec.
00:25:59 :Je crée un repoqui explique tout ce qui est Overflow,ValueError, les erreurs de triples.On pourra en revenir après,mais je l'ai préparé sur unreadme.
00:26:11 :En gros, là, ce qui va se passer,c'est que si un utilisateuret que letoken, il est, on va dire, bien checké,hop, on va passerl'utilisateur àActive="True", on va le sauvegarder.
00:26:25 :Et là, on va mettre un petit message au montadeur,votre compte est désormais actif, vous pouvez vous connecter.Et sinon,vous pouvez vous contacter par mail pour résoudrele problème, c'est assez basique.
00:26:35 :Donc voilà, ici, on a tout notre système d'activationpar email.Et c'est là que tu disais, est-ce qu'il y a un tempsdelimite ? Et effectivement,
00:26:45 :oui, il y en a une de limite.Quand on va dans leCodesource de Django, on a vuqu'ici, on faisaitun CheckTokenpourvérifier le token qu'on a envoyé.
00:26:59 :Et ce qu'il se passe dans le CheckToken,alors, il se passe plein de choses.On vous a vu qu'on avaitun petit,le lien, on avait un petit...
00:27:11 :On va pas se tirer du 6, quoi.Et en fait, là, il va faireplein de pales d'opérations. Il va essayer derecréer, en fait, au passage,un token, en fait, dansla même condition pour vérifier s'il n'y a paseu de modificationsentre deux. Enfin, c'est super sécurisé.
00:27:27 :Je me suis intéressé à ça, ça donne un peumal au crâne, mais après, quand on se pose dessus,on se dit, ouais, en fait, les mecs ont codé ça,ils ont vraiment pensé à tout.
00:27:35 :Et du coup, ils ont même penséà la limite,ce que je disais tout à l'heure, avec cetteconstante ici, qu'il va chercher dans lessettings. Donc, voilà.
00:27:45 :Et en fait,dans tes settings de base de Django,si...Et voilà, il est là.Donc ça, ce n'est pas mes settings à moi.
00:27:57 :Ça, c'est les settings de Django.On n'y touche pas, mais c'est justepour vous montrer qu'en fait, il est ici.Pas surpris de timeout.En fait, quand vousmettezdes constantes, souvent dans votrefichier de settings, vous allez venirécraser ce qu'il y alà-dedans. Là, par exemple, Django,
00:28:17 :de base, il utilise son modèle à lui,votre user. Et moi, ça, j'ai redéfinipar mon modèle à moi, donc c'est venir écraser ça.Donc ça, c'est les settings globalesde Django dans CodeSource.
00:28:27 :Mais si on revientdans mes settings,hop, on peut s'amuser à faire un ...On met un délai de 10 secondes.Et vous allez voirqu'avec un délai de 10 secondes,si ...
00:28:41 :On va refaire un sign upavec mon outlooklà.Hop.Et, j'ai envie de mettrela rapide, mais parfois, il galère un peu.Donc là, on va attendre,allez, 10 secondes.
00:28:59 :Il était là, c'était 25.Ça, c'était celui-là tout à l'heure, ça.Voilà.Oups, qu'est-ce qui s'est passé ?Je vais effacer ça pour ne pas le faire exprès.
00:29:15 :Alors, attendez.Voilà.J'ai pas de...Je ne vois plus.Alors là.Ben, ouais.Je ne le retrouve pas dans mes...C'est récent.Je te l'ai dit, il est là.
00:29:45 :Bon, là, on est sûr que du coup,il ne sera plus à jour, le lien.Donc là, si je l'ouvre...Attention, j'espère que c'est...Voilà. Vous pouvez nous contacter par mail,
00:29:55 :vous nous raisonnerez le problème.Parce qu'il n'a pas réussi à l'activer,le rotatage, il est expiré, quoi.OK.Voilà.Donc, c'est mort.Oui ?Juste, curiosité, le fichier Global Settings,il est situé où, en fait ?
00:30:13 :Dans django.conf...Attends, on va y aller.J'appelle jamais,quand j'ai besoin des constantes de settings,j'appelle jamais directement mon...Ouais, c'est ça, c'est django.conf.Il te le dit, ici,dans le lien.
00:30:31 :Voilà, package django.confGlobal Settings. Voilà.OK. Ça marche, super, merci.Voilà, il est là dedans.Tu peux aller voir, après, il y a plein,plein de choses qu'il y a dedans.
00:30:43 :Ouais, t'as tout un tas de trucs qui sont par défaut,c'est ça ?Ouais, c'est vrai que toi, après, tu vas venir surcharger,enfin, ouais, ça peut être à surcharger,quand on parle de constantes,mais bon, on va dire ça, ouais,tu peux venir écraser, en fait.
00:30:57 :60 par 60 par...En temps, je ne sais plus.Des trucs comme ça ?Ouais, alors, par défaut, je ne les ai pas dotés.Ça fait trois jours, par défaut.
00:31:09 :Ouais, c'est ça, c'est exactement ça.Ça, c'est trois jours, ouais.Je ne l'avais pas calculé, mais je l'avais lu une fois,mais ouais, c'est trois jours.
00:31:17 :Et il faut le déposer en heures, minutes et compagnie,j'imagine, c'est ça ?Bah, moi, alors, je n'ai jamais touché.Ouais, voilà.En général, je ne touche pas,je laisse tel quel, mais je pense que tu pourraistrès bien te le mettre en seconde,si t'es un petit peu en colère.
00:31:33 :Tu peux te le mettre en seconde.Je n'ai jamais essayé, je t'avoue que, ouais.Une question.Oui, oui, c'est des secondes. Ils l'ont juste mis en 60 secondes,
00:31:41 :fois 60 secondes.Ouais, c'est ça.Trois jours pour que ce soit plus visiblepour celui qui vient à dire le truc,mais tu peux très bien...
00:31:51 :Ouais, plutôt que de mettre3600 secondes, là, où je ne sais pas quoi.Ouais, il n'y a pas d'erreur.C'est des secondes, à la fin.
00:31:59 :C'est juste un calcul mathématique qu'ils ont noté en dur.Donc ça, c'est plus visible.Donc voilà,ça, ce qu'on avait vu ici,c'était ce qu'on voulait voir.
00:32:09 :C'était pour vous dire que, voilà, en gros,la classe de Django, en fait, elle va utilisercette constante-là pour vérifierla validité du lienau niveau du temps.
00:32:19 :Parce que nous,on a juste fait...On en a juste arrêté,cette classe-là. On va vraiment utilisertout ce qu'il y a dedans. Ce qu'on a juste chargé,
00:32:29 :c'est cette méthode-là. Rien de plus.Donc vous voyez, en fait,il n'y a pas grand-chose à faire pour pouvoir créer notrepetit système de tokens.
00:32:37 :Donc voilà, on en était oùà l'activation ? Voilà. Donc là, on aactivé notre compte. On est bien. Maintenant,on veut que l'utilisateur puissefaire un log-in, log-out.
00:32:49 :Alors, bien sûr, des choses plus basiques,mais c'était aussi la base dusujet de ce soir.À la base, j'allais faire plus là-dessusque sur l'activation du compte par email,mais je pensais que c'était intéressantde passer un peu de temps dessus.
00:33:03 :Pour le log-in,personnellement, j'aime bien utiliserla log-in viewparce que, je ne sais pas, je l'ai fait tout pour moi.En fait, en troislignes de code, j'ai une vue de log-inqui fonctionne très bien. Vous l'avez vue.
00:33:19 :Hop, il n'y a pas de problème. Elle est là.Voilà, je suis connecté.Après, il y a une autre façon de faire.Hop, tac.Il y a une autre façon de faire.
00:33:33 :Ça va être de passer parune vue basée surles fonctions. Alors, elle intéresse aussitac.On va faire un petit peu de code, on ne parle pas grand-chose,mais on va faire une vue basée sur les fonctions.
00:33:47 :Pour ça, il va nous falloir du coup un formulaire.Hop là.Donc, on va se créer un petit formulairede log-in.Tac.Donc, on va l'appeler làpour me différencier du genreque vous voulez peut-être.
00:34:05 :MyLoginForm.Juste pour l'exemple.Voilà. Form.C'est juste pour en faitfaire une petite introduction auformulaire. Enfin,une session d'actualité.Mais avec le log-in, ça peut être...
00:34:21 :J'ai déjà vu pas mal de projetsoù ça passait par des log-inà utiliser des fonctions.Donc, on va vouloirquoi pour le formulaire d'e-mail?
00:34:31 :Donc, Form.C'est Forms.EmailField.Voilà.On va vouloir unpassword. Tac.Donc, le password,c'est bien sûr, en fait, le password c'est un parfum.Mais on ne va pas vouloir quele mot de passe soit visible.
00:34:49 :On va lui rajouter un petit widget.On va l'appeler Forms.Voilà. PasswordInput.Voilà. Donc, en fait,là, on est dans le type de données,en gros, et là, on va être vraiment dansle...
00:35:03 :dans le widget,dans le passwordinput.Ce qui va nous permettre de cacher notre mot de passe.Ensuite, ici,on va l'importer maintenant.MyLoginForm.Tac.J'en étais là.
00:35:21 :On va l'appeler LoginView.Hop. On va avoir notre requête.Et ici, on vacommencer par définiren forme linéaire, qui est MyLoginForm.Et on varetourner, du coup,dans le template HTML qui s'appelle...
00:35:41 :qui est dans Account.Donc, notre requête.Hop. Account.Ici, Login.HTML.Hop.Et en contexte,on voit le papier de formulaireque j'aidéfini. Oh, bah alors,
00:36:01 :j'ai pas eu l'occasion de mettre l'ictionnaire, excusez-moi. Tac.Hop là.Et voilà.Donc, pour ceux qui habitent avec Django, le contexte,c'est toujours un dictionnaire. Je sais pas pourquoi, des fois,
00:36:13 :j'ai une tendance à passer à l'arrache comme ça, maisje commence à l'écrire.Le template,pareil, donc c'est pour ceuxqui n'étaient pas là la fois d'avant, pour les templates,en fait, Djangopousse les dossiers template dans une applicationet va les reconnaître. Donc,
00:36:29 :dans mon dossier template, ici, j'aiun dossierqui s'appelle Account.Et je vais avoir, du coup,mon Login.HTML qui est dans Account,au même niveau.
00:36:41 :Hop, on va laisser, voilà.Au même niveau que Account, je vais avoir mon Login.HTML.Donc je fais Account.HTML.Comme ça, Django va reconnaîtremon template HTML.
00:36:51 :Voilà, donc là, si on va dansla LoginView, si je modifie mon URL pourlui passerma...Hop là. La LoginView.Donc là,on a plus besoin de passer la méthodeAsView parce qu'on est dans une fonction.
00:37:09 :LoginView,qu'on n'appelle pas. Voilà.Hop, on lance le serveur.Login.J'ai bien mon formulaire.Le problème, c'est qu'ici, il ne fait rien.Donc,pour ça, il faut gérer le casoù on a une requête poste.
00:37:29 :Donc, il se requeste quoi?Méthode.Donc, si on a une requête poste,ce qu'on va faire, c'est qu'on va, dans notre formulaire,on va passerdans notre formulairela requête, tout simplement.
00:37:45 :Voilà.Et si notre formulairehop là,il est valide.Hop là. Il y a quelqu'un qui a des questions? Peut-être non.J'écoute, excusez-moi.Si notre formulaire est valide, là,ce qu'on va faire, c'est qu'on vaauthentifier l'utilisateuravecles informations qu'il a rentrées.
00:38:11 :Donc,on va utiliserAuthenticate.Authenticatevient detango.com.authdonc avec l'logo Authenticate, ici.Voilà.Hop là, on était où? On était ici.Et Authenticate, peut-être,il ne faut pas... Non, il n'y a pas besoin de passer
00:38:33 :la requête. Alors, il peut se débrouillersur la requête.Il peut se débrouillersur la requête. Par contre, il lui fautforcémentl'emailque l'utilisateur a envoyéet un mot de passe.
00:38:51 :Il lui fautle mot de passe qu'il a envoyé.Et ça, du coup, on vale rechercherdans ce qu'il a envoyé. Ici, Authenticate.Voilà. Et ensuite,
00:39:05 :on va mettre une petite condition.Alors, j'ai un zoomqui est assez gros pour la présentation, du coup, j'ai un peu de mal à...Donc, on va vérifierque l'utilisateur, il n'est pas None.
00:39:15 :Euh...Djangoa cette façon de faire, et mêmes'il n'y a pas qu'avec Django, j'ai vu, on en a parlé,il peut rentrer un petit bout, peut-être.
00:39:25 :On pourrait très bien dire If User,mais ce n'est pas pareil, parce qu'en fait,entre None, par exemple,si vous faites une...Je ne sais pas si vous avez une...
00:39:35 :Vous avez ça.Ça, ce n'est pas la même chose.Voilà. Là, vous pourrez très bien...Si on met If Chain, ça va être évalué à False.
00:39:47 :Si vous mettezIf Chain, ici, ça fonctionnera pareil, en fait.Mais ici, on veut absolumentvérifier que l'utilisateurétait bien None, parce qu'Authenticate,si on va regarder dans le code source,soit ça retourne un utilisateur, soit ça retournerien du tout. Enfin, None. Voilà.
00:40:03 :Ça peut être un peu confus au début,mais...Ça fait partie desinterrogations que j'ai régulièrement.C'est quoi la différence entreIf User is not None etIf Not User, par exemple.
00:40:17 :C'est ce que je disais avec un autreexemple, par exemple, c'est queta chaîne de code, quand tu vérifiessi ta liste est vide, par exemple,tu mets...
00:40:27 :C'est ça, si t'as rien dans ta liste, tu fais If Not Listet quand il n'y a riendedans, tu vas rentrer dans cette condition, parce qu'effectivementil n'y a rien dedans, maisc'est pas égal à None, en fait.
00:40:37 :Il faut vraimentque cette différence soit de...Je disais tout à l'heure, quand on rentre ça,ça, si tu fais If Not Chain,ça passe paret ça va êtrepareil dans ce cas-là.
00:40:51 :Mais ici, c'est pas le même...On n'est pas dans le mêmecas de figure, le même objet, en fait.Il y aune distinction, quand même, c'est que l'utilisateurvide n'existe pas, contrairementà la chaîne vide. Et donc, du coup,
00:41:07 :là, si tu fais If Not User,enfin, If User, en l'occurrence,ça suffit, parce quela seule condition qui feraitqu'il est faux, c'est s'il vaut None.
00:41:17 :Et là,c'est intéressant, Thierry, parce queDjango recommande de mettre If Not Noneet je ne sais pas trop pourquoi,mais exactement, il va absolument,il nous incite à le mettre, ça, If Not None.
00:41:29 :Dans ses exemples, il l'utilise,donc finalement, c'estcomplètement équivalent.Est-ce que c'est une recommandationou c'est un exemple ?Dans les faits, c'est ce que tu veux faire, c'est queAuthenticate va retourner Nonesi l'utilisateur,si la connexion n'est pas légitime.
00:41:49 :Et pour le coup, c'est ce que tu veux tester,donc c'est explicite, et on aime bienl'expliciter.Ok, merci.Authenticate,ce qu'il va retourner ici,quand on regarde, il ne retourne rien,la seule chose qu'il va retourner, c'estsoit l'useur, soit la fonctionva retourner None.
00:42:11 :C'est tout.J'aime bien me balader sur Django, mais c'est un coupavoir mal au crâne des fois parce que tu te posestrop de questions.
00:42:19 :Donc voilà,le login a besoin de la requêteet de ton utilisateur.Voilà, et on va faire unretourne, on va faire unredirect vers l'index.
00:42:31 :Et ici,on va faire les choses bien.Ouais, on va se mettreune condition ex comme ça.Voilà.Donc là, si on regarde,et voilà,là je suis connecté.
00:42:47 :Par contre, on va faire,là je vais faire une erreur exprès.Voilà, il ne fait rien,il ne se connecte pas, je n'ai pas de message d'erreur,je n'ai rien.
00:42:57 :Ici,il pourrait y avoir deux façons de faire.Soit,quand vous êtes dans le cadred'unlogin issude Django,où le login ne se fait pas,vous allez remettre une autre condition encore ici.
00:43:15 :Et là, vous allez mettreun message,comme on a fait tout à l'heure,en mettant par exemplele mot de passe ou l'utilisateurincorrect, machin.
00:43:27 :Je n'aime pas trop faire ça. Je l'ai fait, je ne suis pasvraiment fan. Ce que j'aime bien faire, c'est allertoucher dans mon formulaire ici.
00:43:33 :Ce que je vais faire, c'est que je vaissurcharger la méthode clean.Alors là,on va le faire en live parce queje m'engage dans un truc.
00:43:43 :C'est bon.On vaappeler la méthode super.Hop.Ok, c'est ça.Il me semble que c'est ça la méthode clean.Et on va retourner.Alors, ce qu'on pourrait faire du coup,c'estuser...
00:44:05 :On pourrait faire un truccomme ça.On va refaire ça en fait.Authenticate. On va l'utiliser ici.On va faire userName.Voilà, on va faire ça. userName
00:44:19 :égalcleanData.Et là, ici, ça va être l'email.Et passwordest égal à cleanData.Hop là.Password.Et ici, on peut faireif userici, s'il est un non,on peutlever uneerreur. Donc, c'est
00:44:47 :variation d'erreur.Et là, on peut mettreuser oupassword.C'est sympa.Vous comprenez.K.O.K.O.Je pense que j'ai passé les off. Je pense que ça va marcher.
00:45:07 :On va tenter quelque chose.Hop.Et là, maintenant, si je fais un login.Hop.Ça ne marche pas.Qu'est-ce que j'ai fait dans la méthode clean?
00:45:19 :J'ai fait mon raise.Et...CleanData.J'ai oublié un truc.Il se trouve, il faut desargs.User authenticate.Là, j'ai l'email. Ici, cleanData.Password.Ok.
00:45:43 :Et ici, je retournemes cleanData.Attendez.Super.Euh...Tac.Je regarde si il y a quelque chose.Hop.Oups.Hop.Je vais essayer quelque chose d'or.
00:46:11 :On va recharger la page.C'est génial.Ça ne vient pas de l'or.C'est bien ce que je pensais.Euh...Je vais regarder du coup.Je pensais qu'il y avait moyen de faire comme ça.
00:46:27 :Pour moi, c'est même sûr d'être clean.Ici, j'utilise cleanData.Email.Excusez-moi, je fais ça en live.Password est égal à cleanData.J'ai bien mon password.
00:46:43 :Raise. Ok.Je regarde tout de suitece qui ne lui va pas ici.Je me dépêche.Hop là.Tac, tac.Tac.Euh...Ok.Euh...Ouais, c'est ce que j'ai fait.
00:47:11 :Ok.J'ai eu une erreurqui m'embête là.C'est dommage.Je pensais que...Ah, je suis bête. Excusez-moi.Voilà.Même en s'en cherchant, sans trouver la solutionsur Internet.
00:47:29 :Ok.C'est la méthode cleanqu'on veut surcharger.Attendez.Je ne pense pas qu'il y ait besoind'ArgsDKWard ici.Tac.Pardon ?Il n'y a pas besoin.
00:47:47 :Ouais, besoin, c'est ce qu'il me semblait.C'est ça.Je ne sais pas pourquoi j'ai carrément quitté cleanData.Euh...Même pas besoin d'aller plus loin que ça.
00:47:57 :Euh...Allez, on recommence.On va relancer ça.J'ai un coup de feu, du coup.J'aime pas ça.J'ai envie de s'embarquer dans un truc un petit peu...
00:48:09 :Voilà, c'est ça.Donc voilà.C'est une méthode de faire, en fait, pour...Dans votre formulaire,si l'effet maison, entre guillemets,pour lever une erreur,une erreur,l'utiliser par validation erreur.
00:48:25 :Et moi, vu que je suis un gros tricheur,j'ai Django CrispyFormsqui se charge de me les rendreet je vous complique pas la vie.
00:48:33 :Voilà. Et juste pour revenir sur le formulaire...Euh...Inspectez. Je connais pas encore Vivaldi.Voilà, c'est comme ça.Votre formulaire, on est bien d'accordqu'il est sans Python,mais que vous avez bien votre emailici,et votre password online ici, voilà.
00:48:53 :Donc, en fait,vous pouvez tout faire en Python.Enfin, presque tout faireen Python. Votre formulaireet votre template.Vous mettez juste votre formulaire,c'est tout.
00:49:07 :Il y a un peu de HTML à faire quand même,mais en gros, ça se trouve.Votre baliseForm, votre méthode,le CSRFToken,ça, la plupart des gens qui font Django,ils connaissent. Et moi, j'utilise
00:49:19 :CrispyForms. Voilà.CrispyForms, j'aime bien, ça me rend mes...Je l'utilise avec Bootstrap 5,donc ça m'habille en forme, mais...Mes formulaires, voilà.Et pour le Logout,c'est une fonction toute simple.
00:49:35 :C'est une fonction toute simplequi peut utiliser uneclasse, bien sûr, mais moi, perso,à la fois, j'utilise une fonction,et vous avez juste à passerla fonction Logout ici,avec la requête, et c'est tout.
00:49:49 :Votre Logout, il est fait. Il n'y a pas plus du compliqué que ça.Donc, voilà.Si vous utilisez une classe,la classe LogoutView de Django,il vous obligera à utiliserune métapost,par un formulaire avecmétapost. Je trouve
00:50:05 :que c'est pas plus mal, parce que ça modifiel'état de votre base de données, vous les connectez.Donc, c'est pour ça qu'ici,j'oublie forcément d'avoir le postici, sur le Logout.
00:50:15 :Donc,la LoginView, du coup, je vais revenirrapidement dessus.Tac.En fait, vous n'avez même pasbesoin de lui donner de formulaire, en fait.Ça va le gérer pour vous.
00:50:29 :Donc, vous avez juste un template,la page suivante, et c'est bon.La page desuccès, je veux dire. Et c'est bon, et même les erreurs
00:50:37 :vont être gérées pour vous.On l'a vu tout à l'heure, de toute façon, quand je signele connecté. Donc, voilà. Maintenant,on va juste passer sur lesmodifications.
00:50:47 :J'ai une petite question.Oui. Pourquoi est-ce quetu mets la next page àindex, forcément ?Là, c'était vraiment que pourpour l'exemple.C'était sur la LoginView,la classe.
00:51:07 :Ouais, c'est ça, je suis là.Vas-y, dis-moi.Parce que ça, c'est une des fonctionnalitésclés, on va dire,de la LoginView de Django.Et si tu fais ça,tu perds quand mêmeune bonne fonctionnalité,qui est cette capacité de te renvoyerchaque fois sur la pagequi t'a envoyé vers le login.
00:51:31 :Ah ! Oui, c'est bon.Par exemple, si tu cherches àatteindre ta page de profil, par exemple,et que tu n'es pas connecté,toi, tu vas être redirigé automatiquementvers la page de login.
00:51:45 :Et ensuite, quand tu t'es logué,il va te renvoyer vers ta page de profil.Et là, comme tu le fais,il va systématiquement, quand tu le fasses,te renvoyer toujours vers la page d'index,ce qui peut être, en termes d'utilisateur,un petit peu embêtant.
00:51:59 :Je suis d'accord avec toi.J'ai souvent eu ce cas où, effectivement,je redirigais quand j'avais un loginrequerred, c'est ce qu'il y a là, par exemple.
00:52:07 :Et donc, automatiquement,je renvoyaisvers la pageoù je voulais accéder à la base.C'est parce qu'avant, peut-être que j'avaisl'habitude de faire mes LoginViewsous forme de fonction,et que je n'ai pas vraiment expérimentédans ce cas-làavec la LoginView sous forme de classe.
00:52:27 :Merci Thierry.Ce qui fait que la fonctionest incorrecteselon la sémantique de Django,ce qu'il veut faire. Par contre,sur ta classe,en haut, ça te simplifieparce que tu effaces ta ligne 58,et puis, tu as justeà mettre le template nameet puis ce que tu veux.
00:52:49 :Tu fais comment pourrépartir ?Ici, tu effaces simplement la ligne 58et puis, tu asune classe de login qui fonctionne.Et puis, ça, tu n'as même pas besoinde la définir. En fait, moi, je n'ai pas souvenir
00:53:05 :en 20 ans d'avoir définiune LoginView de ma vie.Donc, en général,tu n'as jamais besoin de le faire dans un projet.La LoginView de Django,elle est OK.
00:53:17 :Elle fonctionne.Oui, bien sûr.OK.D'accord. J'ai pensé à ce cas-là.Merci Thierry.Merci d'avoir soumis ce potentielproblème.Du coup, pour lesmodificationsdes mots de passe quand on estsur le...
00:53:39 :quand on est connectéici,des fois, je vais modifier mon mot de passe.Ici, je vais rebrancher mon mot de passe.Voilà.C'est ça. Donc là, j'ai modifié mon mot de passe.
00:54:01 :Là, il est modifié.Il n'y a pas de problème.Je reviens à l'accueil. Maintenant, s'il me déconnecte,il faut que j'utilise le nouveau mot de passe pour me connecter.
00:54:09 :Ensuite, je peux très bien aussidire... Là, je reviens à mon mot de passe.Je suis perdu. Du coup, je vais ici.Je mets mon adresse mail.
00:54:17 :Par exemple, lui.Hop.Et là,je vais m'envoyerdu coup, un lien pour faireun reset de mon mot de passe. S'il veut arriver un jour,
00:54:29 :il est là. Voilà.Donc, vous voyez, restriction du mot de passe.Hop, je clique.Boum.Le reset se confirme.Nouveau mot de passe.Et c'est tout bon. Maintenant,
00:54:49 :mon mot de passe a été modifié.Si je mets le dernier, je suis revenu à celui initial,je peux me connecter.Voilà. Donc, en fait,
00:54:57 :c'est pareil avec Django. C'est un peu tout lâché,on va dire.Je me fais un...C'est intéressant.Je me fais un...Dans mon papier dessus, j'ai un modulepassword. Et c'est là que je gère tous mes...
00:55:11 :mon système de manipulation de mot de passe.Donc, on a vu icique l'utilisateur,quand il veut changer son mot de passe,lui-même,on va utiliser cetteclasse-là.
00:55:27 :Ici, je remets mon HTMLque j'utilise.Là, ça va être...C'est beaucoup des formulaires.Donc, en fait, vos templates, ils ne changent pas énormément.J'ai même oublié de l'appeler login.
00:55:39 :Je vais peut-être...Je vais en mettre peut-être mon mot de passe ici.Voilà.Et en fait, à chaque fois,vous mettez ici votre vue de redirectionune fois que vous avez...
00:55:51 :Une fois que le formulaire est validé.Donc là, je change mon mot de passe.Ça me renvoie vers la vue changementdonne. OK. Boom.Ici.
00:56:03 :Et change password done.Ça me dit, en gros, que le mot de passe a été modifié.Voilà.C'est ce qu'on a fait làà l'instant.
00:56:13 :Oui, Thierry.Dans ton...Ouais.Ouais, Thierry, t'es encore là.Toi, tu le fais de cette façon-là aussi.Je sais que Thibault l'avait montré aussi une fois.
00:56:29 :Tu fais...Alors, par contre, ça, Thierry,j'ai vu ton message et je n'ai jamais fait comme ça.Enfin, je n'ai jamais essayéde... Je ne l'ai pas refait
00:56:41 :comme ça depuis longtemps.Mais tu peux aussi définir facilement les templatesHTMLpersonnalisés ou pas.Je ne sais pas si tu m'entends....Du coup, Thierry,quand tu fais ton... Ouais, Thierry me parlait
00:57:07 :du coup de...J'en parlais peut-être à la fin, à ce moment-là,mais ouais, je l'avais appris comme ça à la base.En gros, là, ce que je fais ici,ce que je fais ici,c'est que du coup, ce que je disais,là, je change mon mot de passe. J'ai la vue pour aller changer le mot de passe.
00:57:21 :Une fois que l'utilisateur l'a changé,boom, c'est validé.Il n'y a pas de problème.L'extra contexte, ce n'est pas forcémentobligatoire. Ça, c'est un plus si on avait
00:57:31 :le temps, mais j'ai l'impression qu'il est déjà tard.On ne va pas s'embêter avec çapour cette fois-ci. Ensuite,s'il veut faire un reset de son passwordutilisateur,ici, je passe par la password.resetview.
00:57:43 :Donc pareil, j'ai un templateque je définis. Je définis un templatepour mon email. Donc à chaque fois,j'ai tous mes templates qui sont définis ici.
00:57:51 :Donc resetpassword, resetpasswordcomplete, confirm, done, email.Donc là, ici, c'est monresetpasswordqui est là. Donc c'est encoreun formulaire, donc il n'y a pas grand-chose qui change.
00:58:03 :Et j'ai le template de mon email.Qui va être traduiten français, peut-être.Oui, c'est bon.Ça, je l'ai copié.En fait, c'est le système de base de Django. Il faudrait que je l'ai
00:58:15 :recopié, mais je pourrais utiliser celui de base.Donc ici, vous avezvotre reset. Ici, la resetdonne vue, c'est qu'en gros,le reset a bien été...
00:58:27 :Je vais reprendre pour ne pasqu'on se mélange. On va faire reset.Donc là, on est ici. On a notre vue.Resetpassword.On envoie le mail.
00:58:39 :Resetpassword done.Resetpasswordlà. Resetpassword done.Et ensuite, on vaaller confirmer justement cereset.En cliquant sur le lienqu'on a reçu. C'est en cliquant sur le
00:58:59 :lien qu'on va confirmer notre reset.Voilà. Et donc tout ça,c'est inclus à Django. Je n'ai rienréinventé. En fait, c'est gérible de toute leur classe.
00:59:07 :Il faut juste penserà... avecDjango, dans lesURL.Quand vous faites votrereset, j'ai tout séparé.Je vous ai remis sur votre vue.Donc ça a bien été fait. Il n'y a pas de problème.
00:59:23 :Le reset done.Ici, ça va être notre...Quand on va cliquer sur le lien, en fait,on va pareil avoir un token avec unUIDB comme on a vu tout à l'heure.
00:59:33 :Django va utiliser son système de tokenpour...pour qu'on aitle droit, entre guillemets, de réinitialiser le mot de passe.Voilà. Et ensuite, une fois qu'on a réussi le mot de passe,
00:59:43 :c'est une complète vue.Ça marque, OK, votre mot de passe a été...a étéréinitialisé. Voilà.Il n'y a vraiment, en fait, pas grand chose à refaire.
00:59:53 :C'est vraiment changement de mot de passe.On change, c'est fait.On fait un reset.Donc le mail a été envoyéet ensuite, on vaarriver sur la confirmation.
01:00:05 :Et là, c'est terminé. Tout simplement.Il n'y a rien de plus.Et dans les URL, voilà, c'est ce que je vous disais.On change le mot de passe. C'est fait.
01:00:13 :Et dans le cas du reset, c'est on reset.Le mail a été envoyé.On arrive sur le formulaire, à part le mail,pour changer son mot de passe.
01:00:21 :Et là, ça a été fait.Voilà. Tout simplement.Donc, voilà,pour les resets du mot de passe.Je vais vous donner lerepo, dans tous les cas.
01:00:33 :Je ne sais pas s'il y a des questions...Ouais. Ouais, justement.Désolé, j'ai une question encoreun petit peu à côté.Juste, vous avez pas mal defois où c'était appelé reverse lady.
01:00:45 :Et j'ai juste un peu du mal à capterla différence,par exemple, avec un redirect.Avec un reverse normal,tu veux dire ? Parce que le reverse, c'est reverse lady.
01:00:55 :Oui, pardon. Ouais.J'ai un exemple.Je n'ai pas d'exemple là.Et quand tu définis une classe, en cliquant, par exemple,tu vas avoirune classe que tu vas appeler...
01:01:07 :On va le faire maintenant,tout de suite.Non, justement, c'est une questionque vous m'étiez posée aussi au début.Hop.Je m'ouvre un...Tiens, j'avais fait le test, j'avais prévule cas où j'avais la question.
01:01:25 :Donc, tu es d'accord que là,j'ai une classe,mais je ne l'ai instantané nulle part.Ok ? Ouais.J'ai fait un print dans ma classe.
01:01:35 :Et le print, ça fait bien quand même.En fait, quand tu définis une classe,en cliquant,les attributs de ta classe,ils vont être évaluésau moment où on veut les charger.
01:01:49 :Les attributs de ta classe, ils vont être évalués.Et le problème avec Django,c'est que les URLne sont pas forcément évaluées tout de suite.
01:01:57 :Elles ne sont pas changées tout de suite.Donc, si tu as des reverse comme ça dans tes classes,ils vont chercher des URLqui ne sont pas tout de suite résolues.
01:02:05 :Ok.Les attributs sont automatiquement évalués.C'est pour ça.C'est pour ça qu'il faut un reverse lazy.Et en fait,les URL, elles n'ont été évaluéesqu'au moment où il y en a besoin vraiment.
01:02:19 :D'accord.Dans les fonctions,tu peux faireun reversenormalpuisqu'en fait,le reverse, ça ne va pas être évaluétant que tu n'utilises pas ta fonction,et quand c'est enattribut de classe,ils vont chercher à évaluerle résultat de l'URL alors qu'elle ne sera même pas chargée.
01:02:43 :Ok. D'accord. Je comprends.C'est pour ça que tu asun reverse lazy qui est paresseuxet des reverse qui ne sont pas paresseux.Ok.Super. Merci beaucoup.
01:02:55 :Désolé. Je ne sais pas si c'était clair.Si, très clair. Ça m'a permis de comprendreque c'estun truc qui n'était pastrès clair dans ma tête, justement.
01:03:05 :Ok.Ah oui, je reparlerai.Je reparlerai. Il y a donc Thierryqui m'a fait penser à quelque chose, qui m'a envoyéune façonde gérer avecl'authentification, tout ça,en incluantles liens du URL.
01:03:25 :Voilà.On en reparlera. Je ne sais pas si tu veux dire un motrapidement, Thierry, là-dessus.Simplement, toutes les vues que tu as montrées,toi, tu les as définiesjuste pour souventdéfinir ton template name.
01:03:39 :Et ça, c'est en faitinutile.Il suffit d'inclure les URLs de Djangocar tu as tout prévu pour ça.Et en fait, tu aszéro vue à créer.
01:03:51 :Tu as juste la vue de sign-up,d'inscription à créer.Toutes les autres vues, elles sont fournies par Djangodonc on n'a pas besoin de les redéfinir soi-même.
01:03:59 :Par exemple,change password.Moi, j'ai effectivement tendance àredéfinir mes classes comme ça.Mais effectivement, il y a une façonde faire. Thierry,tu m'as envoyé un messageprivé. Ça, je l'avais vu au tout début.
01:04:19 :Je l'avais fait. Mais par contre,le template qui est utilisé dans ta façonde faire, je ne sais pas sion peut le redéfinir facilement. J'ai un doute.
01:04:27 :Alors, en fait,les templates par défaut, ce n'est pasles mêmes chemins que toi. Mais tu peuxle redéfinir. C'est-à-dire que tu utilisesle chemin que Djangoutilise lui-même. Et donc, tu vas pouvoir
01:04:39 :le redéfinir. Maistu peux aussi définirtes propres chemins.Le chemin par défaut, c'estregistration plutôt que account.Mais rien ne t'empêche de mettre dans tes templatesde ton applicationuser ou autre. Je n'ai pas vu comment
01:04:55 :ça s'appelait. Rien ne t'empêchede mettre un répertoire qui s'appelleregistration et desurcharger les templates de Djangodirectement.C'est vrai que j'ai tendance àfaire mes classesen fait d'un fichier pythonexprès en fait avec mes classesde dons de cette manière-là.
01:05:15 :Je ne sais plus pourquoi. On en avait parléune fois sur Twitter.Tu m'avais dit que ce n'était pas forcément une mauvaise choseça, de redéfinir dans un fichier à part.
01:05:25 :Non, ce n'est pas une mauvaise chose,mais ça peut faire peurà la personne qui débutede voir le nombre de classesqu'il doit redéfinir.
01:05:35 :D'accord.Pour les classes qui débutent, je passeraipar le système. D'accord.Je comprends.C'est vrai que du coup, ce que disait Thierry,en plus c'est beaule nom de sa formation d'ailleurs.
01:05:49 :Je vous invite à aller revoir sur ce qui estle compte.Je suis passé par la suite. C'est vrai que je l'ai fait une fois,
01:05:57 :mais après je ne sais pas pourquoi.Je redéfinis toujours mes classesici avec mes templateset mes reverses. Après, je reverse forcémentversce que Django ferait déjà à la base,mais j'ai tendance à me faire un fichier pythonà partavec mes vues que je redéfiniscomme ça.
01:06:17 :Le système peut être un peu plus simplecarrément.A voir de quelle façonvous le faites.Ecoutez, c'était à peu près tout.Est-ce qu'il y avait des questions ?
01:06:31 :Peut-être juste une question par rapportà ce que tu parlais,Gabriel, avec Thierry, justement.Le fait quece soit redéfini comme ça,au-delà del'organisation, ça va permettrede changer quoi ? Ça va être
01:06:53 :l'URL et puisle template ?Oui, je l'ai fait.Peut-être que ça change ?Non, j'en fais mes URLs,mes templates. Si j'ai besoin de passer
01:07:05 :de l'extra contexte, en général,il n'y a pas forcément besoin de passer.Pour personnaliser vraiment.Oui, c'est ça.Là, par exemple,tu me diras, c'est débile ce que je mets dedans,mais c'était pour l'exemple.
01:07:21 :Tu peuxpasser du contextecomme ça, avec un attribut.On peut passer parcette méthode-là.En fait, dans ta vue,tu peux définir d'autres chosesdans ton contexte.
01:07:39 :Tu pourrais très bien,je ne sais pas, je n'ai pas d'exemple, maisavoir d'autres éléments que tuvoudrais envoyer.C'est pour ça, moi,j'ai un peu mes templates un peu tout fait.
01:07:53 :Dans tous mes projets, je le fais comme ça.Je personnalise comme ça, à la demande,je personnalise mes vues.C'est pour ça que je...C'est vrai qu'on avait parlé de Cyrix une fois,il m'avait dit justementqu'il voulait utiliser le systèmeDjango de manière plus directe.
01:08:11 :On se souvient, Cyrix,c'était pas une mauvaise chose en soi.Mais que oui, effectivement,quelqu'un qui débute dans Django, qui va voirtoutes les classes, il va se dire« Putain, pourquoi il fait ça ? »
01:08:23 :C'est parce que, tant que j'ai l'habitude,c'est ma façon de faire, et comme ça,je passe mon contexte, si j'ai besoin.Voilà, c'est tout.Voilà, je pense que du coup...
01:08:37 :Le rendu de mes formulaires,c'est sympa,ça c'est un module Django,mais on verra,à la fin de la prochaine session,sur Django CrispyForm,et les formulaires en général.
01:08:51 :Voilà, je ne sais pass'il y avait des questions,c'est qu'on n'a pas eu le temps,si on avait eu le temps,j'aurais parlé des tests,comment clister les systèmes utilisateurs,mais là, on a déjà dépassé un petit peu.
01:09:05 :On a déjà dépassé un petit peu, donc...Oui voilà, est-ce qu'il y a d'autres questions du coup ?Non pas ?Je vais mettre toutes les systèmes.
01:09:21 :Fab ?Ça reste dans, ça.Ouais, je sais.C'est costaud.Il faut s'y mettre.C'est vraimentune erreur.Pour les questions, il faut que j'arrive.
01:09:39 :Je fasse un peu moins de choses peut-être.Il y a peut-être un point que je n'ai pas vudans la gestion des mots de passe,c'est peut-être dans lewidget, c'est si tu veuxvisualiser le mot de passesaisi.
01:09:53 :Ah, parce que là,il est masqué, ouais.Il suffit que tu...là tu supprimes ton widgetet ton mot de passe va être en clair du coup.
01:10:05 :Ah oui, non mais tu sais, c'est les petits boutonsoù tu tapes en masquéet t'appuies sur le petit seuilet en fait tu visualisesparce que c'est dans un widget ou autre chose.
01:10:15 :Ouais, alors ça c'est un peu plus du front.Je pense, et çac'est du front.Je ne sais pas s'il y a des gens qui font du front,moi Thierry c'est qui fait du front, mais je ne sais pass'il y en a d'autres qui sont basés en front, mais ça j'avoue que
01:10:27 :ce n'est pas trop bon.Ok.Par exemple, justepour le rendu des messages, j'avais promisà Étiennej'avais promis un truc à Étienneparce qu'on utilisaitles messages de Django là.
01:10:45 :Moi je suis sur une applicationde...je ne sais pas si j'ai déjà un...pour vous montrer un petit tructout simple.Hop là.Pour vous montrer un truc tout simple.
01:10:59 :J'avais juste dans mon admin, est-ce que j'aiun espace administration, moi je ne l'ai pas encore mis.Je viens de la commencer celle-là, c'est pour ça.
01:11:05 :L'administration.Tac.Utilisateur.On va le supprimer.On va le réinscrire.Il y a des moyens assez simplesde rendreles messages que l'on a vus de Djangoà toi, genre votre compte a bien été crééet machin.
01:11:25 :Alors là, il y a pas mal de choses.Tac.C'est pas...ça s'en fiche, tac.Hop.Hop.Voilà.Donc là, tu vois Étienne,tu as une petite pop-up par exemplequi s'ouvre.
01:11:49 :Bon voilà, ça c'est juste le petit...J'ai promis, je dirais,on utilise un...c'est ce qu'on appelle un...SweetAlert, ça s'appelle,on va le chercher.
01:12:01 :Sweet...Ah non, tac.SweetAlert.Ouais, ça se fait l'air d'eux.Je sais plus, c'est un truc dans le genre, ça se fait l'air.Est-ce qu'il y a un sale avecPip aussi, c'est ça ?
01:12:17 :Ah non, non, non, du tout.Ça, on est dedansjuste pour te montrer son template.Ça,je sais même plus comment on le tête,dernièrement je ne l'ai pas regardé.
01:12:29 :J'ai dû installer un...Voilà, un...avec le CDN, en fait.Comme tu ferais avec Bootstrap par exemple.Même si je sais que c'est pasforcément très bien de mettre le CDNdes fois dans le...
01:12:47 :Mais ensuite, après,t'assiches tes messages dans un script,ton script.Voilà, dès que j'ai des messages,je les mets dans le script.Et c'est un scriptJavascript, c'est tout.
01:13:01 :Voilà.Ok.Euh...Ben voilà.Et après, sinon vous pouvez faire lerecapture, je sais pas.On va faire...Non, non, je rigole.Ouais, ça va prendre un petit peu de temps encore.
01:13:23 :Mais ouais.On pourra faire ça une fois le capture.En fait, les...Parler des...Comment dire, des...Librairies de Django,j'utilise le plus, j'en ai pas mal quand même que j'utilise.
01:13:37 :Ça peut être très pratique.Mais ça, ouais, on fera un...On fera un...Il y a un par ici,un truc à part, je pense.
01:13:47 :Bon celui-là, on l'a pas grand-chose non plus.Euh, non mais ouais.On fera, je sais pas si on a pasles sciences librairies.Donc voilà.
01:14:01 :C'est top.Voilà.Ben merci beaucoup en tout cas.Merci beaucoup.Fais un truc pour lui, comme toujours.Ben merci.C'est sympa.Il y avait une question sur le...
01:14:17 :Le fait de montrer le mot de passesi on voulait le montrer.Je viens de préparer un petit exemple si jamaisla personne veut voir comment ça se fait.
01:14:29 :Ah vas-y, ouais.Par contre, j'ai aucune idée si je peux partager ou pas.Ah si, si, si. Attends, j'arrête le mot de partage.Vas-y.Alors,ça fonctionne.
01:14:41 :En général, j'ai des problèmes avec...Voilà.C'est la première fois que je le fais avec un...Peut-être non.Non.Non, ce sera pas pour maintenant.
01:14:55 :Mais je posterai quelque part, je te donnerai.Parce que je suis sur mon Macet puis comme je n'ai jamais partagé mon écransur Discord,il me demande d'aller autoriser ce partageet puis ça me prendrait 10 minutespour trouver où c'est.
01:15:09 :Merci.Mais conceptuellement, c'est juste duJavaScript en fait.D'accord.C'est vraiment une ligne de JavaScript.L'idée, c'est quele input du formulaire, il est affiché avecun type password.
01:15:25 :Et puis il faut juste en JavaScript, en clic sur un bouton,venir changer ce type de l'inputde passworden type texte. Et puis dans ce cas-là,
01:15:33 :ça va immédiatement enlever les étoiles et puisrendre visible le mot de passe.Et puis on peut faire une sorte de boutontoggle pour passerde vue password en vue texteet puis revenir en vue password, etc.
01:15:45 :Mais du coup,sur le back-office de Django,il faut le mettre visible alors ?En texte visible ?Mais en fait, c'est juste une histoire de front-end.
01:15:55 :C'est juste une histoire de front-endparce que cette histoire d'étoiles,c'est juste un rendu du navigateurqui met les étoiles.Mais derrière,la valeur, elle est en texteen clair.
01:16:09 :Donc l'idée, c'est justed'éviter que si tu as quelqu'un qui regarde sur tonépaule,la personne puisse voir ton mot de passelorsque tu le tapes.
01:16:19 :Mais programmatiquement,le mot de passe, il navigueen clair. Il n'y a absolument rienqui est encrypté ou quoi que ce soitdans ce processus-là.
01:16:29 :D'accord, il est encrypté après ?Au niveau de l'enregistrement ?Au niveau de l'enregistrement,alors là, il y a toutqui est prévu par Django.
01:16:39 :Oui, oui.Là, il y a un hasherqui intervientet qui va chiffrer ton mot de passe.Oui, parce qu'on a un peu vu...C'est une autre question encore.
01:16:51 :Ok.Je voulais te dire,si tu fais, par exemple,tu feras le testserbettement à user.object.createen mettant ton utilisateuret ton mot de passe,et bien là, en fait, il ne sera pas forcément encrypté ton mot de passeparce qu'il faut vraiment que tu passes parle manager createUser
01:17:11 :ou createSuperUser, en fait.Oui, avecles trucs d'encodage et décodage.Enfin, c'est vu dans le codeque tu encodais et ensuite tu décodais.Ça, c'est pour le token.
01:17:23 :Mais...J'avais quelqu'un, je ne sais plus, qui faisait dans un projetje ne sais plus quiet en fait, au début, je n'avais pas compris son erreurparce que je n'avais pas rien de son code. Il me fait
01:17:33 :je ne comprends pas. Il faitmes utilisateurs dans un base de données.Je ne sais pas ce qu'ils sont en clair.Sur administration,effectivement, il y avait les mots de passe en clair.
01:17:43 :Je me disais, attends, commenttu fais pour faire tes utilisateurs ?Je faisuser.objects.createet puis il mettait userName,donc l'utilisateur, et password,le mot de passe, comme ça. Et du coup, c'est créé juste
01:17:57 :comme ça, un peu à l'arrachel'utilisateur, sans passer parle processusdu manager de Django, en fait,qui te hache tout ça.D'accord.Ça peut se voir. Je l'ai vu.
01:18:13 :J'ai déjà vu.C'est intéressant.Un sujetqu'on pense simple, c'est hyper complexe.Tu m'étonnes.Tu vois,ce que fait Django pour tourner la planche,c'est assez énorme.
01:18:29 :Je vous ai mis le lien,le repo,dans le chat.Super.David,je t'ai rajouté dans le chatc'est Reversalogy.Justement dans leredmi du GitHub.
01:18:53 :Super, merci beaucoup Gabriel.Unepetite question.Comment est-ce qu'on fait pourvoir les vidéos desprécédentes présentations ? Parce que tu disaistout à l'heure, Gabriel, quela précédente que tu avais faite avait étéenregistrée.
01:19:11 :On les retrouve.Alors attends,Johnnur est en train d'enregistrer.Difficilement, d'ailleurs.Alors attends, c'est dans...Dans les événements,il faut rechercher aprèsla session.Je recherche par exemple dans cette session.
01:19:33 :Par raisonqu'il y a... Qui a filmé celle-là ?Celle-là date de quand ?Celle-là date du 24 avril.Ouais, elle bat fort.Pendant l'événement, en fait, quand tu regardes dedans,tu retournes sur les sessions et t'as lesliens vers le drive où sontles vidéos.
01:19:51 :Moi, dans l'événement, j'ai queles prochains.J'ai pas les anciens.En gros, tu l'as posérevenir, passer, tout ça ?T'as pas ancien poste ?
01:20:09 :Non, moi, j'ai pas non plus.En fait, il faut cliquer en haut, sur passer.En haut, il y a avenir, passé,projet, tout ça.Et dans passer, normalement, on les trouve.
01:20:21 :Ah, c'est décoché par défaut.D'accord.Enlevez tous les fils.Dans le forum événement, vous avez ancien...Ça s'appelle ancien poste, quoi.Ouais, ancien poste.Non, moi, je vois pas.
01:20:35 :Je crois que j'ai pasle forum événement, moi.J'ai pas ça.Ah, c'est bizarre.C'est embêtant, ça.J'ai pas non plus le forum événement.T'as envie de cliquer dessus ?
01:20:49 :Non, c'est dans communauté.Il faut rechercher.Il faut rechercher un salon.Hein ?C'est pas en cliquantjuste en haut,et en cliquant sur show all channels.
01:21:03 :Là, normalement, il y a...Je l'ai pas bien entendu.Où est-ce qu'il faut cliquer ?Tout en haut, dans docstring.Sur l'onglet docstring, tout en haut à gauche.
01:21:17 :Tu cliques dessus, et après, t'asshow all channels.Ah, d'accord.Après, tu casses la mousse.Sachant quemon talk, j'en ai fait deux avant.Le deuxième, il était sur...
01:21:35 :C'est pas du Club Django,c'était sur Wagtail.J'ai intégré un projet Wagtail sur un projet Django.Mais le premier,la première présentation,bon, j'étais un peu stressé, c'est la première.
01:21:47 :Mais ça se regarde, je pense.Ça parlait...Je parlais des...Je sais même pas s'il a été enregistré la première, d'ailleurs.De toutes les opérations crudes,en fait, avec les vues fondées sur les classes.
01:21:59 :Voilà.Il était bien le premier, hein.Mais ça s'entendait pas que tu stressais, hein.Bon, bah, merci.Je l'ai mêmeregardé la dernière fois, mais...
01:22:11 :Ah, bah, donc il y avait une relève.C'est bon.C'est de côté, là, mais...Ah.C'est bon.Merci.Ouais, bah, écoutez, on va...Je vais prévoir les premiers changements.
01:22:27 :Je verrai pour les prochains, du coup.Il y a tellement de choses à faire, à voir.Là, bah, je m'en parlais avec Thierry récemment.Là, je commence à créer mes décorateurs,mais on peut très bien créer ses médecines.
Aucune occurrence trouvée pour « ».