IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Vous êtes nouveau sur Developpez.com ? Créez votre compte ou connectez-vous afin de pouvoir participer !

Vous devez avoir un compte Developpez.com et être connecté pour pouvoir participer aux discussions.

Vous n'avez pas encore de compte Developpez.com ? Créez-en un en quelques instants, c'est entièrement gratuit !

Si vous disposez déjà d'un compte et qu'il est bien activé, connectez-vous à l'aide du formulaire ci-dessous.

Identifiez-vous
Identifiant
Mot de passe
Mot de passe oublié ?
Créer un compte

L'inscription est gratuite et ne vous prendra que quelques instants !

Je m'inscris !

Python - Apprendre à planifier les disponibilités de véhicules de location à partir de données extraites d'un fichier Excel,
Un billet blog de Denis Hulo

Le , par User

0PARTAGES

I. Introduction

Dans une agence de location de véhicules on souhaite connaître leur disponibilité dans le futur en fonction des locations déjà programmées.


L'objectif de ce billet est en fait de planifier les disponibilités des véhicules à partir de données enregistrées dans un fichier Excel ou dans des tables SQLite.

Cette opération sera réalisée en 3 étapes principales :

  1. importation des données externes dans des listes de dictionnaires ;
  2. génération des disponibilités en fonction de la période et du modèle ou du type de véhicule choisis ;
  3. exportation de la liste des disponibilités dans une feuille Excel.


II. Données externes

Dans notre cas, les données sont enregistrées dans des feuilles Excel ou dans des tables SQLite.

II-A. Fichier contenant les données sur les véhicules

Structure du fichier :



Aperçu du contenu de la feuille Excel :



II-B. Fichier contenant les données sur les locations de véhicules

Structure du fichier source :



Aperçu du contenu de la feuille Excel :



Note importante : pour simplifier, on garde uniquement les colonnes essentielles et on affiche le nom du client et le numéro de véhicule au lieu des identifiants pour savoir directement qui loue le véhicule.

Comme on le verra plus loin, on peut également extraire ces informations d'une base de données SQLite.

III. Module openpyxl

Il permet de lire et d'écrire dans des feuilles de fichiers Excel au format xlsx ou xlsm.

III-A. Installation

Pour installer la librairie exécutez simplement la commande :

pip install openpyxl

C'est plus simple qu'avec pandas.

III-B. Code exemple

On donne ici quelques lignes de code prises dans la documentation pour mieux comprendre comment utiliser openpyxl :

Code Python : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from openpyxl import Workbook 
  
wb = Workbook() 
  
# pointe sur la feuille active 
ws = wb.active 
  
# copie la valeur 42 dans la cellule A1 
ws['A1'] = 42 
  
# ajout d'une ligne à la feuille 
ws.append([1, 2, 3]) 
  
# copie la date et l'heure actuelle dans la cellule A2 
import datetime 
ws['A2'] = datetime.datetime.now() 
  
# sauvegarde du fichier 
wb.save("sample.xlsx")

Autre exemple, pour lire le contenu d'une cellule Excel :

Code Python : Sélectionner tout
var = ws['A1']

Permet de copier le contenu de la cellule A1 de la feuille ws dans la variable var.

Equivalent à :

Code Python : Sélectionner tout
var = ws.cell(row = 1, column = 1).value

On peut donc lire et écrire dans des cellules précises et sur des lignes ou des colonnes pas forcément adjacentes, ce qui n'est pas vraiment possible avec pandas.

Si vous souhaitez avoir plus d'information sur ce module je vous invite à consulter ce tutoriel.

Note importante : on donnera en complément pour chacune des fonctions utilisant openpyxl le code équivalent avec pandas.

IV. Importation des données dans des listes de dictionnaires

IV-A. Fichier Excel

On récupère les données des deux feuilles Excel dans des listes Python à l'aide du module openpyxl :

Code Python : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
from openpyxl import load_workbook # module utilisé pour lire le contenu du fichier xlsx 
  
def importer_feuille(ws): 
    # lecture et importation des données de la feuille ws dans une liste de dicos 
  
    # initialisation de la liste des dictionnaires 
    liste_dicos=[] 
  
    # mémorisation des indices maxi. de ligne et de colonne  
    ligne_max = ws.max_row 
    col_max = ws.max_column 
  
    # parcours les lignes de la feuille Excel en commençant par la 2e ligne 
    for i in range(2, ligne_max + 1): 
        dico = {} # initialisation du dico 
        # parcours des colonnes de la feuille 
        for j in range(1, col_max + 1): 
            # copie de la valeur associée à la clé dans le dictionnaire : vehicule['id_vehicule'] = ws.cell(row = i, column = 1) 
            cle = ws.cell(row = 1, column = j).value 
            dico[cle] = ws.cell(row = i, column = j).value 
  
        # ajout du dico à la liste 
        liste_dicos.append(dico) 
  
    return liste_dicos # retourne la liste des dicos 
  
def importer_donnees(chemin_fichier): 
    # importe les données sur les véhicules et les locations qui sont contenues dans le fichier Excel 
  
    # ouverture du classeur dont l'emplacement est passé en argument 
    wb = load_workbook(chemin_fichier) 
  
    # on pointe sur la feuille vehicules 
    ws = wb["vehicules"] 
  
    # récupération dans une liste des données de la feuille vehicules 
    liste_vehicules = importer_feuille(ws) 
  
    # on pointe maintenant sur la feuille locations_vehicules 
    ws = wb["locations_vehicules"] 
  
    # récupération dans une liste des données de la feuille locations_vehicules 
    liste_locations = importer_feuille(ws) 
  
    return (liste_vehicules,liste_locations) # renvoi des 2 listes de dicos

Fonction équivalente avec pandas :

Code Python : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import pandas 
  
def importer_donnees(chemin_fichier): 
    # importe les données sur les véhicules et les locations qui sont contenues dans le fichier Excel     
  
    # lecture et importation du contenu de la feuille vehicules dans un DataFrame 
    df = pandas.read_excel(chemin_fichier, sheet_name="vehicules") 
    # transformation du DataFrame en liste de dictionnaires 
    liste_vehicules = df.to_dict('records') 
  
    # lecture et importation du contenu de la feuille locations_vehicules dans un DataFrame 
    df = pandas.read_excel(chemin_fichier, sheet_name="locations_vehicules") 
    # transformation du DataFrame en liste de dictionnaires 
    liste_locations = df.to_dict('records') 
  
    return (liste_vehicules,liste_locations) # renvoi des 2 listes de dicos


IV-B. Base de données SQLite

On peut également extraire les données de tables SQLite à l'aide de la librairie sqlite3 :

Code Python : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
import sqlite3 
from sqlite3 import Error 
  
def create_connection(db_file): 
    """ crée une connexion à la base de données SQLite 
        specifié par le chemin du fichier passé en argument 
    :param db_file: chemin du fichier db 
    :return: un objet connexion ou renvoie none 
    """ 
    conn = None 
    try: 
        conn = sqlite3.connect(db_file) # on crée l'objet connexion 
        return conn 
    except Error as e: # gestion de l'erreur 
        print(e) # affichage du message d'erreur 
  
    return conn 
  
def importer_table(connexion, nom_table, liste_cles): 
    # importation des données de la table dans une liste de dicos  
  
    cur = connexion.cursor() 
  
    cur.execute("select * from " + nom_table) 
  
    # initialise la liste qui contiendra les données de la table 
    liste_dicos=[] 
  
    # récupère le contenu de la table dans une liste 
    liste_donnees = cur.fetchall() 
  
    # parcours de la liste contenant les lignes de la table 
    for row in liste_donnees: 
        # initialisation du dico et de l'indice de colonne 
        dico = {}; j=0 
  
        # copie des données de la ligne dans un dictionnaire 
        for cle in liste_cles: 
            dico[cle]= row[j] 
            j+=1 # incrémentation de l'indice de colonne 
  
        # ajout du dictionnaire à la liste 
        liste_dicos.append(dico) 
  
    return liste_dicos # renvoi la liste de dicos 
  
  
def importer_donnees(): 
    # importe les données sur les véhicules et les locations qui sont contenues dans les tables SQLite 
  
    database = r"C:\sqlite\db\locations.db" # chemin de la base de données 
  
    # création de la connexion à la base de données SQLite 
    conn = create_connection(database) 
  
    # si la connexion a été réalisée 
    if conn is not None: 
  
        # création de la liste des clés des dicos pour les véhicules 
        liste_cles = ['id_vehicule','num_vehicule', 'modele_vehicule','type_vehicule','marque'] 
  
        # récupération des données de la table vehicules dans une liste 
        liste_vehicules = importer_table(conn, 'vehicules', liste_cles) 
  
        # création de la liste des clés des dicos pour les locations 
        liste_cles = ['id_location','num_vehicule', 'client','debut_loc','fin_loc'] 
  
        # récupération des données de la table locations_vehicules dans une liste 
        liste_locations = importer_table(conn, 'locations_vehicules', liste_cles) 
  
        return (liste_vehicules, liste_locations) # renvoi les 2 listes de dicos 
  
    else: 
        print("Erreur! impossible de créer la connexion à la base !")

Résultat obtenu pour les locations :

Code Javascript : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
[ 
    { 
        "id_location": 1, 
        "num_vehicule": "AA-016-AA", 
        "client": "BONNEMAISON", 
        "debut_loc": datetime.datetime(2023,3,14,15,0), 
        "fin_loc": datetime.datetime(2023,4,14,15,0) 
    }, 
    { 
        "id_location": 2, 
        "num_vehicule": "AA-007-AA", 
        "client": "BONNEMAISON", 
        "debut_loc": datetime.datetime(2023,4,3,12,0), 
        "fin_loc": datetime.datetime(2023,5,3,12,0) 
    }, 
    { 
        "id_location": 3, 
        "num_vehicule": "AA-008-AA", 
        "client": "CESARO", 
        "debut_loc": datetime.datetime(2023,4,24,12,0), 
        "fin_loc": datetime.datetime(2023,5,24,12,0) 
    }, 
    ... 
]


Note importante : l'utilisation de dictionnaires va nous aider par la suite à identifier chaque colonne dans le code Python.

V. Génération de la liste des disponibilités des véhicules

Si on souhaite par exemple connaître les disponibilités du modèle Nissan Qashqai entre le 01/03/2023 12:00 et le 30/06/2023 12:00 :



On voit sur le planning précédent que l'on peut ainsi obtenir les disponibilités des véhicules à partir des locations déjà enregistrées :



Cette opération sera réalisée par la suite à l'aide de deux fonctions Python.

V-A. Génération des disponibilités pour un véhicule

La fonction generer_disponibilites_vehicule va permettre de déterminer les périodes de disponibilité pour chaque véhicule.

Arguments de la fonction :

  • liste_locations : liste des locations de véhicules pris en compte dans la période (liste de dictionnaires) ;
  • debut_periode : date et heure de début de la période de recherche ;
  • fin_periode : date et heure de fin de la période de recherche ;
  • num_vehicule : numéro du véhicule recherché ;
  • modele_vehicule : modèle de véhicule recherché ;
  • type_vehicule : type de véhicule pris en compte.


Déroulé de la fonction :

  • 1. filtrage des locations par numéro de véhicule ;
  • 2. parcours de la liste des locations du véhicule ;
  • --- 2.1. pour chaque location du véhicule, évaluation de la période de disponibilité correspondante ;
  • --- 2.2. pour chaque location du véhicule, ajout de la période de disponibilité à la liste ;
  • 3. renvoi de la liste des disponibilités du véhicule.


Code Python : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
def generer_disponibilites_vehicule(liste_locations, debut_periode, fin_periode, num_vehicule, modele_vehicule, type_vehicule): 
    # génère la liste des dispos du véhicule 
  
    # filtre de la liste des locations par numéro de véhicule 
    liste_locations_vehicule = [loc for loc in liste_locations if (loc['num_vehicule']==num_vehicule)] 
  
    liste_dispos = [] 
  
    # tri de la liste des locations du véhicule par date de début de location 
    liste_locations_vehicule = sorted(liste_locations_vehicule, key=lambda k: (k['debut_loc'])) 
  
    # on initialise les dates de début et de fin de disponibilité du véhicule avec les dates de début et de fin de la période choisie 
    debut_dispo = debut_periode 
    fin_dispo = fin_periode 
  
    # parcours de la liste des locations du véhicule 
    for loc in liste_locations_vehicule: 
  
        # si la date de début de location est comprise dans la période [debut_dispo, fin_dispo] 
        if (debut_dispo<loc['debut_loc']) and (loc['debut_loc']<fin_dispo): 
            # on ajoute le véhicule à la liste avec ses dates de début et de fin de disponibilité 
            ajouter_dispo(liste_dispos, num_vehicule, modele_vehicule, type_vehicule, debut_dispo, loc['debut_loc']) 
  
        # on mémorise la date de fin de location comme date de début de dispo. pour la prochaine location 
        debut_dispo = loc['fin_loc'] 
  
    if (debut_dispo < fin_dispo): # si debut_dispo < fin_dispo alors il faut ajouter une période supplémentaire à la liste 
        # ajout du véhicule à la liste avec ses dates de début et de fin de disponibilité 
        ajouter_dispo(liste_dispos, num_vehicule, modele_vehicule, type_vehicule, debut_dispo, fin_dispo) 
  
    return liste_dispos # renvoi la liste des dispo. 
  
  
def ajouter_dispo(liste_dispos, num_vehicule, modele_vehicule, type_vehicule, debut_dispo, fin_dispo): 
  
    # création du dico contenant les références du véhicule avec ses dates de début et de fin de disponibilité 
    dispo_vehicule={'num_vehicule': num_vehicule, 'modele_vehicule': modele_vehicule,'type_vehicule': type_vehicule, 
                    'debut_dispo': debut_dispo,'fin_dispo': fin_dispo} 
  
    # ajout du dico à la liste des disponibilités 
    liste_dispos.append(dispo_vehicule)


V-B. Génération des disponibilités pour un modèle ou un type de véhicule

La fonction generer_disponibilites va permettre de générer la liste des disponibilités pour un modèle ou un type de véhicule et pour la période choisie.

Arguments de la fonction :

  • liste_vehicules : liste des véhicules (liste de dictionnaires) ;
  • liste_locations : liste des locations de véhicules (liste de dictionnaires) ;
  • debut_periode : date et heure de début de la période de recherche ;
  • fin_periode : date et heure de fin de la période de recherche ;
  • modele_vehicule : modèle de véhicule recherché (argument optionnel) ;
  • type_vehicule : type de véhicule pris en compte (argument optionnel).


Déroulé de la fonction :

  • 1. filtrage des locations par modèle ou type de véhicule et par période de recherche ;
  • 2. parcours de la liste des numéros de véhicules ;
  • --- 2.1. pour chaque numéro, évaluation des périodes de disponibilité ;
  • --- 2.2. pour chaque numéro, ajout des périodes à la liste des disponibilités ;
  • 3. renvoi de la liste des disponibilités.


Code Python : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
def generer_disponibilites(liste_vehicules, liste_locations, debut_periode, fin_periode, modele_vehicule='', type_vehicule=''): 
    # génère la liste des dispos pour la période et le modèle ou le type de véhicule choisis 
  
    # génère la liste des véhicules par modèle ou type 
    # on utilise la fonction lower() dans les conditions pour convertir les deux chaînes de caractères en minuscules et ainsi rendre leur comparaison insensible à la casse. 
    if modele_vehicule!='': # si un modèle est choisi 
        liste_vehicules = [vehicule for vehicule in liste_vehicules if (vehicule['modele_vehicule'].lower() == modele_vehicule.lower())] 
    else: 
        if type_vehicule!='': # si un type de véhicule est choisie 
            liste_vehicules = [vehicule for vehicule in liste_vehicules if (vehicule['type_vehicule'].lower() == type_vehicule.lower())] 
        else: 
            print("Chosir un modèle ou une type de véhicule !") 
  
    # tri de la liste de véhicules par type, modèle et numéro 
    liste_vehicules = sorted(liste_vehicules, key=lambda k: (k['type_vehicule'], k['modele_vehicule'], k['num_vehicule'])) 
  
    # initialise la liste des disponibilités 
    liste_dispos = [] 
  
    # filtre de la liste des locations en fonction de la période choisie 
    liste_locations = [loc for loc in liste_locations if (loc['fin_loc']>debut_periode) and (loc['debut_loc']<fin_periode)] 
  
    # parcours de la liste 
    for vehicule in liste_vehicules: 
        # création de la liste des disponibilités pour le véhicule 
        liste_dispos_vehicule = generer_disponibilites_vehicule(liste_locations, debut_periode, fin_periode,  
                                                                num_vehicule=vehicule['num_vehicule'], modele_vehicule=vehicule['modele_vehicule'], type_vehicule=vehicule['type_vehicule']) 
        liste_dispos = liste_dispos + liste_dispos_vehicule # ajout à liste_dispos 
  
    return liste_dispos # renvoi la liste des disponibilités


Elle renvoie une liste de dictionnaires de la forme :

Code Javascript : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
[ 
   { 
      "num_vehicule":"AA-007-AA", 
      "modele_vehicule":"Nissan Qashqai", 
      "type_vehicule":"SUV", 
      "debut_dispo":datetime.datetime(2023,3,1,12,0), 
      "fin_dispo":datetime.datetime(2023,4,3,12,0) 
   }, 
   { 
      "num_vehicule":"AA-007-AA", 
      "modele_vehicule":"Nissan Qashqai", 
      "type_vehicule":"SUV", 
      "debut_dispo":datetime.datetime(2023,5,3,12,0), 
      "fin_dispo":datetime.datetime(2023,6,30,12,0) 
   }, 
   { 
      "num_vehicule":"AA-008-AA", 
      "modele_vehicule":"Nissan Qashqai", 
      "type_vehicule":"SUV", 
      "debut_dispo":datetime.datetime(2023,3,1,12,0), 
      "fin_dispo":datetime.datetime(2023,4,24,12,0) 
   }, 
   ... 
]


VI. Exportation de la liste de dictionnaires dans une feuille Excel

On exporte ensuite la liste obtenue dans une feuille Excel à l'aide de cette fonction :

Code Python : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
def exporter_dispos(chemin_fichier, nom_feuille, liste_dispos): 
    # exporte les disponibilités dans une feuille du fichier Excel 
  
    # création d'un objet Workbook 
    wb = Workbook() 
  
    # pointe sur la feuille active 
    ws = wb.active 
  
    # renomme la feuille active 
    ws.title = nom_feuille 
  
    # récupération des clés du dictionnaire 
    liste_cles = list(liste_dispos[0].keys()) 
  
    # mise à jour des entêtes de colonne de la feuille : 1re ligne 
    ws.append(liste_cles) 
  
    # parcours de la liste des dispos 
    for dispo in liste_dispos: 
        liste_valeurs = list(dispo.values()) # liste de valeurs du dictionnaire 
        # ajout d'une ligne de valeurs 
        ws.append(liste_valeurs) 
  
    # sauvegarde du classeur 
    wb.save(chemin_fichier)

On utilise à nouveau le module openpyxl mais cette fois-ci pour copier les données dans une feuille Excel.

Fonction équivalente avec pandas :

Code Python : Sélectionner tout
1
2
3
4
5
6
7
8
9
import pandas 
  
def exporter_dispos(chemin_fichier, nom_feuille, liste_dispos): 
    # exporte les disponibilités dans une feuille du fichier Excel 
  
    # conversion de la liste de dicos en DataFrame 
    df = pandas.DataFrame(liste_dispos) 
    # copie du DataFrame dans une feuille du fichier Excel 
    df.to_excel(chemin_fichier, sheet_name= nom_feuille)

Résultat obtenu :



VII. Module complet de test

Finalement, nous donnons le module complet contenant les fonctions permettant de générer la liste des disponibilités :

Code Python : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
from openpyxl import load_workbook # module openpyxl utilisé pour lire et écrire dans un fichier xlsx 
from openpyxl import Workbook # --- 
from datetime import datetime 
import os 
#import pandas 
  
def importer_feuille(ws): 
    # lecture et importation des données de la feuille ws dans une liste de dicos 
  
    # initialisation de la liste des dictionnaires 
    liste_dicos=[] 
  
    # mémorisation des indices maxi. de ligne et de colonne  
    ligne_max = ws.max_row 
    col_max = ws.max_column 
  
    # parcours les lignes de la feuille Excel en commençant par la 2e ligne 
    for i in range(2, ligne_max + 1): 
        dico = {} # initialisation du dico 
        # parcours des colonnes de la feuille 
        for j in range(1, col_max + 1): 
            # copie de la valeur associée à la clé dans le dictionnaire : vehicule['id_vehicule'] = ws.cell(row = i, column = 1) 
            cle = ws.cell(row = 1, column = j).value 
            dico[cle] = ws.cell(row = i, column = j).value 
  
        # ajout du dico à la liste 
        liste_dicos.append(dico) 
  
    return liste_dicos # retourne la liste des dicos 
  
  
def importer_donnees(chemin_fichier): 
    # importe les données sur les véhicules et les locations qui sont contenues dans le fichier Excel 
  
    # ouverture du classeur dont l'emplacement est passé en argument 
    wb = load_workbook(chemin_fichier) 
  
    # on pointe sur la feuille vehicules 
    ws = wb["vehicules"] 
  
    # récupération dans une liste des données de la feuille vehicules 
    liste_vehicules = importer_feuille(ws) 
  
    # on pointe maintenant sur la feuille locations_vehicules 
    ws = wb["locations_vehicules"] 
  
    # récupération dans une liste des données de la feuille locations_vehicules 
    liste_locations = importer_feuille(ws) 
  
    return (liste_vehicules,liste_locations) # renvoi des 2 listes de dicos 
  
  
def importer_donnees_v2(chemin_fichier): 
    # importe les données sur les véhicules et les locations qui sont contenues dans le fichier Excel 
  
    # lecture et importation du contenu de la feuille vehicules dans un DataFrame 
    df = pandas.read_excel(chemin_fichier, sheet_name="vehicules") 
    # transformation du DataFrame en liste de dictionnaires 
    liste_vehicules = df.to_dict('records') 
  
    # lecture et importation du contenu de la feuille locations_vehicules dans un DataFrame 
    df = pandas.read_excel(chemin_fichier, sheet_name="locations_vehicules") 
    # transformation du DataFrame en liste de dictionnaires 
    liste_locations = df.to_dict('records') 
  
    return (liste_vehicules,liste_locations) # renvoi des 2 listes de dicos 
  
  
def exporter_dispos(chemin_fichier, nom_feuille, liste_dispos): 
    # exporte les disponibilités dans une feuille du fichier Excel 
  
    # création d'un objet Workbook 
    wb = Workbook() 
  
    # pointe sur la feuille active 
    ws = wb.active 
  
    # renomme la feuille active 
    ws.title = nom_feuille 
  
    # récupération des clés du dictionnaire 
    liste_cles = list(liste_dispos[0].keys()) 
  
    # mise à jour des entêtes de colonne de la feuille : 1re ligne 
    ws.append(liste_cles) 
  
    # parcours de la liste des dispos 
    for dispo in liste_dispos: 
        liste_valeurs = list(dispo.values()) # liste de valeurs du dictionnaire 
        # ajout d'une ligne de valeurs 
        ws.append(liste_valeurs) 
  
    # sauvegarde du classeur 
    wb.save(chemin_fichier) 
  
def exporter_dispos_v2(chemin_fichier, nom_feuille, liste_dispos): 
    # exporte les disponibilités dans une feuille du fichier Excel 
  
    # conversion de la liste de dicos en DataFrame 
    df = pandas.DataFrame(liste_dispos) 
    # copie du DataFrame dans une feuille du fichier Excel 
    df.to_excel(chemin_fichier, sheet_name= nom_feuille) 
  
  
def generer_disponibilites_vehicule(liste_locations, debut_periode, fin_periode, num_vehicule, modele_vehicule, type_vehicule): 
    # génère la liste des dispos du véhicule 
  
    # filtre de la liste des locations par numéro de véhicule 
    liste_locations_vehicule = [loc for loc in liste_locations if (loc['num_vehicule']==num_vehicule)] 
  
    liste_dispos = [] 
  
    # tri de la liste des locations du véhicule par date de début de location 
    liste_locations_vehicule = sorted(liste_locations_vehicule, key=lambda k: (k['debut_loc'])) 
  
    # on initialise les dates de début et de fin de disponibilité du véhicule avec les dates de début et de fin de la période choisie 
    debut_dispo = debut_periode 
    fin_dispo = fin_periode 
  
    # parcours de la liste des locations du véhicule 
    for loc in liste_locations_vehicule: 
        # si la date de début de location est comprise dans la période [debut_dispo, fin_dispo] 
        if (debut_dispo<loc['debut_loc']) and (loc['debut_loc']<fin_dispo): 
            # on ajoute le véhicule à la liste avec ses dates de début et de fin de disponibilité 
            ajouter_dispo(liste_dispos, num_vehicule, modele_vehicule, type_vehicule, debut_dispo, loc['debut_loc']) 
  
        # on mémorise la date de fin de location comme date de début de dispo. pour la prochaine location 
        debut_dispo = loc['fin_loc'] 
  
  
    if (debut_dispo < fin_dispo): # si debut_dispo < fin_dispo alors il faut ajouter une période supplémentaire à la liste 
        # ajout du véhicule à la liste avec ses dates de début et de fin de disponibilité 
        ajouter_dispo(liste_dispos, num_vehicule, modele_vehicule, type_vehicule, debut_dispo, fin_dispo) 
  
    return liste_dispos # renvoi la liste des dispo. 
  
  
def ajouter_dispo(liste_dispos, num_vehicule, modele_vehicule, type_vehicule, debut_dispo, fin_dispo): 
  
    # création du dico contenant les références du véhicule avec ses dates de début et de fin de disponibilité 
    dispo_vehicule={'num_vehicule': num_vehicule, 'modele_vehicule': modele_vehicule,'type_vehicule': type_vehicule, 
                    'debut_dispo': debut_dispo,'fin_dispo': fin_dispo} 
  
    # ajout du dico à la liste des disponibilités 
    liste_dispos.append(dispo_vehicule) 
  
  
def generer_disponibilites(liste_vehicules, liste_locations, debut_periode, fin_periode, modele_vehicule='', type_vehicule=''): 
    # génère la liste des dispos pour la période et le modèle ou le type de véhicule choisis 
  
    # génère la liste des véhicules par modèle ou type 
    # on utilise la fonction lower() dans les conditions pour convertir les deux chaînes de caractères en minuscules et ainsi rendre leur comparaison insensible à la casse. 
    if modele_vehicule!='': # si un modèle est choisi 
        liste_vehicules = [vehicule for vehicule in liste_vehicules if (vehicule['modele_vehicule'].lower() == modele_vehicule.lower())] 
    else: 
        if type_vehicule!='': # si un type de véhicule est choisie 
            liste_vehicules = [vehicule for vehicule in liste_vehicules if (vehicule['type_vehicule'].lower() == type_vehicule.lower())] 
        else: 
            print("Chosir un modèle ou une type de véhicule !") 
  
    # tri de la liste de véhicules par type, modèle et numéro 
    liste_vehicules = sorted(liste_vehicules, key=lambda k: (k['type_vehicule'], k['modele_vehicule'], k['num_vehicule'])) 
  
    # initialise la liste des disponibilités 
    liste_dispos = [] 
  
    # filtre de la liste des locations en fonction de la période choisie 
    liste_locations = [loc for loc in liste_locations if (loc['fin_loc']>debut_periode) and (loc['debut_loc']<fin_periode)] 
  
    # parcours de la liste 
    for vehicule in liste_vehicules: 
        # création de la liste des disponibilités pour le véhicule 
        liste_dispos_vehicule = generer_disponibilites_vehicule(liste_locations, debut_periode, fin_periode,  
                                                                num_vehicule=vehicule['num_vehicule'], modele_vehicule=vehicule['modele_vehicule'], type_vehicule=vehicule['type_vehicule']) 
        liste_dispos = liste_dispos + liste_dispos_vehicule # ajout à liste_dispos 
  
    return liste_dispos # renvoi la liste des disponibilités 
  
  
# importation du contenu du fichier locations_vehicules.xlsx dans 2 listes de dictionnaires 
liste_vehicules, liste_locations = importer_donnees("locations_vehicules.xlsx") 
  
print("Liste des véhicules :\n") 
  
# on affiche le contenu de la liste des véhicules 
print(liste_vehicules) 
  
print() 
print("Liste des locations :\n") 
  
# on affiche le contenu de la liste des locations 
print(liste_locations) 
  
# choix du modèle ou du type de véhicule recherché 
modele_vehicule="Nissan Qashqai" 
#type_vehicule = "SUV" 
  
# définition de la période de recherche 
debut_periode = datetime(2023, 3, 1, 12, 0, 0) # début période = 01/03/2023 12:00 
fin_periode = datetime(2023, 6, 30, 12, 0, 0) # fin période = 30/06/2023 12:00 
  
# génération de la liste des disponibilités en fonction des critères retenus 
liste_dispos = generer_disponibilites(liste_vehicules, liste_locations, debut_periode, fin_periode, modele_vehicule=modele_vehicule ) 
  
if liste_dispos!=[]: # si la liste n'est pas vide 
  
    print() 
    print("Liste des disponibilités :\n") 
  
    # affiche les disponibilités par véhicule 
    print(liste_dispos) 
  
    # composition du chemin du fichier et du nom de la feuille de destination 
    chemin_fichier = 'dispo_vehicules - ' + modele_vehicule + " - " + debut_periode.strftime('%Y-%m-%d %Hh%M') + " - " + fin_periode.strftime('%Y-%m-%d %Hh%M') + ".xlsx" 
    nom_feuille = 'dispos_' + modele_vehicule 
  
    # export du résultat dans une feuille du fichier Excel 
    exporter_dispos(chemin_fichier, nom_feuille, liste_dispos) 
    os.startfile(chemin_fichier) # ouverture du fichier Excel 
  
else: 
  
    print("Pas de résultat !")

Si vous le souhaitez, vous pouvez récupérer le dossier complet pour tester le code :



VIII. Conclusion

Ce module Python offre donc une solution relativement simple pour obtenir les disponibilités des véhicules à partir de données enregistrées dans des feuilles Excel ou dans des tables SQLite.

Chacun pourra ensuite librement adapter le code pour planifier par exemple les disponibilités de chambres d'hôtel.

Sources :

https://docs.python.org/fr/3/tutoria...tructures.html
https://openpyxl.readthedocs.io/en/latest/index.html
https://docs.python.org/fr/3/library/sqlite3.html
https://docs.python.org/fr/3.11/library/datetime.html

Une erreur dans cette actualité ? Signalez-nous-la !