Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 68 additions & 0 deletions docs/habref_update.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# Mise à jour du référentiel HABREF

Scripts permettant de mettre à jour le référentiel des habitats (HABREF) vers une nouvelle version.

## Avant de commencer

> [!WARNING]
> La mise à jour du référentiel HABREF efface les données de la version du référentiel précédemment installée.

> [!WARNING]
> Il est fortement recommandé de **faire une sauvegarde de la base de données** avant de commencer.

## 1. Importer la nouvelle version et détecter les orphelins

Dans la première étape, il faut télécharger les données du référentiels, stocker ces dernières dans une table temporaire (ref*habitats.tmp*<num_version>). Pour cela, on lance la commande :

```bash
geonature habref import-v07
```

> [!DANGER]
> Il se peut que certaines entrées du référentiels soient supprimées lors d'une mise à jours. Dans ce cas, le fichier `tmp/habref/orphans_habref.csv` liste l'ensemble des données dans votre base utilisant ces entrées Habref.

Si la commande est relancée, les tables temporaires existantes sont automatiquement supprimées et recréées.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pour moi, je serais plus succinct .
"""

Dans la première étape, il faut télécharger les données du référentiels, stocker ces dernières dans une table temporaire (ref_habitats.tmp_<num_version>). Pour cela, on lance la commande :

geonature habref import-v07

[!DANGER]
Il se peut que certaines entrées du référentiels soient supprimées lors d'une mise à jours. Dans ce cas, le fichier tmp/habref/orphans_habref.csv liste l'ensemble des données dans votre base utilisant ces entrées Habref.

Le CSV généré contient les colonnes suivantes :

Colonne Description
ref_table Table du référentiel concernée (ex: habref, typoref)
table_name Table applicative contenant la référence orpheline
schema Schéma de cette table
fk_column Colonne portant la clé étrangère
fk_value Valeur orpheline
nb_lignes_affectees Nombre de lignes concernées

"""

---

## 2 — Analyser et corriger les données orphelines

Dans le cas où plusieurs données orphelines ont été détecté dans l'étape précédente, consultez le fichier `tmp/habref/orphans_habref.csv`. Pour chaque ligne de ce fichier, la valeur `fk_value` est un code habitat qui sera supprimé lors de la mise à jour.

Le CSV généré contient les colonnes suivantes :

| Colonne | Description |
| --------------------- | -------------------------------------------------------- |
| `ref_table` | Table du référentiel concernée (ex: `habref`, `typoref`) |
| `table_name` | Table applicative contenant la référence orpheline |
| `schema` | Schéma de cette table |
| `fk_column` | Colonne portant la clé étrangère |
| `fk_value` | Valeur orpheline |
| `nb_lignes_affectees` | Nombre de lignes concernées |

Vous devez décider, pour chaque cas :

- **Mettre à jour** les données concernées avec le `cd_hab` de remplacement dans la nouvelle version
- **Supprimer** les observations si elles ne peuvent plus être rattachées

---

## 3 — Appliquer la mise à jour

Une fois les données orphelines corrigées, lancez la mise à jour effective du référentiel à l'aide de la commande suivante :

```bash
geonature habref apply-v07
```

Cette commande :

1. Désactive temporairement les contraintes de clés étrangères
2. Vide toutes les tables du schéma `ref_habitats` (dans l'ordre inverse des dépendances)
3. Recopie le contenu des tables temporaires `tmp_*` dans les tables de production
4. Reconstruit la table `ref_habitats.autocomplete_habitat`
5. Réactive les contraintes de clés étrangères
6. Supprime les tables temporaires `tmp_*`

> [!WARNING]
> ⚠️ Si des données orphelines subsistent au moment du `apply-v07`, des erreurs de contraintes FK pourraient apparaître et la migration ne se feras pas. Assurez-vous que toutes les corrections ont bien été appliquées avant de lancer cette commande.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
> ⚠️ Si des données orphelines subsistent au moment du `apply-v07`, des erreurs de contraintes FK pourraient apparaître et la migration ne se feras pas. Assurez-vous que toutes les corrections ont bien été appliquées avant de lancer cette commande.
> [!WARNING]
> ⚠️ Si des données orphelines subsistent au moment du `apply-v07`, des erreurs de contraintes FK pourraient apparaître et la migration ne se feras pas. Assurez-vous que toutes les corrections ont bien été appliquées avant de lancer cette commande.

3 changes: 3 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ Homepage = "https://github.com/PnX-SI/Habref-api-module"
[project.entry-points."alembic"]
migrations = "pypn_habref_api.migrations:versions"

[project.entry-points."flask.commands"]
habref = "pypn_habref_api.commands.habref:habref"

[tool.setuptools]
package-dir = { "" = "src" }
packages = ["pypn_habref_api"]
Expand Down
18 changes: 18 additions & 0 deletions src/pypn_habref_api/commands/habref.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import click

from flask.cli import with_appcontext

from .habref_v7 import import_v07, apply_v07

import logging

logger = logging.getLogger("habref_commands")


@click.group(help="Manager HabRef referentials.")
def habref():
pass


habref.add_command(import_v07)
habref.add_command(apply_v07)
234 changes: 234 additions & 0 deletions src/pypn_habref_api/commands/habref_v7.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
import logging

from pypn_habref_api.env import db

import click
from flask.cli import with_appcontext

from utils_flask_sqla.referential import collect_orphan_rows, export_orphans_to_csv
from .utils import import_habref, apply_habref

base_url = "https://geonature.fr/data/inpn/habitats/"
table_files = {
"typoref": {
"filename": "TYPOREF_70.csv",
"unique_column": "cd_typo",
"table_fields": {
"cd_typo": "CD_TYPO",
"cd_table": "CD_TABLE",
"lb_nom_typo": "LB_NOM_TYPO",
"nom_jeu_donnees": "NOM_JEU_DONNEES",
"date_creation": "DATE_CREATION",
"auteur_typo": "AUTEUR_TYPO",
"auteur_table": "AUTEUR_TABLE",
"territoire": "TERRITOIRE",
"organisme": "ORGANISME",
"langue": "LANGUE",
"presentation": "PRESENTATION",
"description": "DESCRIPTION",
"origine": "ORIGINE",
"ref_biblio": "REF_BIBLIO",
"mots_cles": "MOTS_CLES",
"referencement": "REFERENCEMENT",
"diffusion": "DIFFUSION",
"derniere_modif": "DERNIERE_MODIF",
"type_table": "TYPE_TABLE",
"cd_typo_entre": "CD_TYPO_ENTRE",
"cd_typo_sortie": "CD_TYPO_SORTIE",
},
},
"bib_habref_typo_rel": {
"filename": "HABREF_TYPE_REL_70.csv",
"unique_column": "cd_type_rel",
"table_fields": {
"cd_type_rel": "CD_TYPE_REL",
"lb_type_rel": "LB_TYPE_REL",
"lb_rel": "LB_REL",
"corresp_hab": "CORRESP_HAB",
"corresp_esp": "CORRESP_ESP",
"corresp_syn": "CORRESP_SYN",
"date_crea": "DATE_CREA",
"date_modif": "DATE_MODIF",
},
},
"bib_habref_statuts": {
"filename": "HABREF_STATUTS.csv",
"unique_column": "statut",
"table_fields": {
"statut": "STATUT",
"description": "DESCRIPTION",
"definition": "DEFINITION",
"ordre": "ORDRE",
},
},
"habref_sources": {
"filename": "HABREF_SOURCES_70.csv",
"unique_column": "cd_source",
"table_fields": {
"cd_source": "CD_SOURCE",
"cd_doc": "CD_DOC",
"type_source": "TYPE_SOURCE",
"auteur_source": "AUTEUR_SOURCE",
"date_source": "DATE_SOURCE",
"lb_source": "LB_SOURCE",
"lb_source_complet": "LB_SOURCE_COMPLET",
"titre": "TITRE",
"link": "LINK",
"date_crea": "DATE_CREA",
"date_modif": "DATE_MODIF",
},
},
"habref": {
"filename": "HABREF_70.csv",
"unique_column": "cd_hab",
"table_fields": {
"cd_hab": "CD_HAB",
"fg_validite": "FG_VALIDITE",
"cd_typo": "CD_TYPO",
"lb_code": "LB_CODE",
"lb_hab_fr": "LB_HAB_FR",
"lb_hab_fr_complet": "LB_HAB_FR_COMPLET",
"lb_hab_en": "LB_HAB_EN",
"lb_auteur": "LB_AUTEUR",
"niveau": "NIVEAU",
"lb_niveau": "LB_NIVEAU",
"cd_hab_sup": "CD_HAB_SUP",
"path_cd_hab": "PATH_CD_HAB",
"france": "FRANCE",
"lb_description": "LB_DESCRIPTION",
},
},
"habref_corresp_hab": {
"filename": "HABREF_CORRESP_HAB_70.csv",
"unique_column": "cd_corresp_hab",
"table_fields": {
"cd_corresp_hab": "CD_CORRESP_HAB",
"cd_hab_entre": "CD_HAB_ENTRE",
"cd_hab_sortie": "CD_HAB_SORTIE",
"cd_type_relation": "CD_TYPE_RELATION",
"lb_condition": "LB_CONDITION",
"lb_remarques": "LB_REMARQUES",
"validite": "VALIDITE",
"cd_typo_entre": "CD_TYPO_ENTRE",
"cd_typo_sortie": "CD_TYPO_SORTIE",
},
},
"habref_corresp_taxon": {
"filename": "HABREF_CORRESP_TAXON_70.csv",
"unique_column": "cd_corresp_tax",
"table_fields": {
"cd_corresp_tax": "CD_CORRESP_TAX",
"cd_hab_entre": "CD_HAB_ENTRE",
"cd_nom": "CD_NOM",
"cd_type_relation": "CD_TYPE_RELATION",
"lb_condition": "LB_CONDITION",
"lb_remarques": "LB_REMARQUES",
"nom_cite": "NOM_CITE",
"validite": "VALIDITE",
"date_crea": "DATE_CREA",
"date_modif": "DATE_MODIF",
},
},
"cor_habref_terr_statut": {
"filename": "HABREF_TERR_70.csv",
"unique_column": "cd_hab_ter",
"table_fields": {
"cd_hab_ter": "CD_HAB_TERR",
"cd_hab": "CD_HAB",
"cd_sig_terr": "CD_SIG_TERR",
"cd_statut_presence": "CD_STATUT_PRESENCE",
"date_crea": "DATE_CREA",
"date_modif": "DATE_MODIF",
},
},
"typoref_fields": {
"filename": "TYPOREF_FIELDS_70.csv",
"unique_column": "cd_hab_field",
"table_fields": {
"cd_hab_field": "CD_HAB_FIELD",
"cd_typo": "CD_TYPO",
"lb_hab_field": "LB_HAB_FIELD",
"format_hab_field": "FORMAT_HAB_FIELD",
"descript_hab_field": "DESCRIPT_HAB_FIELD",
"ordre_hab_field": "ORDRE_HAB_FIELD",
"length_hab_field": "LENGTH_HAB_FIELD",
"lb_label": "LB_LABEL",
"date_crea": "DATE_CREA",
"date_modif": "DATE_MODIF",
},
},
"cor_habref_description": {
"filename": "HABREF_DESCRIPTION_70.csv",
"unique_column": "cd_hab_description",
"table_fields": {
"cd_hab_description": "CD_HAB_DESCRIPTION",
"cd_hab": "CD_HAB",
"cd_hab_field": "CD_HAB_FIELD",
"valeurs": "VALEURS",
},
},
"cor_hab_source": {
"filename": "HABREF_LIEN_SOURCES_70.csv",
"unique_column": "cd_hab_lien_source",
"table_fields": {
"cd_hab_lien_source": "CD_HAB_LIEN_SOURCE",
"cd": "CD",
"type_lien": "TYPE_LIEN",
"cd_source": "CD_SOURCE",
"origine": "ORIGINE",
"date_crea": "DATE_CREA",
"date_modif": "DATE_MODIF",
},
},
}


@click.command()
@with_appcontext
def import_v07():
logger = logging.getLogger()

import_habref(
logger,
table_files=table_files,
schema="ref_habitats",
base_url=base_url,
num_version="07",
archive_name="HABREF_70.zip",
)

logger.info("Détection des données orphelines…")
all_orphans = []
for table, config in table_files.items():
logger.info(f" Vérification de {table}…")
all_orphans.extend(
collect_orphan_rows(
ref_table=table,
new_ref_table=f"tmp_{table}",
pk_col=config["unique_column"],
db=db,
schema="ref_habitats",
exclude_tables=list(table_files.keys()),
)
)
nb = export_orphans_to_csv(all_orphans, "tmp/habref/orphans_habref.csv")
if nb:
logger.warning(
f"{nb} valeur(s) orpheline(s) détectée(s), voir tmp/habref/orphans_habref.csv"
)
else:
logger.info("Aucune donnée orpheline détectée.")

logger.info("Committing…")
db.session.commit()


@click.command()
@with_appcontext
def apply_v07():
logger = logging.getLogger()

apply_habref(logger, table_files=table_files, schema="ref_habitats")

logger.info("Committing…")
db.session.commit()
Loading
Loading