Utiliser un socket en Python pour lire les cours sur Binance

A quoi servent les sockets?

Les sockets vous permettent d’ouvrir une liaison continue entre le serveur et le client. A la différence d’une requête AJAX, qui est l’équivalent d’un chargement de page HTTP, qui s’arrête une fois les informations téléchargées, le socket ouvre un stream continu. Cela évite les limitations des requêtes AJAX, comme par exemple la limitation du nombre de requêtes par minutes par exemple.

Si vous voulez connaitre un cours de bourse en temps réel, hors de question d’utiliser des requêtes AJAX, car vous allez vous faire blacklister.

Installer la librairie websocket-client

Il vous faut installer la librairie websocket-client (attention il y a une autre librairie qui s’appelle websocket, ce n’est pas celle là)

pip install websocket-client

Le script:

import websocket,json,os
def on_message(ws, message):
    """ convert string to dictionary"""
    message = json.loads(message)
    clear = lambda: os.system('cls')
    clear()
    print(message)
    print(" ",message['data'][0]['p'],flush=True,end="\r")


def on_error(ws, error):
    print(error)

def on_close(ws, close_status_code, close_msg):
    print("### closed ###")

def on_open(ws):
    ws.send('{"method":"SUBSCRIBE","params":["btcusdt@aggTrade","btcusdt@depth"],"id":1}')

if __name__ == "__main__":
    websocket.enableTrace(False)
    ws = websocket.WebSocketApp(f"wss://stream.binance.com:9443/ws/bnbbtcopen@depth",
                              on_open=on_open,
                              on_message=on_message,
                              on_error=on_error,
                              on_close=on_close)
    ws.on_open = on_open
    ws.run_forever()

Lien vers la documentation du service websocket de Binance:

Python Module not found en exécution en ligne de commande

Alors que ça marchait très bien sous PyCharm…

Imaginons que vous ayez un programme utilisant une librairie externe, par exemple Beautifulsoup, ce dernier étant une librairie externe, donc il faut l’importer avec la commande :

pip install beautifulsoup4

Sous PyCharm, la librairie sera installée dans la section External Librairies, dans la barre latérale Project. Mais le véritable répertoire (sous Windows) sera :

C:\Users\mon_user\PycharmProjects\nom_projet\venv\Lib\site-packages

Remplacez mon_user et nom_projet par vos données propres.

Ainsi lorsque vous exécutez un programme en ligne de commande, et qu’il vous dit « Module Not Found …bs4 » c’est que l’exécutable Python n’arrive pas à le trouver. Il faut créer la variable PYTHONPATH.

Pour ce faire (Windows) dans la boite de recherche de Windows (Cortana) tapez PATH, vous accédez aux variables d’environnement. Ajoutez la nouvelle variable PYTHONPATH puis ajoutez le chemin cité plus haut. MAintenant vous pouvez lancer votre programme en ligne de commande.

Lister les valeurs des chemins d’inclusion

import sys
print(sys.path)

Ce programme va vous afficher tous les chemins qui sont tenus compte pour la recherche de module. En fonction de votre environnement virtuel, les résultats peuvent différer, et vous saurez pourquoi vous avez un Module Not Found.

javascript

Mémento de Fetch

Faire une requête GET avec fetch

L’expression la plus simple pour une requête GET avec fetch est :

fetch("https://google.fr")
.then(function(response){
    return response.json
})
.then()

Pour une requête GET pas la peine d’indiquer à la fonction car c’est celui par défaut

Faire une requête POST avec fetch

Le body

let apiUrl = "http://localhost/api/"
            fetch(apiUrl, {
                method: "POST",
                body: {
                    name : 'toto'
                   }
            })

La requête ci-dessus va envoyer un objet JSON contenat l’attribut « name », via la méthode POST (comme si c’était un formulaire)

Mysql logo

Laragon : passer à MySQL 8

Récemment pour faire des fonction de fenêtrage, j’ai du passer sous Laragon à MySQL 8, version qui supporte cette feature. Pour ceux qui ne le connaissent pas encore, quand vous faites un GROUP BY, vous perdez de l’information en agrégeant une donnée. Pour néanmoins disposer de cette valeur agrégée sur un elisting de résultat non agrégé, c’est là qu’il fuat faire intervenir la fonction de fenêtrage OVER (PARTITION BY).

Passer à MySQL 8 sous Laragon

La plupart des information ont été glanées sur le site de Laragon

Laragon upgrade to MySQL 8 instructions:
https://forum.laragon.org/topic/2017/mysql-8-upgrade-instructions

Après avoir suivi les instruction ci-dessus :
MySQL ne peut démarrer après MAJ à Mysql 8 :

https://forum.laragon.org/topic/1766/laragon-4-0-16-mysql-8-0-18-mysql-cannot-start/3

La page ci-dessus donne les manipulation à faire pour obtenir un nouveau mot de passe :
mot_de_passe_temporaire

"You must reset your password using ALTER USER statement before executing this statement"

ALTER USER 'root'@'localhost' IDENTIFIED WITH caching_sha2_password BY 'root'; //syntaxe mysql 8 !!

PHPMYADMIN on ne peut se connecter après mise à jour
https://stackoverflow.com/questions/52364415/php-with-mysql-8-0-error-the-server-requested-authentication-method-unknown-to


Un nouveau répertoire mysql8 vient de se créer dans le sous répertoire de mysql :
C:\laragon\data\mysql-8
N'oubliez pas avant de faire la migration de backuper le dossier mysql.
logo ethereum

Comment staker ses polkadots

Installer

  • Installer l’extension du wallet polkadot.js
  • créer deux accounts, un polkadot stash (le stash est comparable à un cold wallet) et un polkadot controller (comparable à un hot wallet). Ce sotn juste des noms, ils sont identiques dans leur nature, c’est après leur association dans l’interface de polkadot que leur rôle va diverger
  • virer les coin polkadot dans un des accounts, de préférence celui avec le stash.
  • Aller à la page principale de polkadot, aller dans Network > Staking, puis dans Account actions, cliquer sur le signe +à côté de Nominator, il vous faut un être un nominator avant de pouvoir nommer un validator. Nommez 16 validateurs.

Etudiez bien les profil des validateurs avant de le nommer. Choisissez ceux qui sont identifiés, ayant un bon historique (pas de slashing).

Vérifier le hash (checksum) sha1 d’un fichier

Lorsque vous téléchargez un fichier depuis Internet, vous pouvez vérifier le checksum (quand il est donné par le site) d’un fichier pour vérifier qu’il n’est pas corrompu, c’est à dire que que le checksum est identique à celui donné par le site.

Windows

certutil -hashfile nom_fichier SHA256

Linux

sha256sum nom_fichier

Ces commandes ont bien sûr des options mais ici c’est le minimum syndical qui est montré, et c’est ce dont on a le plus souvent besoin.

Python : nombre d’argument arbitraire avec **kwargs et *args

En python il est possible de construire des fonctions qui acceptent un nombre indéfini de paramètres, aussi bien en positionnel qu’en nommé.

*args

def mafonction(*args):
   for a in args:
        print(a)

mafonction(1)
# 1
mafonction(1,2,3)
# 1
# 2
# 3

le *args est interprété comme un tuple

**kwargs

def mafonction(param,*args,**kwargs):
    for a in kwargs:
        print(a,kwargs[a])

mafonction(nom="Dupont",age=27)
#nom Dupont
#age 27

Notez qu’il n’est pas nécessaire de les appeler *args et **kwargs, on peut utiliser d’autres noms.

On peut mixer ces deux types de paramètre avec des paramètres classiques

def mafonction(param1,*args,**kwargs):
    

Unpack argument list

Cette technique consiste à préfixer le paramètre d’un astérisque, pas lors de la déclaration de la fonction, mais lors de l’appel de la fonction.

def mafonction(a,b,c):
    print(a,b,c)

obj = {"nom":"Dupont","age":27}
mafonction(100,**obj)
# 100,Dupont 27

def mafonction(a,b):
    print(a,b)

l = [1,2]
mafonction(*l)
# 1 2

Pour les listes et tuple on utilisera *args, pour les dictionnaire on utilisera **

mylist = [1,2,3]
>>> foo(*mylist)
x=1
y=2
z=3

>>> mydict = {'x':1,'y':2,'z':3}
>>> foo(**mydict)
x=1
y=2
z=3

>>> mytuple = (1, 2, 3)
>>> foo(*mytuple)
x=1
y=2
z=3

Extended iterable unpacking

Une façon de faire de l’unpacking puissante

first, *rest = [1,2,3,4]
first,*l,last = [1,2,3,4]

Enfin un esyntaxe propre à Python 3 :

def mafonction(arg1,arg2,*,kwarg1,kwarg2):
    pass

La syntaxe ci-dessus impose que les deux premiers paramètres soient positionnel, et les paramètre après l’astérisque soient nommés.

https://stackoverflow.com/questions/36901/what-does-double-star-asterisk-and-star-asterisk-do-for-parameters

Python : tester si une variable est un nombre avec isdigit ()

Le problème de conversion d’une chaine en nombre entier

Lorsqu’on a une chaine de caractères qu’on cherche à convertir en nombre, il faut se poser la question de si c’est faisable.

Imaginons qu’on ait une variable à tester dont le type est un string :

ns = "125"
n = int(ns)

Mais si on a une chaine de caractère qui ne contient pas purement des chiffres (voire une chaine vide):

nm1 = "12.3"
nm2 = "z123"
nm3 = ""

Tenter de convertir ces chaines en entier déclenchera une erreur de type ValueError.

Tester si une chaine est un nombre entier avec isdigit()

En Python tout est objet, un nombre entier est un objet, un booléen est un objet, un float est un objet,(vous pouvez le voir en utilisant la notation pointée). Ces objets ont des méthodes (c’est le nom en OOP pour une fonction). Et dans le cas des chaines de caractères, uen de ces méthode est isdigit().

n = "123"
print(n.isdigit())  # True 
n = ""
print(n.isdigit())   # False
#on peut encore écrire
print("123".isdigit())  #True

Ainsi avant de convertir en entier, testez la chaine avec isdigit() avant d’utiliser int()

if("123".isdigit()):
    n = int("123")

Connexion à MySQL en Python

Installez au préalable Mysql, le plus rapide (avec zéro configuration ) étant d’installer la solution de développement PHP Laragon si vous êtes sous windows.

Ensuite il faudra redéfinir le mot de passe root, allez dans Laragon click droit sur le bouton Database > Mysql > Change root password.

Connexion à Mysql en Python

from mysql.connector import MySQLConnection, Error

def connect():
    """ Connect to MySQL database """
    conn = None
    try:
        conn = mysql.connector.connect(host='localhost',
                                       database='boutique',
                                       user='root',
                                       password='root')
        if conn.is_connected():
            print('Connected to MySQL database')

    except Error as e:
        print(e)

    finally:
        if conn is not None and conn.is_connected():
            conn.close()

if __name__ == '__main__':
    connect()

Exécuter une requête SQL en Python

from mysql.connector import MySQLConnection, Error

def query_with_fetchone():
    try:

        conn = MySQLConnection(host='localhost',
                                         database='boutique',
                                         user='root',
                                         password='root')
        cursor = conn.cursor()
        cursor.execute("SELECT * FROM staffs")

        row = cursor.fetchone()

        while row is not None:
            print(row)
            row = cursor.fetchone()

    except Error as e:
        print(e)

    finally:
        cursor.close()
        conn.close()


query_with_fetchone()

Connexion à Sqlite en Python

Sqlite est une base de donnée un peu spéciale, puisque la base tient dans un fichier binaire, avec extension .db, c’est donc quelque chose de très simple, et Sqlite est destiné à être utilisé sur des systèmes embarqués.

Donc pas besoin d’installer un programme, c’est la librairie Python qui va s’ocuper de cela. De plus c’est dans la librairie standard, ce qui veut dire que l’on n’ pas besoin de faire un pip install.

La librairie Python sqlite3

Il suffit tout simplement d’importer la librairie sqlite3, de créer une connexion pour créer le fichier binaire de la base de données

import sqlite3
from sqlite3 import Error


def create_connection(db_file):
    """ crée une connexion SQLite si lea DB n'existe pas elle sera créée"""
    conn = None
    try:
        conn = sqlite3.connect(db_file)
        print(sqlite3.version)
    except Error as e:
        print(e)
    finally:
        if conn:
            conn.close()


if __name__ == '__main__':
    create_connection(r"C:\db\pythonsqlite.db")

Sivous exécutez pour la première fois ce script, le fichier pythonslqite.db sera créé, par contre il vous faudra avoir le répertoire déjà créé, sinon vous aurez une erreur. Vous pouvez aussi créer une base de données avec DB Browser, un browser de base sqlite.

Requêter dans Sqlite en Python

Voici la recette pour faire une requête SQL en Python dans Sqlite. On acréé la base de données test.db, et il y a une table items. Vous pouvez importer dans DBBrowser le fichier contenant les données ci-dessous ou exécuter le SQL suivant :

BEGIN TRANSACTION;
CREATE TABLE IF NOT EXISTS "items" (
	"id"	INTEGER,
	"nom"	TEXT,
	"prix"	INTEGER
);
INSERT INTO "items" VALUES (1,'Pomme',5);
INSERT INTO "items" VALUES (1,'Poire',3);
INSERT INTO "items" VALUES (1,'raisin',13);
COMMIT;
import sqlite3
from sqlite3 import Error

def create_connection(db_file):
    conn = None
    try:
        conn = sqlite3.connect(db_file)
    except Error as e:
        print(e)

    return conn

def select_items(conn):
    """
    Query all rows in the tasks table
    :param conn: the Connection object
    :return:
    """
    cur = conn.cursor()
    cur.execute("SELECT * FROM items")

    rows = cur.fetchall()

    for row in rows:
        print(row)

db_file = "c:\\Users\\admin\\Documents\\test.db"
conn = create_connection(db_file)
select_items(conn)

Compréhension de liste en Python

Base de compréhension de liste

list = [i for i in range(5)]
print(list)  # [0,1,2,3,4]
list2 = [ i * i for i in range(10)]
print(list2) # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

If dans compréhension de liste

list3 = [ n for n in range(10) if n % 2 == 0]
print(list3) # [0, 2, 4, 6, 8]

If imbriqués
list4 = [ n for n in range(10) if n % 2 == 0 if n >= 5]
print(list4) # [6, 8]

If…Else dans compréhension de liste

list5 = ["Even" if i%2==0 else "Odd" for i in range(10)]
print(list5) #

list6 = [str(i) + ":Pair" if i%2==0 else str(i) + ":Impair" for i in range(10)]
print(list6) 
# ['0:Pair', '1:Impair', '2:Pair', '3:Impair', '4:Pair', '5:Impair', '6:Pair', '7:Impair', '8:Pair', '9:Impair']

csharp green logo

Conversion entre les bases

conversion HEX en décimal

Formule pour convertir un HEX en décimal:

C = 12 x 16^0

AB = 10 x 16^1 + 11 x 16^0 = 10 x 16 + 11 x 1 = 160 + 11 = 171

Comme A est en seconde position son poids est de 16^1, B ayant un poids de 16^0 qui équivaut à 1. La valeur de A est 10 en décimal, B vaut 11 en décimal.

Conversion décimal en HEX

Pour convertir un nombre décimal en HEX, il faut diviser par 16 plusieurs fois. Par exemple pour convertir 199 décimal en HEX:

Calcul de 199 modulo 16 = 7 (le reste de la division entière), le diviseur étant 12. 12 en HEX s’écrit C. Donc 119 en HEX s’écrit C7.

1ère étape : Calcul de 3999 modulo 16 = 15 soit F en HEX, le diviseur étant 249

2ème étape : Calcul de 249 moduleo 16 = 9 soit 9 en HEX, le diviseur étant 15 soit F en HEX.

conversion binaire en décimal

On regarde le poids n de chaque bit (position) on élève 2 à la puissance n, puis on multiplie par la valeur de la position, on somme les sous résultats obtenus pour avoir la valeur en décimal.

Ici on a 1 x 2^7 = 128, 1 x 2^5 = 32, 1 x 2^1 = 2

On somme le chiffres en gras et on obtient la valeur décimale correspondante.

Conversion décimal en binaire

C’est comme la manipulation pour convertir HEX en décimal, sauf qu’ici on divise par 2 au lieu de 16 et on regarde le reste.

Conversion de 112 en binaire

112 % 2 = 0 reste 56, 56 % 2 = 0 reste 28, 28 % 2 = 0 reste 14, 14 % 2 = 0 reste 7, 7 % 2 = 1 reste 3, 3 % 2 = 1 reste 1

En prenant les chiffres en gras de la fin vers le début, on obtient 1110000.

Lien vers un convertisseurs en ligne :

https://www.rapidtables.com/convert/number/decimal-to-binary.html

Attribut de classe et d’instance en Python

Attribut de classe

class Dog:
    leg_number = 4
    def __init__(self,name):
        self.name = name

chien1 = Dog("Médor")
print(chien1.leg_number)  # 4
print(Dog.leg_number)     # 4

Dans l’exemple ci-dessus leg_number est un attribut de classe. Pyton va chercher d’abord dans les attribut d’instance pour voir si leg_number existe, sinon va aller chercher dans les attributs de classe.

Attribut d’instance

name est un attribut d’instance car rattaché à self.

class Dog:
    leg_number = 4
    def __init__(self,name):
        self.name = name

chien1 = Dog("Médor")
print(chien1.name)  # Médor
print(Dog.name)     # AttributeError: type object 'Dog' has no attribute 'name'

Python ne trouvera pas name en attribut de classe. Par contre on peut surcharger name en attribut de classe.

class Dog:
    leg_number = 4
    name = "toto"
    def __init__(self,name):
        self.name = name

chien1 = Dog('médor')
print(chien1.name)   # médor
print(Dog.name)      # toto

Un attribut de classe est commun à tous les objets qui en dérivent.

class Dog:
    leg_number = 4
    def __init__(self,name):
        self.name = name

chien1 = Dog('médor')
chien2 = Dog('Lassie')
print(chien1.leg_number)
print(chien2.leg_number)
Dog.leg_number = 5
print(chien1.leg_number)
print(chien2.leg_number)

https://www.toptal.com/python/python-class-attributes-an-overly-thorough-guide

Héritage de classe dans Python

A première vue, les notions d’orienté objet sont simple en Python par rapport à Java, mais même si l’encapsulation ,n’existe pas en tant que tel (voir le mangling en Python), il y a beaucoup de choses à apprendre en héritage dans Python.

Il y a les fonctions magiques (avec le dunder) pour faire du polymorphisme et l’héritage multiple comme en C++ !

Classe et héritage simple

class Kite:
    def __init__(self,max_altitude):
        self.max_altitude = max_altitude
    def do(self):
        return "I fly"
    def getMaxAltitude(self):
        return self.max_altitude


class BigKite(Kite):
    def __init__(self,max_altitude,weight):
        self.max_altitude = max_altitude
        self.weight = weight
    def getWeight(self):
        return self.weight

Ici BigKite hérite de Kite, et la méthode de constructeur __init__ est surchargée. Si nous voulons utiliser le constructeur de la classe parente :

class Kite:
    def __init__(self,max_altitude):
        self.max_altitude = max_altitude
    def do(self):
        return "I fly"
    def getMaxAltitude(self):
        return self.max_altitude


class BigKite(Kite):
    def __init__(self,max_altitude,weight):
        super().__init__(max_altitude) #appel classe parente
        self.weight = weight
    def getWeight(self):
        return self.weight

On aurait pu écrire aussi :

super(Kite,self).__init__(max_altitude)

Héritage multiple

Ici KiteSurf hérite de la classe Kite et de la classe Surf, qui elles-même héritent de Object, on est ici en présence de diamond problem

class Object:
    def __init__(self):
        pass
    def do(self):
        return "I exist"


class Kite(Object):
    def __init__(self,max_altitude):
        self.max_altitude = max_altitude
    def do(self):
        return "I fly"
    def getMaxAltitude(self):
        return self.max_altitude


class Surf(Object):
    def __init__(self,matter):
        self.matter = matter
    def do(self):
        return "I surf"
    def getMaxAltitude(self):
        return self.max_altitude

class KiteSurf(Surf,Kite):
    def __init__(self):
        pass

ks = KiteSurf()
print(ks.do())

L’affichage de ks.do() méthode existant dans Kite et dans Surf dépend de l’ordre dans lequel est passé en paramètre les classes parentes.

https://he-arc.github.io/livre-python/super/index.html

Encapsulation dans les classes Python

Il n’existe pas de private ni de protected dans Python, la philosophie de Python est que le développeur est un être responsable.

Cependant Python supporte ce que l’on appelle le mangling.

class Dog:
    __init__(self):
        self.name = "Médor"
        self.__tatoo = "X312B13"

chien1 = Dog()
print(chien1.name) # Médor
print(chien1.__tatoo) # AttributeError: 'Dog' object has no attribute '__tatoo'

__tatoo a été substitué par un autre nom en vertu des deux underscores, on ne connait pas le nouveau nom, ce qui reproduit le process d’encapsulation.

javascript

Ecouter un événement de réponse AJAX

C’est quoi un événement en Javascript?

Un événement est par exemple un click de souris, une touche de clavier enfoncée, mais ça peut être purement logiciel, par exemple lorsque la page HTML a fini de se charger, il se produit un événement de type onload.

Un événement de requête AJAX

Ce type d’événement permet de détecter lorsqu’une requête AJAX est émise.

(function() {
    var origOpen = XMLHttpRequest.prototype.open;
    XMLHttpRequest.prototype.open = function() {
        console.log('request started!');
        this.addEventListener('load', function() {
            console.log('request completed!');
            console.log(this.readyState); //will always be 4 (ajax is completed successfully)
            var text = this.responseText
            toto = document.querySelector('#toto')
            toto.innerHTML = toto.innerHTML + text

        });
        origOpen.apply(this, arguments);
    };
})();
php

Débugger sous VSCode en PHP

Il vous faut installer le plugin PHP Debugger de Felix Becker

Configurez XDebug dans le php.ini comme d’habitude (PHPstorm)

Cliquez sur Listen for XDebug

Mettez un breakpoint où vous voulez et lancez la page web.

Pour Débugger avec le serveur interne de PHP

zend_extension = C:\laragon\bin\php\php-7.2.19-Win32-VC15-x64\ext\php_xdebug-2.6.1-7.2-vc15-x86_64.dll
[xdebug]
xdebug.remote_enable = 1
xdebug.profiler_enable = off
xdebug.profiler_enable_trigger = 1
xdebug.remote_port=9000
xdebug.remote_handler=dbgp
xdebug.profiler_output_name = "cachegrind.out.%u.%H.%R"
xdebug.profiler_output_dir = "c:/laragon/tmp"
xdebug.show_local_vars=0
xdebug.remote_autostart=1

Il faut mettre dans le php.ini la configuration suivante pour Xdebug en plus :

xdebug.remote_autostart=1
javascript

Javascript import et symbole @

Vous avez sans doute souvent vu dans un script javascript moderne ceci:

import Component from '@/components/component'

Normalement si on veut importer un module Javascript, il faut utiliser les / et les .. soit pour remonter d’un niveau soit pour descendre d’un niveau, comme on le ferait dans n’importe quel langage de programmation.

Cette notation n’est pas du Javascript natif, elle est rendue possible par l’utilisation d’un plugin de type module loader ou module bundler.

C’est un plugin comme babel plugin root import, qui permet d’avoir cette syntaxe. Mais de quel root? le root du projet javascript en question. Ainsi quelque soit l’emplacement du plugin et de la page qui demande le plugin, on utilisera l’arobase pour atteindre un plugin comme si on le demandait depuis la racine du projet.

Cela permet d’éviter que la syntaxe suivante :

import Component from 'components/component'

Dans ce cas ça va chercher dans /node_modules.

Si on cherche un module dans le projet

import Component from './components/component'

Mécanisme de session de Django

Similaire aux sessions en PHP, dans Django il faut importer deux lignes pour pouvoir travailler avec les sessions:

#settings
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions', // le module Session
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'products.apps.ProductsConfig'
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware', // le middleware
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

Avec Django par défaut les sessions sont sauvées dans la base de données.

Les formulaires dans Django

Les formulaires sont un vaste chapitre comme dans tout framework web quelque soit le langage. Mais Django permet de les manipuler plus facilement que Symfony par exemple.

cleaned_data qu’est ce que c’est?

Il y a deux types de formulaire dans Django, les formulaires classiques qui héritent de forms.Form, et mes formulaires liés à des entités, qui héritent de forms.ModelForm.

Avec les modelForm, inutile de s’inquiéter du cleaned_data.

Dans un form classique on doit utiliser les données validée:
if form.is_valid():
    ex = Example()
    ex.username = form.cleaned_data['username']
    ex.save()

Alors que dans un modelForm, cette étape est automatique.

if form.is_valid():
    form.save()

https://stackoverflow.com/questions/53594745/what-is-the-use-of-cleaned-data-in-django

Upload de fichiers dans Django

Pour uploader un fichier dans un formulaire, il faut modifier le model,

class Product(models.Model):
    name = models.CharField(max_length=50)
    price = models.FloatField()
    stock = models.IntegerField()
    image = models.CharfieldField(max_length=1000)

class Product(models.Model):
    name = models.CharField(max_length=50)
    price = models.FloatField()
    stock = models.IntegerField()
    image = models.FileField()

Après avoir changé la propriété dans le model, il faut faire une migration

python manage.py makemigrations products  #le nom de l'app
python manage.py migrate

Ensuite il faut faire quelques modification de code, dans le settings.py de votre projet :

#monprojet\settings.py
MEDIA_ROOT = os.path.join(BASE_DIR,'media')
MEDIA_URL = '/media/'

#monprojet\urls.py
from django.contrib import admin
from django.urls import path, include

from django.conf import settings
from django.conf.urls.static import static

urlpatterns = [
    path('admin/', admin.site.urls),
    path('products/', include('products.urls'))
]

if settings.DEBUG:
    urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
    urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

php

Doctrine et ses 4 façons de requêter la base de données

DQL Doctrine Query Langage

$query = $this->em->createQuery(
    "
    SELECT p
    FROM AppBundle\Entity\RedditPost p
    WHERE p.id > :id
    "
)->setParameter('id', 50);

$data = $query->getResult();

Mais on ne peut splitter la requête simplement, alors qu’avec le query builder c’est possible:

// it is still DQL, but now it is painful

var $someConditional = false;

if ($someConditional === true) {
    $query = $this->em->createQuery(
        "
        SELECT p
        FROM AppBundle\Entity\RedditPost p
        WHERE p.id > :id
        "
    )->setParameter('id', 50);
} else {
    $query = $this->em->createQuery(
    "
        SELECT p
        FROM AppBundle\Entity\RedditPost p
    "
    );
}

$data = $query->getResult();

Query Builder

C’est mieux avec le query builder, plus facile de paramétrer sa requête, tout est à base de méthode objet.

// using Doctrine's Query Builder

var $someConditional = false;

$query = $this->getDoctrine()->getRepository('AppBundle:RedditPost')->createQueryBuilder('p');

if ($someConditional === true) {
    $query
        ->where('p.id > :id')
        ->setParameter('id', 50)
    ;
} 

$data = $query->getQuery()->getResult();

https://codereviewvideos.com/course/doctrine-databasics/video/dql-vs-doctrine-query-builder

$query = $this->getDoctrine()
    ->getRepository('AppBundle:RedditPost')
    ->createQueryBuilder('p')

createQueryBuilder('p') implicitly creates the equivalent:

    SELECT p
    FROM AppBundle\Entity\RedditPost p

C’est la raison pour laquelle on n’a pas besoin de SELECT et FROM explicite

Native Query

Ressemble beaucoup au SQL, la notion de resultSetMapping est centrale.

use Doctrine\ORM\Query\ResultSetMapping;

$rsm = new ResultSetMapping();
// build rsm here

$query = $entityManager->createNativeQuery('SELECT id, name, discr FROM users WHERE name = ?', $rsm);
$query->setParameter(1, 'romanb');

$users = $query->getResult();

https://www.doctrine-project.org/projects/doctrine-orm/en/2.7/reference/native-sql.html

On peut utiliser le resultSetMappingBuilder pour construire des requêtes Native Query

use Doctrine\ORM\Query\ResultSetMappingBuilder;

$sql = "SELECT u.id, u.name, a.id AS address_id, a.street, a.city " . 
       "FROM users u INNER JOIN address a ON u.address_id = a.id";

$rsm = new ResultSetMappingBuilder($entityManager);
$rsm->addRootEntityFromClassMetadata('MyProject\User', 'u');
$rsm->addJoinedEntityFromClassMetadata('MyProject\Address', 'a', 'u', 'address', array('id' => 'address_id'));

Raw SQL

On met du pur SQL dans un repository Doctrine

    public function getEvoplusStatusCountByMonthByCommercial(int $idUser, $start, $end)
    {
        $conn = $this->getEntityManager()->getConnection();

        $sql = "select count(*) as count, M.ID_ETAT_MATRICE, EM.LIBELLE_ETAT_MATRICE from MATRICE M 
inner join ETAT_MATRICE EM on 
M.ID_ETAT_MATRICE = EM.ID_ETAT_MATRICE 
where 
CONTRAT_DATE_SIGNATURE BETWEEN '$start' AND '$end'
AND USR_ID = $idUser GROUP by M.ID_ETAT_MATRICE; ";

        $stmt = $conn->prepare($sql);
        $stmt->execute();
        $res = $stmt->fetchAll();

        return $res;
    }

Cette méthode est ma préférée, vou sl’aurez compris je ne suis pas un fan des ORM, c’est tellement plus facile de faire des requêtes SQL, et tant pis si on n’a pas d’objet en résultat, manipuler des tableaux associatifs n’est pas si difficile.

Introduction à Jupyter Notebook

Jupyter Notebook est une interface web pour faire de la datascience, vous exécutez vos scnippet Python dans ce qu’on appelle des cells, des unités d’exécution.

Pour l’installer, voici la procédure :

Installation des librairies

pip install pandas
pip install numpy
pip install matplotlib
pip install xlrd

Installation de Jupyter Notebook

pip install notebook

#démarrer notebook
jupyter notebook

Vous pouvez installer d’abord Jupyter Notebook et installer les librairies depuis Jupyter Notebook

!pip install pandas 

le ! permet d'accéder au shell.

Afficher les log server dans Python Django

Il est pratique de logger en mode développement les requêtes servies par le serveur de Python

dans le fichier settings.py de votre projet mettez ce code juste après le DEBUG = true

if DEBUG:
    # will output to your console
    logging.basicConfig(
        level = logging.DEBUG,
        format = '%(asctime)s %(levelname)s %(message)s',
    )
else:
    # will output to logging file
    logging.basicConfig(
        level = logging.DEBUG,
        format = '%(asctime)s %(levelname)s %(message)s',
        filename = '/my_log_file.log',
        filemode = 'a'
    )

https://stackoverflow.com/questions/4558879/python-django-log-to-console-under-runserver-log-to-file-under-apache

Comprendre le mot clé with en Python

La syntaxe en Python de with est assez étrange, quel problème essait-il de résoudre?

with est utilisé lorsqu’on travaille avec des ressources non managées, notamment ouverture d’une fichier. Avant on utilisait try...catch,

    set things up
    try:
        do something
    finally:
        tear things down

Syntaxe basique de with

with expression [as variable]:
    with-block

L’expression est évaluée, et retourne un objet qui implémente le context management protocol, c’est à dire qui possède les méthodes __enter__() et __exit__()

with open('text.txt','w') as fichier
    fichier.write('Hello')

Avec cette syntaxe pas besoin de fermer explicitement le fichier, c’est automatique.

Retour en haut