Catégorie : python

PyCharm cheatsheet

Vim

Live templates

Settings > Editor > Live template Créer son live template, exemple :
if/else/endif ->
{% if $IF$ %}
{% else %}
$END$
{% endif %}
Commentaires fermés sur PyCharm cheatsheet Publié dans

100 livres Python pour tout le monde !

Pour toutes les personnes qui croient qu’on passe des jours entiers à écrire des bouquins pour les donner, changez d’endroit : oui ils sont payants… et c’est normal.

Bref, pour tous ceux qui veulent apprendre et payer pour avoir les meilleurs livres, écrits par les meilleurs, dans le domaine qui vous intéresse, vous avez tout ici : pythonbooks.org.

Sam Agnew bidouille le bon vieux Zelda à la PyCon 2017

Je vous laisse découvrir qui est Sam Agnew, mais dans la vidéo :

  • il fait un peu de LUA pour hacker et analyser le code de Zelda ;
  • il met en place le fait de discuter entre twitter et le code qui écrit en direct dans Zelda ;
  • cela écrit en direct dans Zelda pendant qu’on joue !

Enorme. Et en plus vous verrez du code sur comment lire les notifications twitter en quelques lignes de Python

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…

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 : 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 : 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 !

Django : internationalisation des fichiers javascript : tutoriel complet

Django vient tout faire pour l’internationalisation de pages HTML, mais saviez-vous qu’il est aussi possible et de manière très simple d’internationaliser vos échanges AJAX ?

Vous avez un tutoriel ici.

Seul point noir : ils ont oublié deux éléments essentiels, je vais donc faire une explication courte ici, puis ajouter un résumé dans ma cheatsheet Django.

Dans l’ordre :

  • Configuration de urls.py :
    Ajouter le dictionnaire dans lequel vous précisez vos « packages ». Vos « packages », ce sont simplement les dossiers qui correspondent à l’application que vous voulez afficher. Normalement c’est un dossier racine de votre projet, moi je l’appelle très souvent « app » pour qu’il soit tout en haut des dossiers racine. Donc ici :

    js_info_dict = {
        'packages': ('app',)
    }
  • Configuration de urls.py :
    Ajouter l’URL jsi18n. Attention ! L’aide ne précise pas du tout où la mettre et c’est là où j’ai perdu énormément de temps, faites attention : il faut le mettre dans les patterns traduits, soit ici :

    urlpatterns += i18n_patterns(
        url(r'^jsi18n/$', javascript_catalog, js_info_dict,
            name='javascript_catalog'),
            # blabla...
    }
  • Includes des fichiers js dans les pages :
    <script src="{% url 'javascript_catalog' %}"></script>
  • Includes des fichiers js dans les pages :
    <script src="{% static 'js/globals.js' %}"></script>
  • Dans le fichier précédent, j’ai le code suggéré dans la documentation :
    function _(a) {
         return gettext(a);
    }
  • Générer les chaînes à traduire. Là aussi dans la documentation ils en parlent mais très mal. Pour résumer, il faut préciser le domaine djangojs :
    Exemple d’ordre qui lance la recherche de toutes les chaînes à traduire, en ignorant le dossier third_party (où je mets les outils externes que je ne veux pas toucher) :

    makemessages -d djangojs -i third_party --locale fr --locale en
  • Traduire. Ce sont les fichiers djangojs.domaine djangojs.po qu’il faut modifier, pas le classique django.po (sans strong>js).

Et à partir de là, tout fonctionne : dans tous les fichiers JavaScript qui suivent, je peux traduire à la fois ce qui arrive en AJAX, ou bien tout simplement afficher un message via _(). Exemple :

$('#menu').empty().append(
    $('<h5 />').html(_('Waiting...'))
);