Session du 22 octobre 2024 à 21h00
Veille & Discussions
Deviens membre Premium magic_button
Cette session de mentorat est réservée aux membres Premium. Rejoignez-nous pour accéder à toutes les rediffusions des sessions de mentorat !
Premium
- check +100h de formations
- check +180 exercices de code
- check +100h de mentorats en rediffusion
- check 20 projets
- check Mentorats groupés hebdomadaires
- check Support individuel avec nos mentors
Session de mentorat "foire aux questions"
Poser toutes vos questions sur Python, ses finesses, sa bibliothèque standard, ses frameworks.
00:00:00 :Oui, normalement, tu peux partager ton écran sans problème, je pense. Le partage d'écran,c'est une petite flèche, un petit cadre rectangle avec une flèche à l'intérieur qui doit êtreprésentée maintenant, normalement, on t'autorise. Voilà, ça arrive.
00:00:45 :Bon, là, j'essaie de… Tu vois mon écran ?Oui, oui, je vois bien.Bon, là, j'ai juste créé un fichier, pareil, pour juste d'abord essayer. Je vais l'organiser en tant
00:01:09 :que librairie OFX. Mais là, j'étais au brouillon Test Connectivity. Si tu vois ici, là, par exemple,j'ai créé mon AMP. Là, c'est une requête que j'ai mise ici.
00:01:28 :Alors là, c'est peut-être quelque chose à… Il faudrait que je regarde une fois. Techniquement,ce sera pris comme une chaîne de caractère, tout ça.Oui, tout ça, oui.
00:01:40 :Donc, quand tu la récupères du côté de Python, que tu la…Ben là, je…Pour marquer comme du JSON, il faut que tu l'analyses avec quelque chose comme JSON.
00:01:51 :Effectivement. Je mets le load. Je récupère la clé-là. Est-ce qu'il y a le query ?Et là, je récupère la valeur exactement du complexe query qu'il y a là.
00:02:10 :Oui.Maintenant, là, j'ai mis mes connexions.Oui.Et là, si tu vois, je mets le cursor, j'exécute, je récupère le headers et le résultat.Oui.
00:02:32 :Maintenant, j'ai deux fonctions. Lui, par exemple, là, c'est le créer le Excel sheet.Oui.J'aime voir le résultat. Il me donne un fichier output Excel, un fichier.
00:02:48 :Bon, j'ai demandé un peu à Copilot de me générer un truc comme ça, donc…Oui, alors là, il génère un fichier Excel avec…Exactement, le contenu. Donc, il crée exactement le fichier. Il crée le fichier.
00:03:05 :Et je l'appelle, la fonction, ici, il appelle le fichier. Et là, à partir de ça, ici, j'envoie le mail.Donc, à quelques groupes de personnes, ici, que j'appelle la fonction dans le create Excel, là, Excel sheet.
00:03:26 :Voilà, je l'appelle, ici. Une fois que je… Une fois que, comment dirais-je, j'ai mon fichier, ici, là.J'appelle le fichier, ici, pour envoyer le mail.
00:03:44 :Bon, pour l'instant, ça marche. C'était juste d'abord tester tout le truc, le process brouillon, côté brouillon, passé.Je voulais m'assurer que ce que j'ai fait, c'est bon. Comme ça, maintenant, je vais l'organiser en tant qu'une librairie, en fait.
00:04:00 :Mais là, je n'ai rien composé sur ça. J'ai juste créé trois fichiers, settings, modèles, contrôleurs.Bon, j'essaye de me voir maintenant comment réorganiser tout ça, en fait.
00:04:15 :Faire ça en tant que, vraiment, une librairie qu'on exécute. Pas la mécanique, ici, comme ça, en fait.Oui. Alors, bon, là, déjà, tu peux réorganiser en deux sujets. Il y a tout d'abord tout le code qui s'exécute au niveau global de ton module.
00:04:35 :C'est essentiellement du code de connexion, par exemple, ici.Ce que tu peux éventuellement faire avec ce code de connexion, c'est que tu peux le déplacer, par exemple, dans un module,que tu peux appeler database.py ou quelque chose comme ça, ce qui va te permettre de te connecter à ta base de données
00:04:54 :et ensuite, éventuellement, la connexion à cette base de données, de l'obtenir par importe dans les autres fichiers, par exemple.Voilà. Exactement. Ok. Je peux créer un fichier uniquement.
00:05:09 :Ensuite, tu as tes fonctions. Les fonctions qui servent soit à générer le fichier Excel, soit à envoyer les e-mails.Voilà.Ça, tu peux les garder tels quels. Simplement, ça me fait un petit peu bizarre d'avoir des fonctions qui sont définies dans un bloc try-except.
00:05:30 :Moi, ce que je ferai, c'est que, en tout cas, la définition des fonctions, je le ferai en dehors du bloc try-except.Et de manière générale, ce n'est pas une super pratique de faire un try-except qui capture absolument tout.
00:06:05 :Ce qu'il faudrait à terme, si tu veux améliorer le programme, c'est d'identifier quelles sont les sources possibles d'arrêt,quelles sont les erreurs possibles au sein des différentes fonctions, et puis de gérer ces exceptions de manière individuelle.
00:06:24 :Par exemple, la fonction d'envoi d'e-mail, par exemple, ne va pas générer les mêmes exceptions.La fonction d'envoi d'e-mail ne va pas générer les mêmes exceptions que la fonction de génération d'un fichier Excel, par exemple.
00:06:49 :Et essayer de gérer ces exceptions de manière un peu plus granulaire et un peu plus spécifique.Le risque que tu auras, si tu fais comme ça, c'est-à-dire que si tu as tout ton code qui est encapsulé dans un immense try-except,c'est de faire qu'au final, tes erreurs peuvent être masquées.
00:07:23 :Effectivement.Dans ce cas-là, au moins, les erreurs ne sont pas invisibles, et puis ça peut éventuellement se justifier.Moi, ce que je fais souvent, c'est que j'utilise plutôt ça dans un contexte.
00:07:55 :Mais pour l'instant, en tout cas, les définitions de fonction, je ne les ferai pas dans ce bloc-là.Oui, je sais que je vais l'éliminer complètement. J'avais voulu mettre ça comme bon, je n'ai rien commencé. Je vais le mettre dans le contrôleur ici.
00:08:10 :Je vois que je n'ai pas besoin de modèle pratiquement parce que je peux récupérer les headers ici de la requête.Voilà, je peux récupérer les headers.
00:08:38 :Mais j'ai vu que je peux récupérer les headers ici directement.Donc, pratiquement, je n'ai pas besoin de modèle pour mapper aux headers.Et si tu penses maintenant, c'est tout ce qui est paramétrage, je vais penser à tout ce qui est base de données.
00:09:00 :Je ne sais pas, base de données, connexion de base de données et des trucs, peut-être username, mot de passe, tout ça.Déjà, au niveau des tests, je dirais que dans le premier temps, tu peux séparer plusieurs choses dans ton application.
00:09:20 :Tu peux séparer la partie de ton code qui se connecte à une base de données externe.Donc, tu connais la base de données d'entreprise dans laquelle tu travailles.
00:09:31 :Alors, ce type de test, tester la connexion.En fait, on peut tester le code de connexion, mais tester la connexion, ce n'est pas quelque chose qui dépend de nous.
00:09:44 :En fait, techniquement, cette connexion est indisponible, bien que notre code soit correct.Donc, en fait, tester une connexion, ce n'est pas idéal au niveau d'un test unitaire ou d'une dépendance externe.
00:10:09 :Donc, ici, on peut séparer ce côté connexion éventuellement du côté tester les deux fonctions.Et les deux fonctions que tu as actuellement, c'est-à-dire que tu as, alors pour les autres,Sylla nous présente son code et un code dans lequel il génère un fichier Excel à partir de données qu'il récupère en bas dans une base de données Oracle.
00:10:32 :Et ensuite, il envoie un rapport par e-mail à différentes personnes, des groupes de personnes.Donc, il y a deux fonctions pour ça.Et puis, là, il s'agit de la question de tester individuellement ces différentes fonctions.
00:10:49 :Donc, moi, déjà, je les testerai individuellement.C'est-à-dire que je créerai des tests qui vont tester spécifiquement CreateExcelSheet.Et je créerai d'autres tests qui vont tester individuellement SendEmailWithAttachment.
00:11:04 :OK ?D'accord.Et ce que je ferai également, c'est que j'essaierai de supprimer.Il y a des techniques dans les tests pour essayer de supprimer justement les dépendances externes.
00:11:17 :Par exemple, typiquement, c'est le cas dans SendEmail.Toi, tu veux tester en premier temps que ton code fait les choses correctes.C'est-à-dire qu'il envoie le bon texte aux bonnes adresses e-mail.
00:11:31 :Donc, ça, c'est la partie qui dépend de ton code.Donc, tu veux vérifier que ton code est correct de ce point de vue-là.Puis, il y a la partie qui dépasse les bornes de ton application, qui est que l'e-mail est bien envoyé.
00:11:44 :Ça, tu ne peux pas tellement tester.C'est nouveau, ça ne dépend pas de toi.Ça dépend du serveur SMTP, du fait que tu aies une bonne connexion, etc.
00:11:54 :Donc, c'est deux choses différentes.Donc, quand on parle de tests unitaires, souvent,et quand on parle de tester unitairement la fonction SendEmailWithAttachment,on parle vraiment ici de tester le code de cette fonction, la logique de cette fonction.
00:12:09 :Et puis, les bornes de ce test doivent s'arrêter aux bornes de cette fonction.C'est-à-dire que le monde extérieur ne nous intéresse pas.J'ai fait, il y a quelques semaines, ici, sur Doctrine FR, en Motorola, sur les mocs.
00:12:25 :Je pense que tu étais là, parce que j'ai souvenir que tu étais presque toujours là.Ouais, ouais.Sur les mocs.Donc, ça, c'est peut-être quelque chose qui peut t'aider à isoler les tests de la fonction, par exemple,SendEmailWithAttachment.
00:12:39 :L'idée, c'est qu'on veut, effectivement, faire croire qu'on envoie l'e-mail,mais plutôt que d'envoyer l'e-mail, on veut capturer les informations qui sont envoyéeset vérifier si c'est bien les informations envoyées.
00:12:53 :Et pour ça, les mocs peuvent t'aider.Donc, n'hésite pas à regarder ça et à poser des questions dans le channel Discord à ce sujet.Et il n'y a pas de travail à faire.
00:13:03 :Pareil pour la création du fichier Excel.On a deux possibilités.Soit on crée effectivement le fichier, mais dans un espace temporaire.Puis après, on va vérifier qu'il y a bien un fichier qui a été créé, qu'il a le nom désiréet éventuellement qu'il a le bon contenu.
00:13:20 :Donc, on peut faire ce genre de test.Ou alors, on peut simuler l'écriture du fichier, c'est-à-dire pas écrire le fichier sur le disque,mais vérifier ce qu'on aurait écrit dans le fichier, quel aurait été le nom du fichier, etc.
00:13:33 :Les deux stratégies sont viables du point de vue des tests unitaires ici.Donc, on peut avoir l'écriture sur disque ou éviter l'écriture sur disque.Donc, c'est moins critique d'utiliser les mocs pour l'écriture sur disque.
00:13:46 :Et là, Pytest, si tu utilises Pytest,Pytest a des outils pour te permettre d'écrire des fichiers dans un espace temporaireque les fichiers de test ne se retrouvent pas juste sur ton disque comme ça.
00:13:58 :Et puis, quand tu lances les tests,tu te retrouves avec plein de fichiers qui ont été générés pour ça,mais qu'à la fin des tests, ces fichiers soient automatiquement éliminés.
00:14:08 :Donc là, il y a des stratégies pour ça.D'accord.C'est probablement que c'est un petit peu trop avancé à ce niveau-làpour écrire les tests ensemble ce soir.
00:14:17 :Mais n'hésite pas à essayer d'écrire quelques tests.Et puis, par exemple, la semaine prochaine,de revenir avec quelques essais par rapport à ces tests-là.Des tests ciblés sur tes fonctions.
00:14:30 :C'est-à-dire qu'en test, tu dois tester une fonction.D'accord.En fait, chacune de tes deux fonctions peut être testée par plusieurs testsqui vont tester différents aspects du fonctionnement de cette fonction.
00:14:42 :Mais en test, tu ne devrais pas toucher normalement à plus qu'une fonction ou une méthodede telle manière à ce que tu n'aies pas des tests qui iraient dans tous les sens.
00:14:52 :Et dans un tout premier temps,essaye de tester le comportement de ton codeet de bien borner ces tests pour qu'ils s'arrêtent à ton code.
00:15:01 :Ne pas tester des dépendances externes,des envois sur des serveurs externes, des requêtes sur des serveurs externes, etc.Parce que ça, c'est quelque chose qui ne dépend pas de toi.
00:15:12 :Oui, oui. Effectivement.Il n'y a pas de souci.Donc, je vais bien réorganiser ça et mettre le test dans l'librairie.Parce que ce que je veux même, au fait,pour lancer l'application, je voudrais créer le main ici dans l'librairie,un dash dash main.
00:15:32 :Comme ça, quand tu mets Python, tu mets le main.Du coup, il lance directement le programme que je vais importer.Peut-être le contrôleur et un truc comme ça.
00:15:43 :Je pense que tu nous avais envoyé même un truc sur le MVC.J'avais vu ça là-bas.Tu avais envoyé un exemple.Après, un petit conseil sur le nommage des choses dans le code, par exemple.
00:16:18 :Typiquement, ce que tu appelles librairie, au sens de Python,c'est ce qu'on appelle un package, un répertoire qui possède à l'intérieur de luiun fichier init.py.
00:16:30 :Donc ça, c'est un package.Techniquement, potentiellement, une bibliothèque, donc une librairie,c'est quelque chose que tu peux avoir dans plein de projets différents.Donc, ce que je te recommande, c'est plutôt de donner un nom qui est spécifique à ton projet.
00:16:47 :Pour éviter que sur trois projets différents, tu aies un répertoire librairie.Si tu te retrouves un jour à devoir réutiliser une partie de ton codedans deux projets différents, qui les deux ont du coup un packagequi s'appellerait librairie, tu as plus de risque de collision.
00:17:06 :C'est-à-dire que si tu te trouves un nom spécifique à ton projet,pour ton projet, ce sera aussi avantageux également.Si un jour, tu considères que c'est super intéressant et que tu veux l'isoler,par exemple en faire un paquet qui est éventuellement installable séparémentpour l'utiliser dans plusieurs de tes projets,
00:17:25 :si tu arrives dans un projet qui a déjà un module ou un paquetqui s'appellerait librairie, tu risques d'être coincé.Donc essaye de trouver un nom qui est plus spécifique.
00:17:35 :D'accord, ça marche.C'est pas de souci.N'hésite pas de l'utiliser un petit peu comme fil rouge.La semaine prochaine, on a des montaures une fois par semainesur The String FR, donc n'hésite pas à revenir la semaine prochaineavec ton code et on en discute un moment.
00:17:56 :Ça marche, il n'y a pas de problème.Là, je vais laisser aussi un espace pour les autresparce qu'on n'a qu'une demi-heure environ.N'hésite pas aussi à poser des questions sur ton projetdirectement sur le Discord et à me taguer comme ça.
00:18:11 :Je vois.Il n'y a pas de problème.Et si tu vois aussi, par exemple, le env là,ce que je voulais maintenant, en fait, mon objectif c'est quoi ?
00:18:25 :Là, c'est un dictionnaire.Donc je voudrais, là c'est la première requête.Je voulais, par exemple, la deuxième requête.Là, je voulais mettre comme ça.Je mets, par exemple, là c'est Compress Query 1et je mets Compress Query 2.
00:18:51 :Donc du coup, dans SQL Query, il y aura un dictionnaireet je vais parcourir ce dictionnaire pour prendre toutes les requêtes.Donc du coup, s'il y a une nouvelle requête,je n'ai pas besoin de répandre le code,j'ai juste besoin de venir le formater ici, le mettre.
00:19:05 :Donc du coup, il sera pris, exécuté et envoyé en même tempssans répandre aucun code.Le désavantage de le faire comme ça,c'est qu'actuellement tu utilises un fichier .env
00:19:17 :pour charger ta requête.Tu es donc soumis aux contraintes des fichiers .env ici.C'est sur une ligne d'avoir le SQL Query égalet puis ta requête, qui peut être très longue pour le coupparce que tu peux avoir une complexe requête,Compress Query 1, puis Compress Query 2et là on voit ton dictionnaire, il est sur une ligne.
00:19:41 :Ce qui peut devenir un petit peu difficile à maintenir.La question peut être, à un moment donné,est-ce que tu tiens réellement à ce que ce soit un fichier .env
00:19:51 :qui lise ça ?Parce que de toute manière, tu as un fichier .env.Tu le lis avec Python.env.Tu récupères une chaîne de çaet cette chaîne-là, tu la lis ensuiteavec json.loads.
00:20:09 :Est-ce que tu n'as pas avantage,maintenant c'est une question,à enregistrer cette requête plutôt dans un fichier json directementet tu lis directement ce fichier avec json.loads
00:20:26 :et l'avantage de ça,ce sera que tu pourras formater déjà ton SQL Query.Tu pourras le formater, ce dictionnaire,sur plusieurs lignes.Et donc, tu as les Complexes Query 1, Complexe Query 2,ça deviendra beaucoup plus simpleà formater et à lire que tu auras,je ne sais pas combien tu es censé avoir de Complexes Query.
00:20:55 :Il pourrait y avoir beaucoupet que chacun de ces Selects peut éventuellementavoir certains avantages à être exprimés en plusieurs lignes.Alors pour exprimer un Select en plusieurs lignes,on pourrait imaginer que ces Selects soient dans une liste,dans du json,une liste qui contiendrait plusieurs chaînes,une chaîne par ligne et puis avec un Join côté Python.
00:21:20 :Tu fais un Join pour reconstruire ta requêteet ensuite tu as des possibilités ici dans le fichier jsond'exprimer tes requêtesde manière finalement assez complètesur plusieurs lignes.
00:21:40 :Une autre possibilité,ce serait d'avoir un répertoire Requestou le Request.C'est un exemple.Tu pourrais imaginer avoir des fichiers à l'intérieuren format .sql par exemple.
00:21:58 :Et puis dans chaque un de ces fichiers,tu as une requête complexe.Et ce que tu fais,plutôt que d'avoir un truc avec toutes les requêtes complexes,tu fais une liste de ces fichiers dans le répertoireet tu vas lire chaque un de ces fichiers de manière séquentielle.
00:22:16 :Donc tu vas charger du coup le textecorrespondant à chaque requête SQLet tu vas envoyer ces requêtes SQL tour à tour au serveur.De nouveau, quel est l'avantage ?
00:22:28 :L'avantage est peut-être la lisibilité.Nous pensons toujours que toi,si tu fais ça, c'est pour te faciliter la vie.Donc actuellement, je vois ta requête là sur une lignequi fait 3 kmet que tu m'expliques que peut-êtretu auras plusieurs complexes queryqui seront toutes sur la même ligne.
00:22:48 :Je suis en train de me poser la questionest-ce que réellement ça te fait gagner du temps ?Donc pense à l'interface dont tu as besoinet ça c'est valable pour tous les autres.
00:23:01 :Quand vous cherchez un petit peuquelle est la bonne façon d'interagir avec l'utilisateur,alors l'utilisateur ici c'est Sylla directementqui a son programme qui va lire des requêtes SQLpour les envoyer à une base de données.
00:23:14 :Il faut se demander quel est le format le plus pratique,le plus visible, le plus facile à maintenirpour que l'utilisateur introduise l'information qui l'intéresseet puis ensuite se poser la même questionpour le retour d'informations,sous quelle forme je dois lui retourner l'informationpour que ce soit le plus proche de ce qu'il demande,
00:23:32 :le plus facile ensuite à analyser.Alors pour le coup là,on est sur l'introduction d'informationset comme ça c'est subjectif,mais je n'ai pas le sentiment que d'avoir toute ta requêtesur une ligne dans un fichier .ham
00:23:46 :soit la bonne interface pour te faciliter la vie.Si c'était moi qui devais remplir ton fichier .hamavec des requêtes,je pense que j'aurais déjà juré une bonne dizaine de foisen me rendant faire et puis j'aurais eu l'impressionque j'avais avantage à le faire directement dans un client Oracle
00:24:11 :et puis le faire à la mainparce que finalement si tu essaies d'automatiser tout ça,c'est pour gagner du temps.Et si ça te prend plus de temps d'entrer ta requêtedans ton fichier .ham
00:24:21 :que de balancer la requête dans un client Oracle,tu n'as rien gagné.Je suis d'accord.Faut peut-être réfléchir à ça, l'ergonomie du programme.Oui, je pense que c'est mieux de créer le fichier SQL,comme tu l'as dit.
00:24:38 :Tu as déjà créé un fichier.Bon.New file.Je mets, par exemple.Je te laisserai le faire hors mentorat parce que.D'accord, ça marche.Il y a trois personnes qui nous ont rejointset puis ils ont peut-être aussi des questions.
00:24:58 :Je vais essayer de répéter.Je te reviens avec ça la semaine prochaine.On revient, il n'y a pas de problème.Et puis n'hésite pas à poser des questions aussi hors mentorat,sur le Discord.
00:25:11 :Il n'y a pas de problème.Voilà.Donc bonjour à ceux qui sont arrivés en cours de route.Bonjour.Oui, on est arrivés un peu en retardparce qu'il y a eu un problème en fait avec le liensur le site d'UpString.
00:25:25 :Il n'y avait pas le lien du mentorat en fait.Ça nous renvoyait vers Discordsur une page qui n'existait pas sur Discord,mais il n'y avait pas de lien de mentorat.
00:25:35 :OK.Alors il faut que je regarde ça.Et finalement.Donc c'est Gabriel qui nous a sauvés.J'ai envoyé des bouteilles à la mer à Thibault,à Gabriel, à notre mentor.
00:25:46 :Et du coup, c'est Gabriel qui nous a envoyé le lien du Google Meet.Du coup, je me demandais comment Sylla avait fait pour se connecter.
00:25:57 :Moi, j'ai utilisé l'application.J'ai utilisé UpString.J'ai planifié.J'ai su aller dans UpString.J'ai fait un Google Meet.Mais j'ai l'impression que c'était...On pouvait avoir le lien directementsi on y allait avant 9 heures.
00:26:14 :Et puis que si on avait dépassé d'une minute,il a dit...Après, je ne sais pas ce qui...Apparemment, par erreur.Alors c'est donc une erreur.
00:26:23 :J'ai mis tous les screenshots dans Discordpour aller voir.Mais je me suis connecté avant 9 heureset après 9 heures, c'était la même chose.
00:26:34 :OK. Alors, moi, je vais aller regarder.Et surtout, essayer de...Alors, premièrement...Mais tout va bien puisqu'on est là.Si il y a une erreur, c'est qu'elle vient de moi.
00:26:43 :Et puis, je vais déjà vérifierque je n'ai pas fait la même erreur pour les semaines à venir.En tout cas, merci de me l'avoir reporté.
00:26:51 :Donc, n'hésitez pas.Si vous avez posé des questions,c'est une session plutôt foire aux questions.Vous avez compris qu'avec Sylla,on a passé un petit peu de temps sur son programme.
00:27:03 :De votre côté, vous avez aussi des questions.C'est ouvert.Moi, je veux bien...Alors, j'ai commencé à poser ma questionsur le Discord ce matinet tu m'as envoyé une réponseavec les vidéos de Daniel Roy-Greenfeldpour comment créer des...
00:27:24 :Plusieurs profils.Enfin, quelle est la meilleure approchepour créer des profils d'utilisateurs différentspour utiliser l'application.Et donc, dans la vidéo,alors que je n'ai pas encore eu le temps de regarder en entier,mais j'ai compris qu'il suggérait d'utiliser des proxy-models.
00:27:41 :Alors, les proxy-models,c'est le point de détail là-dedans.Mais c'est un point de détailqui peut amener plus d'ergonomie.Je dirais, sur le principe,c'est surtout le fait d'avoirun seul modèle utilisateurpour tous les utilisateurs.
00:28:02 :Donc, toute entité utilisateurqui doit se connecter à ton applicationaura un seul modèle utilisateur.Ça, c'est toujours vrai,même si j'ai plusieurs profils d'utilisateurs.
00:28:13 :Et ensuite, je créedifférents profils d'utilisateurs,donc différents modèles séparéspour mes utilisateurs.Et chacun de ces modèles,on a deux possibilités de le faire.
00:28:26 :Mais la partie qui nous donne le plus de contrôle,c'est souvent de mettre une relationone-to-one entre cet utilisateur-làet le user.Donc, chaque useraura un profil d'utilisateurqui va pointer sur lui.
00:28:43 :Et ce profil d'utilisateur seraun des types d'utilisateurs que tu as.Et pour le coup,l'information qui est spécifiqueà chaque utilisateurva aller dans ce modèle de profil.
00:28:57 :Et l'information qui est communeà tous les utilisateurs,et surtout l'information de connexion,le mot de passe, etc.,va dans le modèle user.Et donc, ce modèle est doncune façon de faire à deux modèlesqui est vraiment le plus classiqueque tu as pour plusieurs utilisateurs.
00:29:15 :Et effectivement,Daniel Greenfield fait ici,en plus,mais une couche avec des modèles proxypour rendre la choseun petit peu plus transparentequand tu codeset un petit peu plus ergonomiquepour manipuler ce duo.
00:29:32 :Et également,on a des possibilités de faireavec les signaux en Django,par exemple,pour faire que lorsque tu créesun profil utilisateur,par exemple,j'imagine que j'ai un profil,je suis sur une applicationde e-learninget puis j'ai un profil étudiant,un profil enseignant,par exemple,je ne sais pas.
00:29:51 :C'est ce genre de choses.Donc, je peux faire en sorteque lorsque je crée un étudiant,j'ai automatiquement créationdu user correspondant.Donc, ça,je le gère généralementavec les signaux Django,c'est-à-dire qu'il y a un typedes signaux, si tu veux,c'est vraiment quelque chosequi permet de réagir
00:30:14 :à des actions,une sorte de système de plug-inqui permet de réagirà des actions au sein de Django.Et il y a un signalqui s'appelle post-saveet qui permet, par exemple,chaque fois que je sauveun utilisateurou que je crée un utilisateur,j'ai des possibilitésde créer un autre modèle.
00:30:34 :Par exemple,chaque fois que je crée un étudiant,je veux créer le modèled'utilisateur qui va avecet puis les deux,je vais les vier.
00:30:42 :Et via la relation,le one-to-one fieldqu'on a entre ces deux modèles,on a égalementun autre champqui s'appelle onDeletequi permet de fairela relation inverse.
00:30:56 :Ce onDelete,si on utilise la valeuronDelete égale Models.Cascades,on a la possibilité de faireque quand j'effaceun utilisateur,du coup,l'étudiant correspondantou l'enseignant correspondantsera effacé.
00:31:13 :Comme ça,on a un système à deux modèlespour représenter ces utilisateurs.En modèle userplus en modèle de profil spécifiqueet on a la possibilitéd'automatiser le cycle de viede ces deux modèlespour que quand j'effaceun utilisateur,le profil qui va avec s'effaceet lorsque je supprime
00:31:32 :ou lorsque je créeun utilisateur,c'est le modèle userqui va avec,qui s'efface.D'accord.Juste si je reformulepour voir si j'ai bien compris.
00:31:42 :Si par exemple,j'ai trois profils,moi dans mon modèle de données,il faut que je créequatre modèles,un modèle pour chaque profilplus un modèle userqui fera une relationone-to-one avec...
00:31:52 :Oui, c'est ça.Comment ce modèle user ?Ça peut être le modèle userpar défaut de Django,mais a priori,il n'est pas forcément recommandéde travailler directementavec le modèle user par défaut.
00:32:05 :Donc effectivement,ça va nous faire créerune sorte de...On va hériter d'abstract userou d'abstract based useret on va créer notre propre user.
00:32:13 :Puis effectivement,tu vas créer trois profilsd'utilisateurs,donc trois modèles séparés.Et ces trois modèles séparésauront les donnéesqui leur sont spécifiques.D'accord.Donc dans mon modèle user,je mets un champ profil,par exemple,qui a une relation one-to-oneet qui renvoie vers les trois profils.
00:32:36 :C'est ça ?C'est ça.Ok, super.C'est très clair.Merci beaucoup.Et comme ça,ça te permet de faireque ces trois utilisateurs différents,du fait qu'ils partagent tousle modèle user,ils sont directement ancrésdans le système de permissionet de login de Djangovia leur modèle commun,
00:32:58 :le modèle user.Et puis sinon,comme n'importe quel autre modèle,après,ils portent des informationsqui leur sont propres.Alors typiquement,sur un utilisateur,le username ou l'email,c'est des données plutôt de connexionet ça va allerdans le modèle user personnalisé.
00:33:15 :Tandis que des informationsplus spécifiques,alors si je suis prof,ça va être les matièresque j'enseigne.Si je suis étudiant,ça va être les cours que je suis.
00:33:24 :Ce sont des chosesde nature différentequi vont aller dans les profils.OK.Et la relation one-to-one,on la définit biendans le modèle user,pas dans les profils ?
00:33:36 :Non,dans les profils.Le mieux,c'est dans les profilsparce que le modèle,ça permet de ne pas...Sinon,on devrait avoirtrois relations dans user.
00:33:50 :Moi,je préfère généralementavoir une relationdans chaque modèle de profil.C'est généralement plus clair.Et également,l'avantage,si tu prends l'habitudede créer ta relationdans les modèles de profil,ça fonctionne aussisi tu utilisesle user par défaut de Django.
00:34:06 :C'est-à-dire que,dans ce cas-là,tu n'as pas accèsà la modification du modèle user.Mais même si je n'ai pas accèsà la modification du modèle user,je peux faire pointertrois modèles de profilsur ce modèle user par défaut.
00:34:20 :Donc même dans ce cas-là,ça fonctionne.Trop bien.Merci beaucoup.Bien compris.Je crois qu'il y a Jean-Baptistequi a plein de questions.Il ne faut pas qu'il hésite.
00:34:33 :Je crois que c'est Jean-Christophe.Oui, bonsoir.M'entendez-vous correctement ?Oui.Merci.On avait parlé des logs ensembleil y a quelques temps.J'ai travaillé sur le sujet.
00:34:48 :Donc, je me suis fait un module,un package app underscore config.Et dans son init,je définis, on va dire,le format des logs,le nom du fichier,des choses comme ça.
00:35:04 :J'ai un petit souci,c'est que dans le format,j'utilise pour son nameet pour son function,function name en fait,le function name,dans le but de tracerqui est l'émetteur du log.
00:35:23 :Je m'aperçois qu'en fait,quand j'ai un log émanant d'un module,ça fonctionne bien,mais quand je reviens dans le mainet que je continue à tracer dans le main,je suis obligé d'utiliserun petit superfugequi consiste à direunderscore config.logger.name
00:35:53 :est égal à underscore underscore nameunderscore underscore.Du coup, je suis obligéd'actualiser manuellementla source en fait.Est-ce qu'éventuellement,tu as un moyen de partagerjuste l'écran pour vous ?
00:36:12 :Je ne sais pas si tu l'as devant toi ou pas.Si tu l'as devant toi,c'est plus facile.Oui, bien sûr.Techniquement,dès qu'on est dans le main,je suis en train de voir,excusez-moi,pour partager l'écran,je ne suis pas habitué à cette interface.
00:36:32 :Ici, il y a une sorte de rectangleou de télé avec une flèche vers le haut.D'accord, oui.Quand on clique dessus,on a la possibilité de choisirsoit l'écran complet,soit une fenêtre en particulier,soit même un onglet de chrome.
00:36:50 :Voilà.Est-ce que vous voyez mon deuxième écran ?Oui, c'est en train d'arriver.Oui, c'est bon.D'accord.Donc, la structure,si on regarde dans mon navigateur de fichiers à gauche,ici, j'ai donc l'APP Config avec son limite.
00:37:09 :Et donc, son limite est ici,complètement à droite.Et dedans, en fait,pour configurer mon logger,j'utilise le %m ici.Seulement, je me suis aperçu quesi je ne fais pas cette petite pirouette ici,en fait, quand je reviens dans le main,là, je suis dans le main, ici.
00:37:38 :Ça, c'est le main.Si je ne mets pas ça,en fait, il va garder le nom du dernier module appelé.C'est ce que je comprends.
00:37:49 :Alors, j'ai dû certainement faire quelque chose de pas correct.Alors, ici, si je regarde,c'est que tu donnes le name,donc le underscore underscore name underscore underscoreà appconfig.logger.
00:38:05 :Ça veut dire qu'ici,comme on a la condition de la ligne 20,c'est-à-dire que de facto,on va donner,tous les modules vont avoir de ce logger-là,vont avoir ce nom-là.
00:38:19 :En fait, ici,toi, ce que tu fais,c'est que tu utilises le même logger partout,c'est ça ?Oui.Pour l'instant, oui,parce que j'apprends la techniqueet après, éventuellement,je pourrais faire autrement,mais bon.
00:38:35 :En fait, c'est juste le point bloquant,il est là, en fait,c'est-à-dire qu'ici,j'ai un module qui est ici,userkeyboard,qui va étudier, entre guillemets,est-ce que ma saisie est bien en entier ?
00:38:53 :Si ce n'est pas en entier,ça va boucler, etc.Donc, voilà,je vais avoir une petite gestion d'erreuret une petite gestion de logging.Et c'est surtout celui-là, en fait,ici, que je suis obligé de dire,ça y est,tu n'es plus dans ce module-là,tu es revenu dans le main.
00:39:14 :Alors, est-ce que je peux afficher des logs ?On va regarder.Les logs, ils sont là.Voilà, donc on voit, par exemple,ici, si je fais un petit peu plus large,je crois que là, à mon avis,il ne fait pas ce que tu penses.
00:39:36 :C'est-à-dire que, finalement,la ligne 27, ici,fait exactement la même chose.Ah oui, je comprends.Parce qu'en fait,dans la fonction testUserInput,tu fais exactement la même chose,mais dans un autre module.
00:39:50 :Et chaque fois, du coup,ça te modifie le name de ton app.config.Et c'est le problème, c'est qu'en fait,tu ne partages qu'un seul loggeurpour toute l'application.
00:40:03 :En général, ce qu'on fait,c'est qu'on fait une config par défautet ensuite, on définit un loggeur par fichier.Et justement, logging basic config,ça définit la config de la bibliothèque logging,si tu veux.
00:40:26 :Mais par contre, ensuite,dans chaque fichier,tu vas refaire un logging.getLoggerdans chaque fichier.La ligne 7 de ton init, là,c'est là que tu vas, en principe,la faire dans chaque fichier.
00:40:41 :C'est-à-dire que les différents modulesne vont pas partager le même loggeur.Et chaque loggeur va avoir sa propre année.Tandis qu'actuellement, comme tu partages,là, tu importes ce loggeuret tu réutilises le même loggeur partout,le problème, du coup,c'est que tu dois chaque fois mettre à jour,tu dois changer son nom.
00:41:01 :Mais si, du coup,on a une autre approche, en général,c'est qu'on crée un loggeur par fichieret donc, du coup,chaque loggeur a son propre nom.
00:41:08 :Et comme ça, il n'y a pas de contamination,c'est-à-dire que tout ce qui est écritpar le loggeur du fichier user,keyboard ou terminal, par exemple,ça va être logué comme faisant partiedu module terminal,tandis que ce qui est écrit dans le mailva être logué comme faisant partie du mail.
00:41:26 :Donc, c'est à ce niveau-là que ça se joue.Ce que je vais faire,parce que j'ai...Parmi mes étudiants, en général,les gens sous-utilisent login.
00:41:38 :Ce que je vais faire,je vais faire comme j'avais faitil y a plusieurs semainesavec l'exemple du modèle du contrôleur.Je vais juste faire un petit projet multifichier,mais vraiment tout petit,dans lequel je vais configurer logindans un module de configurationjuste pour te montrer comment on le fait
00:42:01 :dans deux fichiers.Comme ça, tu as un petit module pour le faire.Je vois le principe,mais alors, du coup,je perds la chronologie de la séquencede ce qui s'est déroulé, en fait,si j'ai deux fichiers.
00:42:14 :Alors, il y a une technique que je ne connais pas.C'est possible.Alors, non, tu ne devrais pas perdre la séquenceparce que finalement,chaque enregistrement dans ton fichier de logva être complètement synchrone.
00:42:29 :Donc, chaque inscription va être faiteau moment où l'instruction de log est appelée.Simplement, tous vont écrire dans le même fichier.Tous les loggers vont écrire dans le même fichier.
00:42:43 :Simplement, les inscriptions dans ce fichierauront les noms qui correspondent aux fichiersdepuis lesquels ont été faites les inscriptions.Ah, d'accord.Oui, je vois.Donc, c'est le...
00:42:56 :C'est-à-dire qu'on l'écrit centralementpour que tout se fasse en écrituredans le même fichier,mais que des loggers avec des propriétés différentespuissent écrire dans ce fichier-là.
00:43:08 :Donc, on a une configuration centralisée.Par contre, les loggers sont instanciés et créésdans chaque module.D'accord.Parfait.Et puis, viens...Je suis l'entraîneur, vraiment.
00:43:24 :Je vais essayer de clarifier ça.Ça permettra de voir comment organiser son loginsur plusieurs fichiers dans le cas de cet exemple.Ce sera probablement deux ou trois fichiers.
00:43:34 :D'accord.Petit commentaire, peut-être également.Dans AppConfig, par exemple,je ne sais pas si tu as prévu d'avoir d'autres modulesdans ce AppConfig que le init.
00:43:48 :Je dirais que je ne vois pas de plus-valueà créer un répertoire avec juste le initdans lequel on met un script d'initialisation.Si c'est juste pour la config,tu peux aussi créer un modulequi s'appelle AppConfig.py, par exemple.
00:44:05 :Ce sera le même résultat,mais à mon avis plus conforme à l'esprit de Python.C'est-à-dire qu'on commence à créer un paquet, un package,à partir du moment où on commence à devoir le découperen plusieurs modules.
00:44:19 :Mais si ici, je n'ai que le init à l'intérieur d'un package,ce que je ferai, c'est que j'appellerai AppConfig.py,la racine de mon projet ici,et je le transformerai en un répertoireavec un init à l'intérieur,que si je prévois ou si je ressens le besoin,en cours de route même,
00:44:39 :d'y ajouter d'autres clichés, d'autres configurations.Par exemple, on peut imaginer que dans ce AppConfig,on ait plusieurs modules de configurationqui concernent plusieurs aspects de l'application.
00:44:51 :Alors à ce moment-là, ça fait du sensd'avoir un répertoire AppConfig avec plusieurs modules à l'intérieur.Mais si tu n'as que le init,moi je simplifierai et je mettrai AppConfig ou Config.py.
00:45:02 :Oui, je comprends.C'est un peu surdimensionné pour l'usage que j'en fais.Voilà, toujours se dire, à partir du momentoù mon code évolueet ce module Pythoncommence à devenir gros,donc je vais le découper en plusieurs modulesque je vais mettre dans un répertoire.
00:45:23 :Et à ce moment-là, je crée un paquetqui aura plusieurs de ces modules.Et ça, je peux vraiment le faire dynamiquementau fur et à mesure que je développe.
00:45:33 :C'est-à-dire que, bien sûr, je pourrais faire la conception de tout,mais je pourrais me dire, j'en fais un paquet là,parce que je pense que plus tard,j'aurai besoin de plusieurs fichiers de configuration.
00:45:43 :Mais tant que tu n'as pas cette...Tu as avantage à d'abord faire le plus simple possibleau niveau de cette configuration, donc en module.Et puis, quand il y a le besoin de se dire,je vais transformer ça en un répertoire avec plusieurs modules à l'intérieur,parce que peut-être que le besoin ne se fait jamais sentir,
00:45:59 :et puis après, je dois plutôt faire un refactoring inverseet puis dire là, ce init tout seul,ça fait un petit peu chenille, comme on dit en Suisse,et puis du coup, je vais en refaire un module.
00:46:12 :D'accord.Oui, c'est plus stylé.C'est plus stylé.Tu peux remplacer ton init.py par un app.config.pyet puis éliminer le répertoire app.config.C'est plus simple.Les imports sont les mêmes.
00:46:30 :Tu fais dans les deux cas un front map config import quelque choseou un importable config.Au niveau des imports, c'est la même chose.Donc tu vois que finalement, on peut transformer un module en un paquetsans modifier les imports assez facilement.
00:46:45 :Et moi, de mon côté, je te fais un petit exemple,trois, quatre fichiers qui te montrent comment organiser ça.D'accord.Par contre, je n'arriverai pas à le faire avant demain après-midi.
00:46:56 :Ah oui, non, mais pas de souci.Il n'y avait pas d'urgence.Je déroule les exercices prévus dans le programme Tozaet j'essaye volontairement d'appliquer,de travailler sur les modules, les logs, des choses comme ça.
00:47:16 :Aussi, il y a une personne qui s'appelle Rachid, je crois,de mémoire qui avait fait un exposé sur le TDD.Donc j'ai fait un exercice carrément en TDD.
00:47:27 :Donc j'essaye de mettre en application ce qu'on voit ensemble le soir.Du coup, ça m'oblige à me poser des questionset à avancer dans la méthodologie.
00:47:41 :Alors justement, j'enchaîne sur ma deuxième questionparce qu'il paraît farflu.J'ai voulu faire un bar graph comme on voit en bas.Dunlady, c'est le jeu de rôle du programme Toza.
00:47:55 :Je me suis dit qu'on allait essayer de faire un truc chaud.Et donc, au travers de ça, je rencontre un problème de compréhension de ma part.
00:48:05 :C'est-à-dire que pour faire le petit bar graph,là j'utilise Colorama,que j'ai décidé, là encore une fois,de faire un app output pour dire,voilà ma sortie écran, je vais gérer par exemple mon terminal.
00:48:23 :Et donc j'ai mon fichier terminal qui est iciet la définition de mon bar graph qui est ici.Donc dedans, je pince la valeur, le minimaxiet ma couleur de fond provenant de Colorama.
00:48:40 :Sauf que ce module, moi je souhaite qu'il soit complètement autonome.Donc il a son import Colorama en haut de ce que j'ai besoin.D'ailleurs, là que je n'en ai pas besoin, je pourrais le supprimer,ce qui me ferait un warning de bas.
00:48:54 :Voilà, ça y est, je n'ai plus de warning.Mais ici, à l'appel de la fonction bar graph qui est ici,je renseigne bien tous les éléments.
00:49:05 :J'ai besoin de lui dire, je voudrais l'arrière-plan,le background color en vert et le background color en rouge,selon si c'est moi qui joue ou si c'est le robot qui joue contre moi.
00:49:20 :Et du coup, je me retrouve, j'ai un import de Colorama normal dans mon module,ça c'est normal, mais pour accéder à la constante,je suis aussi obligé de le faire dans mon main.
00:49:35 :Et ça, ça me dérangeait.Donc il y a quelque chose que je ne maîtrise pas.Je ne veux pas faire cet import-là.Je veux que ce module-là soit indépendant.
00:49:43 :Mais comment faire pour lui passer cette constante qui est liée à Colorama ?Tu veux que le terminal soit complètement indépendant,enfin que le terminal.py soit indépendant ?
00:49:59 :Oui, oui, parce que là...Oui, soit indépendant de Colorama.Mais ici...Que le main soit indépendant, effectivement.C'est-à-dire que dans mon main,j'accepte entre guillemets de faire mon import de paragraphes ici.
00:50:17 :Ok, en fait, il n'y a rien qui t'oblige...Je ne veux pas faire ça.Il n'y a rien qui t'oblige techniquement à exposer au mainle fait que tu utilises Colorama.
00:50:29 :C'est-à-dire qu'ici, tu as spécifié dans ton mainles variables back Colorama, back point quelque chose.Oui, oui, pardon.Mais rien ne t'empêche de garder ça à l'intérieur du terminal.py
00:50:48 :et de toi, dans ta fonction, tu vas définir...Alors déjà, tu peux très bien appeler ça bgColoret pas Colorama.bgColoret tu crées une sorte de dictionnaire.
00:51:01 :Une sorte de dictionnaire de conversion.C'est que green deviendra back green, par exemple.Ah, d'accord.C'est une constante de Colorama et sans aucun lien...Enfin, de mon paragraphe, mais sans aucun lien avec Colorama dans mon main.
00:51:16 :C'est que dans ton main, tu vas juste passer la chaîne de caractère greenet dans ta fonction elle-même qui est dans le module terminal.py,tu vas aller chercher, peut-être dans le dictionnaire colors,quelque part dans ton module colors,où green est renvoyé sur back point green.
00:51:37 :Et pour le coup, comme ça, tu récupères la vraie variable Coloramapour faire ce changement de couleur.Mais c'est ce qu'on appelle de créer une barrière d'abstraction,une couche d'abstraction ici,de faire que, en fait, pour le code appelant, le code utilisateur,donc ici ton main,c'est pas important pour lui de savoir que tu utilises Colorama en back end derrière,
00:52:02 :mais...Oui, justement, je veux pas.Moins tu l'exposes, ça, plus ça te permettra, par exemple,s'il y a besoin de plus utiliser Colorama,mais peut-être d'utiliser une autre bibliothèque qui fait la même chose,à un moment donné.
00:52:17 :C'est ça, donc moins tu dissémines cette information.Donc pour moi, ce que je ferais,c'est que soit tu définis tes propres constantes,donc terminal, tu peux définir des propres constantes,soit tu définis ton terminal en dictionnaire privé,qui doit pas être apporté ailleurs,mais qui va faire le lien entre des chaînes de caractère.
00:52:38 :Je prends l'exemple de la couleur green,qui va être mis en correspondance avec la constante Colorama back point green.Et toi, quand ta fonction bar graphvoit qu'il y a du coup Colorama bgColor qui viendrait bgColor égale green,dans ce cas-là, tu vas prendre green,tu vas aller récupérer back green,
00:53:05 :et puis tu utilises back green, etc.Bien sûr, ça complique très légèrement,ça crée une traduction via un dictionnaire.Oui, c'est ça, une table de correspondance en fait.
00:53:20 :Une table de correspondance,finalement, ça crée pas énormément de codes en surcouche,mais ça permet au moins de cacher les choses.Et puis si demain tu utilises la bibliothèque X,dans ce cas-là, la couleur green sera mappée sur une autre constante,ou alors ce sera fait différemment.
00:53:40 :Donc tu caches finalement les détails d'implémentation au sein de Terminal.py.Oui, d'accord. J'avais bien pensé à ça,mais je voulais m'éviter de faire cette table de correspondance,mais finalement c'est le meilleur choix si je veux vraiment aucun lien en fait.
00:53:58 :Ok, parfait, merci.On n'a pas tellement le choix,parce que le lien, on est quand même obligé de le faire à un moment donné,mais si on le cache, ça n'empêche pas qu'on doit le faire sous le capot,pour que ça fonctionne si on utilise Codorama.
00:54:13 :Oui, d'accord.Donc dans l'absolu, ici, je referai ici des constantes en fait ?Soit des constantes, soit un dictionnaire de conversion,chaîne de caractère vers une constante.
00:54:31 :Ah oui, directement.Il y a les deux possibilités.L'avantage d'utiliser des chaînes de caractère,alors l'avantage c'est que le mail n'a rien à apporter,il peut directement écrire green souvent de chaîne de caractère.
00:54:45 :Le désavantage, c'est que s'il fait une faute d'orthographe,sur green il y a peu de chances,mais encore sur green on pourrait faire une faute si on n'est pas anglophone.
00:54:59 :Si on fait une faute, il n'y a rien qui pourra le capturer.Si on utilise des constantes,l'éditeur pourra nous aider si on utilise une constantequ'on n'a pas pu importer ou qui n'existe pas.
00:55:10 :Donc d'utiliser des chaînes de caractère,ça enlève à toute signification la chaîne de caractère et la constanteet il n'y a pas de moyen de capturer que j'utilise greenalors que je ne gère pas la couleur verte.
00:55:23 :Je ne sais pas pour quelles raisons je ne gère pas la couleur verte.Il n'y a pas de moyen de ça.Tandis que si j'utilise des constantes,si j'essaie d'importer, je ne sais pas,from terminal import green par exemple,donc une constante,si green n'existait pas, mon import va échouer.
00:55:38 :Donc pour le coup, j'ai des moyens.Alors déjà Python va me faire échouer,mais surtout certainement que je ne vais pas aller jusqu'à l'échecparce que quand je vais essayer d'importer greendepuis terminal alors qu'il n'existe pas,l'éditeur, ton éditeur, est-il intelligentpour te dire qu'il ne trouve pas cette constante green
00:55:57 :à l'intérieur de terminal.Donc quand tu utilises des constantes,tu peux te faire aider de ton éditeur,tandis que lorsque tu utilises un dictionnaire comme ça,c'est facile parce que pour le coup,je n'ai rien à importer dans main.
00:56:11 :Je peux juste utiliser la couleur,mais je n'ai pas d'aide pour savoirquelles sont les couleurs que je peux utiliser.Et puis je n'ai pas d'erreur immédiate.
00:56:20 :Simplement, j'aurai une erreurquand je passe la couleur dogspringà bar graph.À un moment donné, il va chercher dans colorsla chaîne dogspring, il ne va rien trouver.
00:56:35 :Puis là, soit il y aura une erreur quelque part,soit il y aura une gestion d'erreurforcée ou non de cette situation.Mais au moment où je code dans main,je n'aurai pas directement un retourcomme quoi j'ai utilisé une constantequi n'existe pas.
00:56:55 :Tandis que si tu utilises des constantescomme le fait Colorama,il y a la possibilité d'avoir cette aide là.Tu sais tout de suite si tu faisback.dogspring, par exemple.
00:57:05 :Là, tu sais tout de suite qu'il n'y a pasde couleur de background qui s'appelle dogspring.D'accord, oui.Oui, oui, oui.OK, donc le petit dictionnaireque j'ai commencé à écrire là,ce serait l'idée ?
00:57:19 :Voilà, le dictionnaire que tu as commencé à écrire,c'est l'idée.Maintenant, petit détailqui, selon moi, peut avoir de l'importance.Ce dictionnaire n'a pas vocationà être importé.
00:57:30 :Et toute fonctionou toute variable qui n'a pas vocationà être importée, par exemple dans main,moi ce que je lui mets, c'est un petit underscore devant.
00:57:39 :Comme ça, par convention, en bidon,tout ce qui possède un underscore,que ce soit au sein d'une classeou au sein d'un module,signifie que c'est privé.
00:57:49 :Ah d'accord, comme ça.Voilà.Un simple underscore, en fait.Parce que les doubles underscores sont réservéspour les mots-clés, en fait.Oui, les doubles underscores,en fait, les doubles underscoresavant et après sont réservéspour les mots-clésdu Python ou lesméthodes spéciales et autres choses.
00:58:10 :Et les doubles underscores, juste devant,en non, s'utilisent quasiment pasen Python.D'accord, OK.Voilà, donc ici,il y a une convention qui dit que quand tu veux rendrequelque chose de privé, tu mets un underscore devant.
00:58:24 :Le créateur de Python dit quedans Python, on est entre adultesconsentants et qu'on saitque ce qu'il y a en underscoren'a pas vocation à être importéet n'a pas vocation à être utiliséhors du module.
00:58:39 :D'accord, parfait.Merci beaucoup.Merci beaucoup.Je rends la main.Voilà, j'arrête le partaged'écran.Voilà, est-ce que c'est bon pour vous ?Pour moi, c'est parfait.
00:58:55 :Et puis là,il n'y a plus l'écran.Je pense qu'on va prendre une dernière question.S'il y en a une.Eric, sur Discord,tu as parlédel'atelier que tu animesjeudi soir,en dehors de Docstream.
00:59:20 :Et tu disais quetu nous en dirais peut-être un mot.Des webinairesou quelque chose comme ça.Alors,j'attends encore pour l'instant l'autorisation de Thibautde le faire.
00:59:34 :Mais par contre, effectivement,par rapport à ta questionsur les utilisateurs multiples,il y a un atelier qui est prévu.Attends, je cherche ça.Et là, je balancerai le lienjustement parce que c'était en relation directeavec une question qu'il y avaiteu aujourd'hui.
00:59:56 :Donc, c'est jeudi 7,comment j'aurai sereinementles plusieurs profils utilisateurs dans Djangoen guide étape par étape.Voilà.Ce que je fais généralement,c'est que j'ai des atelierscomplètement gratuits.
01:00:12 :Je demande juste aux gens de s'inscrirevia une page parce queça me permet de leur envoyer des informationsavant l'atelier,après l'atelier,et puis de pouvoirégalement les prévenir s'il y a unquack, un problème ou quoi que ce soit,de savoir qui est censé être là ou pas là.
01:00:30 :Je mettrai un lienpour ces prochains joursparce que ça correspondait exactementà ta question.Super, ouais. D'accord.Je suis très partant.Oui, je fais une...
01:00:44 :C'est quoi, c'est une...Chaque année, à proche deNoël, durant novembreet décembre,je fais généralementtrois fois par semaineun atelier Djangoque j'appelle les webinairesde l'avant. Et puis,
01:01:02 :on regarde, on passe en revuedes différentssujets, mais c'estessentiellement du Django, du web,c'est pas du tout ça,ou du Python fondamental,donc c'est pour ceux qui fontdu web, et justement, dans ce contexte-là,la gestion des profilsmultiples, profils utilisateurs multiples,c'est une des questions qui revient relativement
01:01:24 :souvent, et j'avaisdécidé de dédier unwebinaire à ça.Merci beaucoup. Super.Voilà.Donc, moi je vous souhaiteune très belle soirée. Le prochain,je vais regarderque c'est tout bon, c'est la semaine prochaine,la semaine prochaine, on ale 30, donc c'est le mercredi,cette fois à 21h,
01:01:48 :et à partir de là,si j'ai bien vu,c'est toujours le mercredi,jusqu'à Noël, quasiment, et toujoursà 21h. Donc si c'est pasà 21h, c'est qu'il y a euune erreur, doncj'ai repassé trois fois pour voirqu'il n'y avait pas d'erreur, mais je repasseraiencore. Donc tous les mercredis
01:02:08 :à 21h comme ça, il y a une certainerécurrence, et vous pouvez mettre vos questionsde côté, et puis vous savez qu'au pire,elles pourront répondreau moins partiellement le mercredisuivant. Là, ce soir, il n'y avait pas
01:02:20 :d'erreur sur l'horaire, c'était justeun problème de lien, de connexion.Ouais, je sais qu'il y a une option,il y a une option Discord quelque part, je sais pasqu'est-ce qui m'a pris de la cocher,je fais souventles choses depuis le téléphonepour ce genre de choses,et l'interface,
01:02:38 :elle n'est pas toppour l'instant, sur letéléphone, donc c'est possible que c'est à causede ça, mais en tout cas, je m'excuse.D'accord, donc en fait,c'est toujours sur la plateformeGoogle Meet, en fait. Voilà,
01:02:52 :en tout cas, avec moi,et puis, alors,c'est toujours à priori sur Google Meet,parce que, justement,Thibaut a mis en place des chosesqui permettent d'enregistrer automatiquementl'événement, et puisaprès de poster la vidéo, justement, en replay,de telle manière à ce que vous puissiez le voiren replay, donc
01:03:12 :s'il s'est indiqué quelque chose,d'autre, c'est que c'est une erreur.D'accord,une toute dernière question, le liendont vous parliezpour lesdjango de l'avant, on le retrouve où ?
01:03:26 :Alors, pour l'instant, j'ai pas encore faitle site pour ça,pour l'inscription, mais je,comme tout, sij'en parle avec l'accord de Thibaut,c'est dans lechannel Montora, moi je...
01:03:40 :Ah, c'est dans le channel Montora,d'accord, ok, ça je vais surveiller.Je suis sur le Discord de Doxtrin,et en général, je vais plus ou moinsque sur le channel, sur le salonMontora, donc c'est généralementlà que vous me trouverez,ou que je posterai des chosess'il y a quelque chose à poster.
Aucune occurrence trouvée pour « ».
00:00:00
Introduction à la session
00:03:54
Organisation du code en librairie
00:04:35
Réorganisation du code en modules
00:06:05
Gestion des exceptions et du code structure
00:09:11
Considérations pour les tests unitaires
00:13:01
Utilisation des mocks pour les tests
00:16:18
Nomenclature des modules et paquets
00:20:26
Structure des fichiers de requêtes SQL
00:24:20
Contexte utilisateur pour les applications
00:29:00
Utilisation de proxy models pour les profils
00:34:52
Gestion des logs avec plusieurs modules
00:47:47
Questions sur Colorama et abstraction des dépendances
01:00:06
Conclusion et discussion atelier