Pycharm
Vim
Live templates |
|
Settings > Editor > Live template |
Créer son live template, exemple :if/else/endif ->
|
Tout ce qui concerne le développement en général, que ce soit des choses générales, ou des choses bien précises. Cela va de la gestion de projet à la recherche du fonctionnement de pointeurs en C.
Live templates |
|
Settings > Editor > Live template |
Créer son live template, exemple :if/else/endif ->
|
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.
Je vous laisse découvrir qui est Sam Agnew, mais dans la vidéo :
Enorme. Et en plus vous verrez du code sur comment lire les notifications twitter en quelques lignes de Python
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))
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…
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 :
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 🙂
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é.
settings.py
, rajouter dans les applications installées (INSTALLED_APPS
) l’application 'django.forms'
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')],
class MonCheckboxSelectMultiple(CheckboxSelectMultiple):
template_name = 'include/widget/checkbox_select.html'
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
.
Voici un mémo des « étapes » à remplir dans l’ordre pour faire un formulaire sur mesure en Django « dans l’ordre »:
ModelForm
et utiliser la classe Meta
pour déclarer le modèle via model
, et déclarer les champs via fields
.widget
dans lequel ce champ sera rendu (cf mon exemple dans l’article précédent).generic.UpdateView
def is_valid(self)
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 veutdef 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.
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
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 !
Récupérez les dernières sources sur le site officiel.
Puis allez dans le dossier source et tapez :
./configure --prefix=$HOME/python
Puis, si tout s’est bien passé = pas de message d’erreur :
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 !