Mots-clé : python3

Python : liste : voir si tous les éléments sont identiques

Encore une petite idée prise ici : Astuces Python en anglais

>>> lst = ['a', 'a', 'a']

>>> len(set(lst)) == 1
True

>>> all(x == lst[0] for x in lst)
True

>>> lst.count(lst[0]) == len(lst)
True

Dans l’ordre, du plus « Pythonique » au moins « Pythonique »… mais paradoxalement, du moins efficace au plus efficace.
Utiliser count() est le plus rapide.

Django / jQuery / Select2 / autocomplete

Voici un tutoriel sur quelque chose qui m’a pris plusieurs jours à réaliser « proprement » et encore, ça n’est pas si propre, mais c’est le mieux que je puisse faire actuellement, en termes de rapport « propreté / temps passé » raisonnable.

Voici l’idée : je veux qu’on puisse commencer à taper quelques lettres dans un champ, et que ce dernier aille demander en AJAX/JSON si jamais il y a des tags « connus ». Si c’est le cas, le retour renvoie une liste, qui s’ouvre, et l’utilisateur peut choisir dans cette liste en descendant avec les flèches. S’il n’y a aucun retour, l’utilisateur peut aller au bout, et envoyer son formulaire, et c’est là que la magie intervient : plus tard, s’il revient sur le formulaire, il pourra taper quelques lettres, et on lui proposera le champ en question ! Mieux ! Il peut séparer les champs par une virgule, et donc taper plusieurs choix. Exactement comme lorsqu’on commence à entrer le nom d’un destinataire sur gmail. La classe non ?

J’ai voulu faire cela pour plein de tags, mais le client pour lequel je faisais cela n’a pas réellement compris l’intérêt et m’a demandé de faire une liste de choix « fixes » que l’utilisateur peut cocher. Bref, no comment.

Donc voici comment j’ai procédé (je ne dis pas que c’est la meilleure façon, il y en a sûrement d’autres, mais vous pouvez vous en inspirer) :
– création d’un modèle Tag qui a la langue (selon les langues, pas le même Tag) :
– dériver un type de champ de base Django forms.TypedChoiceField afin de permettre une liste de choix, mais qui sera valide de deux manières : il faut surcharger les méthodes qui convertissent les valeurs de retour de ce champ, afin :
    – soit d’essayer de lire une liste d’entiers, séparés par des virgules, qui sont les ids des champs,
    – soit pour chaque champ qui ne peut pas être converti en entier, appeler une méthode « custom_tag« , qui va ajouter le tag en base de données puis renvoyer un entier = pk du tag ajouté
– créer un Widget custom dans lequel on passera une classe spéciale destinée au JavaScript qui recherchera cette classe
– en JavaScript (mon ami de toujours, qui fait que je passe 20% du temps sur Django à m’amuser et 80% du temps sur l’habillage Web à rager et/ou bidouiller), faire une routine qui va chercher les widgets définis au-dessus et y appliquer le select2 tel que défini dans la documentation
– faire une vue destinée de recherche qui prend un paramètre, et renvoie les résultats trouvés, c’est pour remplir les demandes d’AJAX de select2. Elle doit renvoyer un tableau « résultat » et une variable « total » qui est simplement le « length » de « résultat ».

C’est tout… enfin tout… on se comprend !

Mais en pratique, une fois que tout est mis en place, il suffit de déclarer dans n’importe quel formulaire un champ ainsi, et on aura un champ entièrement dynamique, qui s’auto-alimentera avec le temps. Extrêmement pratique :


    a = _("Emails:")
    emails = TagTypedChoiceField(
        label=a, required=False,
        custom_tag=add_tag_to_languages,
        widget=Select2Widget(attrs={
            'title': a,
            'placeholder': _("type an email"),
            'multiple': 'multiple',
            'data-select2-json': reverse_lazy(
                'co_branding_json_tags_emails',
                kwargs={'company': 'ubisoft'}),
            'class': 'form-control form-control select2'}),
        error_messages=e,
        choices=self.get_list_tags(Tag.TYPE_EMAIL))

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…

Python : cygwin turtle howto

Avec l’installeur Cygwin :

  • installer Python3
  • installer xinit

A partir de là, voici la solution résumée de plusieurs heures de recherche :
Il vous faut préciser l’affichage, qui est chez moi le 0.0 :

export DISPLAY=:0.0

Mettez le code précédent dans votre configuration de démarrage (.bashrc)

Enfin, sur la console, l’astuce qui change tout : il faut lancer xterm.

Et là, un nouveau terminal s’ouvrira, mais qui discute avec le serveurx, et tout fonctionnera.
Pour tester, j’ai simplement lancé python3 et turtle :

  • python3
  • import turtle
  • turtle.Screen()

Et hop l’écran sur lequel on bougera la tortue pour dessiner s’affiche, c’est magique :

Image cygwin python

En espérant vous faire gagner quelques heures de recherche !