init
This commit is contained in:
2
backend-django/backend/utils/insertion/__init__.py
Normal file
2
backend-django/backend/utils/insertion/__init__.py
Normal file
@@ -0,0 +1,2 @@
|
||||
from .administre import *
|
||||
from .commun import *
|
||||
448
backend-django/backend/utils/insertion/administre.py
Normal file
448
backend-django/backend/utils/insertion/administre.py
Normal file
@@ -0,0 +1,448 @@
|
||||
import logging
|
||||
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
from backend.models.administre import Administre, Administres_Pams
|
||||
from backend.models.administre import StatutPamChoices as StatutPam
|
||||
from backend.models.pam import PAM
|
||||
from backend.models.domaine import Domaine
|
||||
from backend.models.filiere import Filiere
|
||||
from backend.models.formation_emploi import FormationEmploi
|
||||
from backend.models.grade import Grade
|
||||
from django.db.models import Q
|
||||
|
||||
from ..alimentation_decorators import data_perf_logger_factory, get_data_logger
|
||||
from ..decorators import execution_time
|
||||
from .commun import (InsertionCounters, batch_iterator, is_same_model,
|
||||
is_same_value)
|
||||
|
||||
logger = get_data_logger(__name__)
|
||||
|
||||
|
||||
@execution_time(level=logging.INFO, logger_factory=data_perf_logger_factory)
|
||||
def update_administre_fmob(df) -> None:
|
||||
"""
|
||||
Met à jour le statut PAM des administrés quand un formulaire de mobilité est annulé.
|
||||
"""
|
||||
ModelType = Administres_Pams
|
||||
Cols = ModelType.Cols
|
||||
status = StatutPam.A_MAINTENIR
|
||||
|
||||
annee_pam = str(int(df['fmob_millesime'].iloc[0]))
|
||||
|
||||
|
||||
updated = (ModelType.objects
|
||||
.filter(**{f'{Cols.O2M_FMOB}__fmob_annulation_fmob': True})
|
||||
.filter(~Q(**{Cols.STATUT_PAM: status}))
|
||||
.filter(a_statut_pam_annee=StatutPam.NON_ETUDIE)
|
||||
.filter(pam__pam_id=annee_pam)
|
||||
.update(**{Cols.STATUT_PAM: status}))
|
||||
if updated:
|
||||
logger.info('%s | mis à jour car FMOB annulé : %s', ModelType.__name__, updated)
|
||||
|
||||
logger.info('Début de la mise à jour des FMOB en "A traiter"')
|
||||
|
||||
next_status = StatutPam.A_TRAITER
|
||||
next_updated = (ModelType.objects
|
||||
.filter(**{f'{Cols.O2M_FMOB}__isnull' : False})
|
||||
.filter(~Q(**{Cols.STATUT_PAM: status}))
|
||||
.filter(a_statut_pam_annee=StatutPam.NON_ETUDIE)
|
||||
.filter(pam__pam_id=annee_pam)
|
||||
.update(**{Cols.STATUT_PAM: next_status}))
|
||||
if next_updated:
|
||||
logger.info('%s | mis à jour car FMOB existe: %s administrés qui ont un FORMOB', ModelType.__name__, next_updated)
|
||||
logger.info("%s[pk=%s] administré mis à jour", ModelType.__name__,next_updated)
|
||||
|
||||
return updated, next_updated
|
||||
|
||||
|
||||
|
||||
|
||||
@execution_time(level=logging.INFO, logger_factory=data_perf_logger_factory)
|
||||
def insert_administre_bo(df: pd.DataFrame) -> None:
|
||||
"""
|
||||
Insère ou met à jour des données de la table des administrés.
|
||||
|
||||
:param df: Dataframe contenant les données pretraités à inserer
|
||||
:type df: class:`pandas.DataFrame`
|
||||
"""
|
||||
logger.info('start update_administre')
|
||||
ModelType = Administre
|
||||
ModelType_2 = Administres_Pams
|
||||
Cols = ModelType.Cols
|
||||
Cols_2 = ModelType_2.Cols
|
||||
col_pk = Cols.PK
|
||||
fields_to_update = [
|
||||
'formation_emploi_id',
|
||||
'a_code_fonction',
|
||||
'grade_id',
|
||||
'a_grade_date_debut',
|
||||
'a_fonction',
|
||||
'a_nom',
|
||||
'a_prenom',
|
||||
'a_sexe',
|
||||
'a_id_def',
|
||||
'a_eip',
|
||||
'a_eip_fiche_detaille',
|
||||
'a_eis',
|
||||
Cols.REL_DOMAINE,
|
||||
Cols.REL_FILIERE,
|
||||
'a_nf',
|
||||
'a_domaine_gestion',
|
||||
'a_date_entree_service',
|
||||
'a_arme',
|
||||
'a_rg_origine_recrutement',
|
||||
'a_date_rdc',
|
||||
'a_date_dernier_acr',
|
||||
'a_date_naissance',
|
||||
'a_diplome_hl',
|
||||
'a_dernier_diplome',
|
||||
'a_credo_fe',
|
||||
'a_date_arrivee_fe',
|
||||
'a_date_pos_statuaire',
|
||||
'a_pos_statuaire',
|
||||
'a_interruption_service',
|
||||
'a_situation_fam',
|
||||
'a_date_mariage',
|
||||
'a_nombre_enfants',
|
||||
'a_enfants',
|
||||
'a_sap_conjoint',
|
||||
'a_fonction1',
|
||||
'a_fonction2',
|
||||
'a_fonction3',
|
||||
'a_fonction4',
|
||||
'a_fonction5',
|
||||
'a_fonction6',
|
||||
'a_fonction7',
|
||||
'a_fonction8',
|
||||
'a_fonction9',
|
||||
'a_date_fonction1',
|
||||
'a_date_fonction2',
|
||||
'a_date_fonction3',
|
||||
'a_date_fonction4',
|
||||
'a_date_fonction5',
|
||||
'a_date_fonction6',
|
||||
'a_date_fonction7',
|
||||
'a_date_fonction8',
|
||||
'a_date_fonction9',
|
||||
'a_pls_gb_max',
|
||||
'a_marqueur_pn',
|
||||
'a_profession_conjoint',
|
||||
'a_id_def_conjoint',
|
||||
'a_sexe_conjoint',
|
||||
'a_origine_recrutement',
|
||||
Cols.STATUT_CONCERTO,
|
||||
Cols.DATE_STATUT_CONCERTO,
|
||||
Cols.STATUT_CONCERTO_FUTUR,
|
||||
Cols.DATE_STATUT_CONCERTO_FUTUR,
|
||||
'a_fud',
|
||||
'a_date_fud',
|
||||
'a_lien_service',
|
||||
'a_categorie',
|
||||
]
|
||||
|
||||
|
||||
fields_to_update_2 = [
|
||||
'pam_id',
|
||||
'administre_id',
|
||||
'a_statut_pam_annee',
|
||||
]
|
||||
models_in_db = {m.pk: m for m in ModelType.objects.only(col_pk, *fields_to_update)}
|
||||
fields_db = ['a_id_sap'] + fields_to_update
|
||||
|
||||
# Integer ou Float Colonnes à mettre à jour
|
||||
fields_num = [
|
||||
'a_sap_conjoint',
|
||||
'a_pls_gb_max',
|
||||
'a_nombre_enfants',
|
||||
'a_id_sap'
|
||||
]
|
||||
|
||||
# Dict pour convertir toutes les colonnes non Integer en chaîne de caractères.
|
||||
dict_conv_str = {a: str for a in fields_db if a not in fields_num}
|
||||
|
||||
# Dict pour convertir toutes les colonnes Integer en Float.
|
||||
dict_conv_float = {a: float for a in fields_num }
|
||||
|
||||
# Lire tous les administrés de la base de données
|
||||
adm_in_db_df = pd.DataFrame.from_records(Administre.objects.all().values_list(*tuple(fields_db)), columns = fields_db)
|
||||
df = df.drop(['_merge'],1)
|
||||
|
||||
if not adm_in_db_df.empty :
|
||||
# Il va y avoir de modification de type donc c'est mieux de ne pas toucher df
|
||||
df_comparaison = df.copy()
|
||||
|
||||
# Modification de type de quelque champs
|
||||
logger.debug('Conversion des types pour la fusion')
|
||||
|
||||
|
||||
df_comparaison = df_comparaison.fillna(np.nan)
|
||||
df_comparaison = df_comparaison.replace('None', np.nan)
|
||||
adm_in_db_df = adm_in_db_df.fillna(np.nan)
|
||||
adm_in_db_df = adm_in_db_df.replace('None', np.nan)
|
||||
|
||||
adm_in_db_df = adm_in_db_df.astype(dict_conv_str)
|
||||
adm_in_db_df = adm_in_db_df.astype(dict_conv_float)
|
||||
|
||||
df_comparaison = df_comparaison.astype(dict_conv_str)
|
||||
df_comparaison = df_comparaison.astype(dict_conv_float)
|
||||
|
||||
compare = pd.DataFrame([df_comparaison[fields_db].dtypes,adm_in_db_df[fields_db].dtypes]).T
|
||||
logger.debug('Comparaison des types pour la fusion')
|
||||
# logger.debug(compare[compare[0]!=compare[1]].dropna())
|
||||
logger.debug('------------------------------------')
|
||||
|
||||
# Comparaison pour savoir ce qui doit etre creer, mis a jour ou supprimer
|
||||
|
||||
comparing_adm_sap = pd.merge(df_comparaison, adm_in_db_df, how='outer', on = 'a_id_sap', suffixes=(None, "_x"), indicator=True)
|
||||
same_rows = comparing_adm_sap[comparing_adm_sap['_merge'] == 'both'].drop('_merge', axis=1)
|
||||
new_rows = comparing_adm_sap[comparing_adm_sap['_merge'] == 'left_only'].drop('_merge', axis=1)
|
||||
delete_rows = comparing_adm_sap[comparing_adm_sap['_merge'] == 'right_only'].drop('_merge', axis=1)
|
||||
|
||||
|
||||
# Comparaison pour savoir des ligne a mettre a jour, lequel est deja a jour et lequel doit se mettre a jour
|
||||
|
||||
comparing_adm_both = pd.merge(same_rows, adm_in_db_df, how='left', on=fields_db,
|
||||
suffixes=(None, "_x"), indicator=True)
|
||||
|
||||
not_updated_rows = comparing_adm_both[comparing_adm_both['_merge'] == 'both'].drop(['_merge'], axis=1)
|
||||
updated_rows = comparing_adm_both[comparing_adm_both['_merge'] == 'left_only'].drop(['_merge'], axis=1)
|
||||
|
||||
# Creation du df final avec une colonne db_create_status qui dis si la ligne doit etre creer ou mis a jour
|
||||
|
||||
update = df.loc[df['a_id_sap'].isin(list(updated_rows['a_id_sap']))]
|
||||
update['db_create_status'] = 0
|
||||
create = df.loc[df['a_id_sap'].isin(list(new_rows['a_id_sap']))]
|
||||
create['db_create_status'] = 1
|
||||
|
||||
df = pd.concat([update,create])
|
||||
|
||||
|
||||
else :
|
||||
df['db_create_status'] = 1
|
||||
not_updated_rows = pd.DataFrame([])
|
||||
|
||||
|
||||
# IDs existants pour les clés étrangères
|
||||
|
||||
domaines_in_db = set(Domaine.objects.values_list('pk', flat=True))
|
||||
filieres_in_db = set(Filiere.objects.values_list('pk', flat=True))
|
||||
formations_in_db = set(FormationEmploi.objects.values_list('pk', flat=True))
|
||||
grades_in_db = set(Grade.objects.values_list('pk', flat=True))
|
||||
|
||||
fields_not_validated = [f.name for f in ModelType._meta.get_fields() if f.is_relation]
|
||||
fields_not_validated_2 = [f.name for f in ModelType_2._meta.get_fields() if f.is_relation]
|
||||
|
||||
dict_create = {}
|
||||
dict_update = {}
|
||||
dict_up_to_date = {}
|
||||
dict_create_2 = {}
|
||||
set_dom = set()
|
||||
set_fil = set()
|
||||
counters = InsertionCounters()
|
||||
|
||||
annee_pam = PAM.objects.filter(pam_statut='PAM en cours')[0].pam_id
|
||||
annee_pam_suivant = PAM.objects.filter(pam_statut='PAM A+1')[0].pam_id
|
||||
|
||||
def process_row(row):
|
||||
pk = str(row[col_pk])
|
||||
pk_2 = pk + str(annee_pam)
|
||||
pk_3 = pk + str(annee_pam_suivant)
|
||||
try:
|
||||
domaine = row['a_domaine']
|
||||
if domaine is not None and domaine not in domaines_in_db:
|
||||
# TODO déjà fait dans l'extraction, serait mieux placé ici
|
||||
logger.warning("%s[pk=%s] domaine ignoré car absent du référentiel : %s", ModelType.__name__, pk, domaine)
|
||||
set_dom.add(domaine)
|
||||
counters.ignored += 1
|
||||
return
|
||||
|
||||
filiere = row['a_filiere']
|
||||
if filiere is not None and filiere not in filieres_in_db:
|
||||
# TODO déjà fait dans l'extraction, serait mieux placé ici
|
||||
logger.warning("%s[pk=%s] filière ignoré car absente du référentiel : %s", ModelType.__name__, pk, filiere)
|
||||
set_fil.add(filiere)
|
||||
counters.ignored += 1
|
||||
return
|
||||
|
||||
grade = row['grade_id']
|
||||
if grade is not None and grade not in grades_in_db:
|
||||
# TODO déjà fait dans l'extraction, serait mieux placé ici
|
||||
logger.warning("%s[pk=%s] ignoré car grade inconnu : %s", ModelType.__name__, pk, grade)
|
||||
counters.ignored += 1
|
||||
return
|
||||
|
||||
formation = row['formation_emploi_id']
|
||||
if formation is not None and formation not in formations_in_db:
|
||||
# TODO déjà fait dans l'extraction, serait mieux placé ici
|
||||
logger.warning("%s[pk=%s] ignoré car formation-emploi inconnue : %s", ModelType.__name__, pk, formation)
|
||||
counters.ignored += 1
|
||||
return
|
||||
|
||||
|
||||
model_2 = ModelType_2(**{
|
||||
'id' :pk_2,
|
||||
'pam_id' :annee_pam,
|
||||
'administre_id' :pk,
|
||||
'a_statut_pam_annee' :StatutPam.NON_ETUDIE,
|
||||
})
|
||||
|
||||
model_3 = ModelType_2(**{
|
||||
'id' :pk_3,
|
||||
'pam_id' :annee_pam_suivant,
|
||||
'administre_id' :pk,
|
||||
'a_statut_pam_annee' :StatutPam.NON_ETUDIE,
|
||||
})
|
||||
|
||||
in_db = models_in_db.get(pk)
|
||||
model = ModelType(**{
|
||||
'pk': pk,
|
||||
'formation_emploi_id': formation,
|
||||
'grade_id': grade,
|
||||
'a_grade_date_debut': row['a_grade_date_debut'],
|
||||
'a_liste_id_marques': row['a_liste_id_marques'],
|
||||
'a_nom': row['a_nom'],
|
||||
'a_prenom': row['a_prenom'],
|
||||
'a_sexe': row['a_sexe'],
|
||||
'a_id_def': row['a_id_def'],
|
||||
'a_eip': row['a_eip'],
|
||||
'a_eip_fiche_detaille': row['a_eip_fiche_detaille'],
|
||||
f'{Cols.REL_DOMAINE}_id': domaine,
|
||||
'a_domaine_futur_id': domaine,
|
||||
f'{Cols.REL_FILIERE}_id': filiere,
|
||||
'a_filiere_futur_id': filiere,
|
||||
'a_fonction': row['a_fonction'],
|
||||
'a_code_fonction': row['a_code_fonction'],
|
||||
'a_nf': row['a_nf'],
|
||||
'a_nf_futur': row['a_nf'],
|
||||
'a_categorie': row['a_categorie'],
|
||||
'a_domaine_gestion': row['a_domaine_gestion'],
|
||||
'a_date_entree_service': row['a_date_entree_service'],
|
||||
'a_arme': row['a_arme'],
|
||||
'a_rg_origine_recrutement': row['a_rg_origine_recrutement'],
|
||||
'a_date_naissance': row['a_date_naissance'],
|
||||
'a_diplome_hl': row['a_diplome_hl'],
|
||||
'a_dernier_diplome': row['a_dernier_diplome'],
|
||||
'a_credo_fe': row['a_credo_fe'],
|
||||
'a_date_arrivee_fe': row['a_date_arrivee_fe'],
|
||||
'a_date_pos_statuaire': row['a_date_pos_statuaire'],
|
||||
'a_pos_statuaire': row['a_pos_statuaire'],
|
||||
'a_interruption_service': row['a_interruption_service'],
|
||||
'a_situation_fam': row['a_situation_fam'],
|
||||
'a_date_mariage': row['a_date_mariage'],
|
||||
'a_nombre_enfants': row['a_nombre_enfants'],
|
||||
'a_enfants': row['a_enfants'],
|
||||
'a_date_rdc': row['a_date_rdc'],
|
||||
'a_date_dernier_acr': row['a_date_dernier_acr'],
|
||||
'a_eis': row['a_eis'],
|
||||
'a_sap_conjoint': row['a_sap_conjoint'],
|
||||
'a_flag_particulier': row['a_flag_particulier'],
|
||||
'a_notes_gestionnaire': row['a_notes_gestionnaire'],
|
||||
'a_notes_partagees': row['a_notes_partagees'],
|
||||
'a_fonction1': row['a_fonction1'],
|
||||
'a_fonction2': row['a_fonction2'],
|
||||
'a_fonction3': row['a_fonction3'],
|
||||
'a_fonction4': row['a_fonction4'],
|
||||
'a_fonction5': row['a_fonction5'],
|
||||
'a_fonction6': row['a_fonction6'],
|
||||
'a_fonction7': row['a_fonction7'],
|
||||
'a_fonction8': row['a_fonction8'],
|
||||
'a_fonction9': row['a_fonction9'],
|
||||
'a_date_fonction1': row['a_date_fonction1'],
|
||||
'a_date_fonction2': row['a_date_fonction2'],
|
||||
'a_date_fonction3': row['a_date_fonction3'],
|
||||
'a_date_fonction4': row['a_date_fonction4'],
|
||||
'a_date_fonction5': row['a_date_fonction5'],
|
||||
'a_date_fonction6': row['a_date_fonction6'],
|
||||
'a_date_fonction7': row['a_date_fonction7'],
|
||||
'a_date_fonction8': row['a_date_fonction8'],
|
||||
'a_date_fonction9': row['a_date_fonction9'],
|
||||
'a_pls_gb_max': row['a_pls_gb_max'],
|
||||
'a_marqueur_pn': row['a_marqueur_pn'],
|
||||
'a_profession_conjoint': row['a_profession_conjoint'],
|
||||
'a_id_def_conjoint': row['a_id_def_conjoint'],
|
||||
'a_sexe_conjoint': row['a_sexe_conjoint'],
|
||||
'a_origine_recrutement': row['a_origine_recrutement'],
|
||||
'a_lien_service': row['a_lien_service'],
|
||||
'a_statut_concerto': row[Cols.STATUT_CONCERTO],
|
||||
'a_date_statut_concerto': row[Cols.DATE_STATUT_CONCERTO],
|
||||
'a_statut_concerto_futur': row[Cols.STATUT_CONCERTO_FUTUR],
|
||||
'a_date_statut_concerto_futur': row[Cols.DATE_STATUT_CONCERTO_FUTUR],
|
||||
'a_fud': row['a_fud'],
|
||||
'a_date_fud': row['a_date_fud'],
|
||||
})
|
||||
if row['db_create_status']:
|
||||
model_3.full_clean(exclude=fields_not_validated, validate_unique=False)
|
||||
dict_create_2.setdefault(pk_3, model_3)
|
||||
|
||||
model_2.full_clean(exclude=fields_not_validated, validate_unique=False)
|
||||
dict_create_2.setdefault(pk_2, model_2)
|
||||
|
||||
model.full_clean(exclude=fields_not_validated, validate_unique=False)
|
||||
dict_create.setdefault(pk, model)
|
||||
else:
|
||||
if not ModelType_2.objects.filter(Q(id=pk_2)).exists():
|
||||
model_2.full_clean(exclude=fields_not_validated_2, validate_unique=False)
|
||||
dict_create_2.setdefault(pk_2, model_2)
|
||||
|
||||
if not ModelType_2.objects.filter(Q(id=pk_3)).exists():
|
||||
model_3.full_clean(exclude=fields_not_validated, validate_unique=False)
|
||||
dict_create_2.setdefault(pk_3, model_3)
|
||||
model.full_clean(exclude=fields_not_validated, validate_unique=False)
|
||||
dict_update.setdefault(pk, model)
|
||||
|
||||
except Exception:
|
||||
counters.errors += 1
|
||||
logger.exception('%s une erreur est survenue à la ligne : %s (pk=%s)', ModelType.__name__, row['index'], pk)
|
||||
|
||||
df['index'] = df.index
|
||||
df.apply(process_row, axis=1)
|
||||
|
||||
if counters.errors:
|
||||
logger.warning("%s | en erreur : %s", ModelType.__name__, counters.errors)
|
||||
|
||||
if counters.ignored:
|
||||
logger.warning('%s | ignoré(s) : %s', ModelType.__name__, counters.ignored)
|
||||
|
||||
if set_dom:
|
||||
logger.warning('%s %s(s) ignoré(s) : %s', len(set_dom), Domaine.__name__, set_dom)
|
||||
|
||||
if set_fil:
|
||||
logger.warning('%s %s(s) ignorée(s) : %s', len(set_fil), Filiere.__name__, set_fil)
|
||||
|
||||
if not not_updated_rows.empty and fields_to_update:
|
||||
logger.info('%s | déjà à jour : %s', ModelType.__name__, len(not_updated_rows))
|
||||
|
||||
batch_size = 50
|
||||
if dict_create:
|
||||
logger.info('%s | à créer : %s', ModelType.__name__, len(dict_create))
|
||||
for idx, data_batch in enumerate(batch_iterator(list(dict_create.values()), batch_size)):
|
||||
ModelType.objects.bulk_create(data_batch)
|
||||
logger.debug('créé(s) : %s (lot %s)', len(data_batch), idx + 1)
|
||||
logger.info('%s | créé(s) : %s', ModelType.__name__, len(dict_create))
|
||||
else :
|
||||
logger.info('%s | rien à créer', ModelType.__name__)
|
||||
|
||||
if dict_create_2:
|
||||
logger.info('%s | à créer dans la vue A+1 : (%s)', ModelType_2.__name__, len(dict_create_2))
|
||||
for idx, data_batch in enumerate(batch_iterator(list(dict_create_2.values()), batch_size)):
|
||||
ModelType_2.objects.bulk_create(data_batch)
|
||||
logger.debug('créé(s) : %s (lot %s)', len(data_batch), idx + 1)
|
||||
logger.info('%s | créé(s) : %s', ModelType_2.__name__, len(dict_create_2))
|
||||
|
||||
if dict_update and fields_to_update:
|
||||
logger.info('%s | à mettre à jour : %s', ModelType.__name__, len(dict_update))
|
||||
for idx, data_batch in enumerate(batch_iterator(list(dict_update.values()), batch_size)):
|
||||
ModelType.objects.bulk_update(data_batch, fields=fields_to_update)
|
||||
logger.debug('mis à jour : %s (lot %s)', len(data_batch), idx + 1)
|
||||
logger.info('%s | mis à jour : %s', ModelType.__name__, len(dict_update))
|
||||
else :
|
||||
logger.info('%s | rien à mettre à jour', ModelType.__name__)
|
||||
|
||||
|
||||
adm_cree = len(dict_create) + len(dict_create_2)
|
||||
adm_modifie = len(dict_update)
|
||||
return adm_cree, adm_modifie, len(not_updated_rows), counters.errors, counters.ignored, set_dom, set_fil
|
||||
|
||||
# pas de suppression ici, il est prévu de faire un upload de fichier spécifique
|
||||
|
||||
61
backend-django/backend/utils/insertion/commun.py
Normal file
61
backend-django/backend/utils/insertion/commun.py
Normal file
@@ -0,0 +1,61 @@
|
||||
from typing import Any, List, Tuple, Union
|
||||
|
||||
import pandas as pd
|
||||
from django.db.models import Choices, Model
|
||||
|
||||
from ..alimentation_decorators import get_data_logger
|
||||
|
||||
logger = get_data_logger(__name__)
|
||||
|
||||
|
||||
def batch_iterator(iterable: Union[List, Tuple, pd.DataFrame], batch_size: int) -> Union[List, Tuple, pd.DataFrame]:
|
||||
"""
|
||||
(je pense que le nom _batch_generator porterait à confusion)
|
||||
Générateur qui morcelle un itérable en lots de taille donnée.
|
||||
|
||||
:param iterable: itérable (supported un data frame)
|
||||
:type iterable: Union[List,Tuple,pd.DataFrame]
|
||||
|
||||
:param batch_size: taille de lot
|
||||
:type batch_size: int
|
||||
|
||||
:return: lot (valide, utilisateur, nouveau)
|
||||
:rtype: Tuple[bool, Optional[UserType], bool]
|
||||
"""
|
||||
length = len(iterable)
|
||||
for idx in range(0, length, batch_size):
|
||||
if isinstance(iterable, pd.DataFrame):
|
||||
yield iterable.iloc[idx:min(idx + batch_size, length)]
|
||||
else:
|
||||
yield iterable[idx:min(idx + batch_size, length)]
|
||||
|
||||
|
||||
def is_same_value(val1: Any, val2: Any) -> bool:
|
||||
"""
|
||||
Indique si deux valeurs sont équivalentes. Le cas le plus courant est une instance de Choices comparée à sa valeur.
|
||||
"""
|
||||
_1 = val1 if isinstance(val1, Choices) else val1
|
||||
_2 = val2 if isinstance(val2, Choices) else val2
|
||||
return _1 == _2
|
||||
|
||||
|
||||
def is_same_model(fields: Union[List[str], Tuple[str]], m1: Model, m2: Model) -> bool:
|
||||
"""
|
||||
Indique si deux modèles contiennent les mêmes données. Ce test permet de limiter les MAJ.
|
||||
"""
|
||||
|
||||
def _get_value(m: Model, field: str):
|
||||
""" Récupère la valeur d'un champ """
|
||||
attr = getattr(m, field)
|
||||
return attr.value if isinstance(attr, Choices) else attr
|
||||
|
||||
return not all(is_same_value(getattr(m1, f), getattr(m2, f)) for f in fields)
|
||||
|
||||
|
||||
class InsertionCounters:
|
||||
"""
|
||||
conteneur de compteurs pour faciliter l'incrémentation dans des fonctions imbriquées
|
||||
"""
|
||||
|
||||
ignored = 0
|
||||
errors = 0
|
||||
Reference in New Issue
Block a user