Python : on n’arrête jamais d’apprendre….

J’avais rendu compatible Python 3 + dernière version de Django authomatic, un outil qui gère la connexion avec plein d’API, sachant que les plus importantes sont google et facebook.

J’avais fait ce code :

    @property
    def params(self):
        # (!) Olivier Pons ! REQUEST removed
        a = QueryDict('', mutable=True)
        a.update(self.request.GET)
        a.update(self.request.POST)
        retour = {}
        for key, value in a.iterlists():
            if len(value) > 1:
                retour[key] = value
            else:
                retour[key] = value[0]
        return retour

J’étais tout content et tout fier de le partager. Ils ont écrit « problème corrigé ».
Et leur solution :

    @property
    def params(self):
        params = {}
        params.update(self.request.GET.dict())
        params.update(self.request.POST.dict())
        return params

J’ai encore plein de choses à apprendre en Python on dirait…

Tiens tiens… Python vs Php…

Depuis plus de quinze ans, j’essaie d’expliquer que des fontes grosses, claires et visibles sont plus efficaces que tout le reste et le Web est allé dans ce sens il y a à peine quinze ans…

Depuis plus de dix ans, je prédis que la domotique va devenir extrêmement importante et omniprésente, et on commence à peine à parler d’objets connectés…

Il y a quinze ans j’ai eu un pressentiment très fort avec Php et j’ai écrit énormément de choses avec jusqu’à acquérir un bon niveau… car je savais que Php était l’avenir !

…jusqu’à il y a cinq ans où j’ai bien senti que tout ralentissait… Je me suis penché sur Python / Django, et j’ai eu le même enthousiasme qu’avec Php il y a quinze ans. C’est pas tous les jours qu’on a ça ! Bref. Tout ça pour dire que :

Python dépasse pour la première fois Php en nombre total de questions sur Stackoverflow.

J’avais eu un entretien de prestation pour Symfony chez… je ne cite pas, mais ils se reconnaîtront pour la description que je fais ensuite : j’avais eu le malheur de leur expliquer que non seulement Symfony c’est une usine à gaz, mais en plus qu’il était dépassé et que Django plus Python était mieux à tous les niveaux. Que n’avais-je pas dit, quel sacrilège ! Mais bon, les deux CTOs ne connaissaient même pas LoL alors que là aussi je prédis depuis plus de cinq ans qu’il y a de plus en plus d’argent à se faire dans le monde des claviers / et du gaming…

J’aimerais bien revoir ces deux CTOs… pour voir s’ils me riraient encore au nez comme ils l’avaient fait… comme si j’étais le dernier des crétins… mais la nature humaine étant ce qu’elle est, il est toujours très difficile – voire impossible pour certains – de dire humblement : « j’avoue, je m’étais trompé »… peut-être qu’ils en seraient capables, je ne les connais pas assez pour m’avancer.

Bref : j’ai toujours prédit les bonnes tendances : Delphi à l’époque, puis Php, puis des concepts comme les commandes de repas en lignes, et maintenant Python et je ne me suis jamais trompé en 25 ans… et hop, une de plus !

J’ai encore une autre grosse tendance pour laquelle je suis sûr que c’est l’avenir, et je n’en parle pas car je suis en train de développer une application dessus… il y a bien sûr une interaction avec un site développé en Python / Django, bien sûr !

Bonne journée à tous 🙂

Django >= 1.11 : faire des widgets de formulaires sur mesure

Les « widgets » sont les composants affichés dans les formulaires qui permettent la saisie des informations (combo, checkboxes, etc.).
A partir de la version 1.11, les widgets ne sont plus du tout construits comme sur les versions précédentes.
Ce qu’il faut retenir : avant, c’était le développeur qui pouvait surcharger les widgets, j’ai fait un petit article ici.
Ce qu’il faut retenir sur la nouvelle gestion des widgets : le graphiste peut avoir accès à l’habillage, et configurer sur mesure l’affichage des widgets. C’est un changement très important du point de vue de travail en équipe, surtout si vous avez un graphiste / front end dans votre équipe.
La documentation est très fournie, jetez un coup d’oeil par là.
Mais son inconvénient, c’est qu’elle est, justement, très fournie… voici donc un résumé.

« surcharger » les widgets

  • Dans settings.py, rajouter dans les applications installées (INSTALLED_APPS) l’application 'django.forms'
  • Toujours dans settings.py, dans la directive TEMPLATES, ajoutez la directive 'DIRS' s’il elle n’y est pas déjà, et précisez dans un tableau les répertoires supplémentaires, par exemple pour moi j’ai :
    'DIRS': [os.path.join(BASE_DIR, 'templates')],
  • Surchargez le composant qui vous intéresse en déclarant le template, exemple :
    class MonCheckboxSelectMultiple(CheckboxSelectMultiple):
        template_name = 'include/widget/checkbox_select.html'
  • Organisez vous dans votre dossier templates à l’identique de la déclaration. Pour remprendre mon exemple j’ai un fichier templates/include/widget/checkbox_select.html dans lequel j’ai copié collé le code source du template Django, puis je l’ai modifié pour qu’il convienne à mes besoins.

Allez chercher les templates, et profitez-en pour lire le code source des formulaires, vous verrez il est simple, et vous verrez comment les templates sont déclarés : Python36/Lib/site-packages/django/forms.

Django : mémo des formulaires « sur mesure »

Voici un mémo des « étapes » à remplir dans l’ordre pour faire un formulaire sur mesure en Django « dans l’ordre »:

  • Créer un formulaire. Classique. Faire un ModelForm et utiliser la classe Meta pour déclarer le modèle via model, et déclarer les champs via fields.
  • Construire ces champs du modèle dans le formulaire. Attention, ne pas confondre le types du champ (qui est en base = le champ du modèle), c’est ce que vous créez, et le widget dans lequel ce champ sera rendu (cf mon exemple dans l’article précédent).
  • Construire la vue, dans le cas update du principe CRUD, j’hérite de generic.UpdateView
  • Dans le formulaire d’origine, créer la fonction dit si le formulaire est valide ou pas : def is_valid(self)
  • Dans la vue, après que le formulaire ait été validé, écrire la fonction def form_valid(self, form) qui est appelée lorsque le formulaire est valide, et utiliser les données nettoyées du formulaire form.cleaned_data pour enregistrer ce que l’on veut
  • Pré-remplir les champs du formulaire, y compris les champs « sur mesure » : c’est dans la vue, via def get_initial(self)

Ouf ! Une fois que tout ça est implémenté, Django construit la vue en lecture (GET) selon un chemin qui ressemble en gros à ça :

  • vue -> form_class
  • forme -> class Meta -> model + fields
  • forme -> constructeur __init__ (ajout champs sur mesure)
  • vue -> get_initial (remplir les valeurs de tous les champs du formulaire)

Django construit la vue en écriture (POST) selon un chemin qui ressemble en gros à ça :

  • vue -> form_class
  • forme -> class Meta -> model + fields
  • forme -> constructeur __init__ (ajout champs sur mesure)
  • forme -> def is_valid(self)
  • forme -> def clean_xx(self) (code qui valide/ou pas le champ xx)
  • forme -> def clean(self) (code qui valide/ou pas tous les champs)
  • vue -> def form_valid(self, form) (sauver ici avec form.cleaned_data)

Alors oui je sais c’est compliqué. Mais quand on y réfléchit bien, sur le modèle MVC, on ne peut pas faire autrement, et c’est le mieux possible. Et encore je n’ai pas parlé de la routine « save() » qui est dans le formulaire : elle est automatiquement appelée lors is_valid() renvoie true, et dans le cas d’un ModelForm elle sauvegarde le formulaire.

Django : les formulaires « sur mesure »

Voici les étapes lorsqu’on sort des sentiers battus et qu’on veut créer un formulaire sur mesure, ainsi qu’une vue sur mesure.

J’ai toujours eu besoin d’un ModelForm : je garde les champs que je veux, voici un code basique qui crée le champ label, avec toutes les traductions nécessaires :

class QuestionForm(forms.ModelForm):
    class Meta:
        model = Question
        fields = ('label', )
    e = {'required': _(u'This field is required'),
        'invalid': _(u'This field contains invalid data')}

    a = u'{}<span class="important-field">*</span>'.format(_(u'Question:'))
    label = forms.CharField(
        label=a, localize=True, required=True,
        widget=widgets.TextInput(attrs={
            'title': a,
            'class': 'form-control form-control'}),
        error_messages=e)

Ensuite pour cette classe, je crée un champ dynamiquement via le constructeur :

    def __init__(self, *args, **kwargs):
        super(QuestionForm, self).__init__(*args, **kwargs)
        # -----------------------------------------------------
        # Création dynamique de champs custom
        # self.fields est de type OrderedDict(), qui se base
        # sur l'ordre d'ajout des éléments. Alors si on veut
        # un autre ordre, pas d'autre choix que de reconstruire
        # le dictionnaire en y appliquant l'ordre qu'on veut :
        #
        # création dynamique de l'image :
        a = _(u'Picture')
        photo = ImageField(
            label=a, allow_empty_file=True, required=False,
            widget=forms.FileInput(attrs={
                'title': a,
                'placeholder': _(u'picture'),
                'class': 'form-control',
                'accept': "image/*", }),
            error_messages=e)
        new_fields = OrderedDict([
            ('label', self.fields['label']),
            ('photo', photo),
        ])
        self.fields = new_fields

Linux : ajouter un client sftp et le chrooter

UPDATE : voici le lien (merci Hervé !) que j’aurais dû lire avant de faire tout cela…
A vous de lire mon blog + celui qui suit et de prendre le meilleur de chacun pour aller au plus vite !

Restrict SSH User Access to Certain Directory Using Chrooted Jail


Voici ce qu’il faut savoir (et qui m’a pris le plus de temps) : pour chrooter vraiment un utilisateur, il faut lui mettre les ordres de commande minimales requises dans un dossier bin et l’autre dossier qui gère les entrées-sorties dev. Et puis ajouter configurer le serveur ssh pour préciser « que du sftp, pas de ssh ». Ce n’est presque jamais documenté dans les sites d’exemples que vous trouverez sur le Web, merci unix.stackexchange !

Dans mon cas, voici tous les ordres que j’ai faits, et qui font qu’au final tout a fonctionné. Si ça se trouve il y en a un ou deux qui sont inutiles… mais je n’ai pas le temps de tout parfaitement nettoyer, je vous dis ce que j’ai compris des ordres, à ma manière :

  • Installer une ligne de commande shell qui peut fonctionner sans aucune dépendance :
    apt-get install bash-static
  • Ajouter l’utilisateur thomas en précisant le nom du shell à lancer :
    useradd -m -c /home/thomas -s /home/thomas/bin/sh thomas
  • Changer son mot de passe :
    passwd thomas
  • S’assurer que le home de Thomas appartient bien à root et est en 755 (sinon ssh refuse la connexion) :
    chmod 755 /home/thomas ; chown root: /home/thomas
  • Créer les dossiers bin et dev :
    mkdir /home/thomas/bin
    mkdir /home/thomas/dev
    cp /bin/bash-static /home/thomas/bin/sh
  • Ensuite il faut copier puis exécuter ce code, mais je ne sais pas trop à quoi ça sert :
    cp /dev/MAKEDEV /home/thomas/dev/
    cd /home/thomas/dev/ && ./MAKEDEV
  • Enfin le plus important : configurer le serveur sshd
    vim /etc/ssh/sshd_config

    Et y ajouter ces lignes, qui précisent où chrooter et (surtout) qu’on n’autorise que le sftp :

    Match user thomas
        ChrootDirectory /home/%u
        AllowTCPForwarding no
        X11Forwarding no
        ForceCommand internal-sftp

C’est le tout dernier ordre, toute dernière ligne qui m’a fait perdre énormément de temps !

Linux : compilation de Python en local

A l’IUT d’Aix en Provence, tous les ordinateurs sont gérés à distance, et sous Linux, aucune possibilité d’installer un logiciel.
Par contre, il est possible de compiler en local !

Compilation Python

Récupérez les dernières sources sur le site officiel.
Puis allez dans le dossier source et tapez :

./configure --prefix=$HOME/python
make && make install

A partir de là, sous PyCharm, précisez le chemin Python qui correspondra à votre $HOME/python et précisez que vous voulez installer les packages dans le répertoire de l’utilisateur courant (une case à cocher).

Et voilà : vous aurez un serveur Web Python et pourrez développer et installer tous les packages et librairies que vous voulez !

LibreOffice Impress : comment faire une macro

Comme ils l’expliquent officiellement ici, tout est en constante évolution, la documentation est pas forcément à jour etc, donc il vaut mieux aller jeter un coup d’oeil directement dans les rouages pour être sûr du fonctionnement de certains objets de LibreOffice. Ajoutez tout d’abord l’inspecteur d’objet. Il faut aller dans les Macros » Gestion des extensions, et ajouter en une extention en copiant/collant l’URL ici.

Tout d’abord le lieu de référence, celui que tout développeur cherche toujours : celui qui affiche tous les élements accessibles et ce qu’on peut faire avec : les namespaces !

List of all namespaces with brief descriptions

Je vous résume mon problème : la nouvelle mise à jour de LibreOffice change le comportement des animations et il n’est plus possible d’appliquer la même animation à un groupe. Il faut applique l’animation à la main, élément par élément ! Sur un slide de 40 pages j’ai déjà 40 fois à appliquer la même animation (ouverture en fondu), mais si je dois le faire pour 40 x 10 animations = 400 fois c’est du n’importe quoi.

Vous avez tout d’abord une liste d’exemples très intéressants ici. Mais le seul problème c’est qu’il y a très peu de choses concernant Impress. Il y a une super documentation ici, mais c’est sur des macros Python, et Python en macros, n’est utilisable que sur Write, pas sur Impress…

Voici un exemple très poussé et dont plein de choses fonctionnent à merveilles, mais certains appels ne fonctionnent pas.

C’est à partir de là que je me suis débrouillé pour écrire ma macro qui sélectionne toutes les animations du slide en cours, et les change au format « Ouverture en fondu -> Durée : 1.0s ».

Windows : astuce pour gagner du temps

  1. Placez un raccourci sont placés dans le répertoire C:\WINDOWS\system32\lnk.
  2. Ajoutez ce répertoire au PATH de Windows donc tous les raccourcis et autres programmes placés dans ce répertoire pourront être exécutés via DOS ou la commande Exécuter de Windows [WIN+R].
  3. Créez un fichier bat très court, moi j’ai, par exemple « h.bat »
  4. Dans ce fichier, si vous voulez ouvrir l’explorateur à un endroit spécifique, tapez « %SystemRoot%\explorer.exe "C:\BLABLA" » avec BLABLA étant le nom du dossier que vous voulez ouvrir

Note : si vous voulez que vos fenêtres s’ouvrent en mode « maximisé » (qui est différent de plein écran), ajoutez au début start /MAX. Exemple :
start /MAX %SystemRoot%\explorer.exe "C:\BLABLA"

Raccourci de liens

Depuis plus de 15 ans j’utilise cette astuce que peu de gens connaissent : cherchez à gagner du temps, vous verrez cela vous servira tôt ou tard !

IUT : jQuery / jQuery Mobile

Sujet

Ce que vous voulez tant que c’est dans le cadre de ce que l’on a vu. Vous avez tout le Web comme inspiration !
N’oubliez pas de me donner le nom et le mot de passe pour se connecter !

Voici les fonctionnalités obligatoires :

  • Connexion + déconnexion (vu en cours)
  • Effets jQuery sur les éléments
  • Appels JSON : au moins deux appels en plus de ceux vus en cours

Sujet imposé si vous n’avez pas d’idée

Cocktails : on se connecte, on a une liste d’éléments (récupérés en JSON) disponibles, on coche ceux qui nous intéressent, on valide, c’est envoyé, et le retour en JSON affiche les cocktails qu’il est possible de faire avec ce que l’on a coché.

Ce que vous devez me rendre

  1. Sur 4 points : le site HTML (bootstrap / design) et le code source du site HTML (HTML5, indentation)
  2. Sur 10 points : les appels AJAX, ainsi que des effets avec jQuery + de la construction dynamique d’éléments avec jQuery (indentation jQuery / JavaScript)
  3. Sur 6 points : le site HTML mobile avec du jQuery Mobile et des appels AJAX (indentation).

Pour favoriser votre organisation

  • Créez un dossier « SiteWeb » : vos pages HTML classiques, et votre code JavaScript
  • Créez un dossier « SiteMobile » : vos pages HTML pour jQuery Mobile, et votre code JavaScript pour jQuery Mobile
  • Créez un dossier « json » : tout votre code « serveur » (en Php sûrement), qui renvoie les pages au format JSON que les deux sites précedents appelleront. C’est la « référence » à n’écrire qu’une fois (copiez-collez ce dossier dans les deux dossiers précédents lorsque vous modifiez le code serveur (sous Linux, pas la peine, faites juste un lien symbolique (si vous voulez plus d’informations contactez moi)))

Librairies autorisées

Interdiction d’utiliser une librairie JavaScript qui ne vienne pas des sites autorisés précédemment

Dernier délai

Dimanche 2 avril à minuit

Fin de semaine de notre dernier cours, soit dimanche à minuit. Passé ce délai ce sera 1 pt par 2 heures de retard (je prendrai en compte la date de réception du mail).
Pour ceux qui essaient vraiment d’aller jusqu’à la dernière minute, toute heure entamée est comptée comme une heure complète. Exemple : un point en moins si je le reçois le lundi 3 avril à 00:01.
N’oubliez pas de me donner le nom et le mot de passe pour se connecter !

Rendu du TP

Vous ne m’envoyez que le code HTML et JavaScript, et un lien vers un site sur lequel vous avez tout réalisé. Ainsi, je n’aurais pas à installer / regarder ce qui a été fait en Php (ou Django/Python pour ceux qui veulent essayer les nouvelles technologies).

Avertissements

  • Copie sur une autre personne (« je se savais pas comment implémenter telle ou telle fonctionnalité dont j’avais besoin pour aller plus loin, je l’ai copiée sur un autre »), deux cas se distinguent :
    • si la personne est clairement nommée, cette fonctionnalité ne sera pas prise en compte dans la notation (= 0 pour cette fonctionnalité) ;
    • si la personne est clairement nommée, et qu’il y a une amélioration de la fonctionnalité : note pour la fonctionnalité divisée par 2 (uniquement la moitié du travail a été faite) ;
    • 0 aux deux personnes sinon ;
  • Si je m’aperçois que vous avez bêtement copié collé des sources Internet, je vous convoquerai pour vous demander de m’expliquer la fonctionnalité, et deux cas se distinguent :
    • si vous ne savez pas m’expliquer le code alors 0 ;
    • si vous savez m’expliquer tout le code alors votre note totale sera divisée par vous + le nombre de contributeurs à ce projet, ce qui se rapprochera certainement de 0 aussi.