Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🎁 Suggestion de changement v1 #1141

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft

Conversation

maxcorbeau
Copy link
Contributor

@maxcorbeau maxcorbeau commented Dec 16, 2024

🎁 Suggestion de changement v1

Carte Notion : CLUSTERING: Modèles & UI django pour le stockage des clusters

  • quoi: un modèle et une UI Django pour suggérer et revoir (rejeter, approuver) des suggestions de changements
  • pourquoi: initialement pour le clustering, mais on veut s'en servir à l'avenir pour suggérer d'autres changements (diff d'ingestion des acteurs)
  • comment: en rendant le schema/nomenclature générique mais en validant les données fournies

Approche

  • Suite à une réunion ce matin on a décidé avec @kolok et @chrischarousset de partir sur une approche abstraite de la notion de changement, pour l'utiliser dans d'autres contextes que le clustering (ex: diff d'ingestion)
  • Par conséquent on a besoin d'un champ JSON pour représenter le changement, car tout changement n'aura pas la même structure (ex: pour le clustering on a besoin d'un cluster_id, pas pour le diff d'ingestion des acteurs)
  • En ce qui concerne la validation du JSON
    • Manque d’XP django de ma part pour savoir ce qui est le mieux
    • Je vois des champs JSONField dans notre code (ex: DagRun.meta_data) mais je ne trouve pas de validation associée
    • Donc par défaut je suis parti sur JSONField avec de la validation dans le modèle sous clean

➡️ Restant à faire

  • Comprendre/résoudre problème d'affichage dans Django Admin UI
  • Une fois le modèle finalisé: écrire des tests unitaires pour valider le cas clustering et s'assurer que les problèmes de formatage de données soulèvent bien des exceptions
  • Tester le modèle en important les clusters de déchetteries

Comment on lines +43 to +46
verbose_name=dedent(
"""Données de debug de la suggestion
(quelles données ont été utilisées pour la suggestion)"""
),
Copy link
Member

@fabienheureux fabienheureux Dec 16, 2024

Choose a reason for hiding this comment

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

Suggested change
verbose_name=dedent(
"""Données de debug de la suggestion
(quelles données ont été utilisées pour la suggestion)"""
),
verbose_name="Données de debug de la suggestion"
"(quelles données ont été utilisées pour la suggestion)",

Suggestion : python permet d'écrire des strings sur plusieurs lignes dans ce genre de situations

Comment on lines +55 to +59
verbose_name=dedent(
"""Données du changement
(stocker uniquement le strict minimum pour
gérer le changement)"""
),
Copy link
Member

@fabienheureux fabienheureux Dec 16, 2024

Choose a reason for hiding this comment

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

Suggested change
verbose_name=dedent(
"""Données du changement
(stocker uniquement le strict minimum pour
gérer le changement)"""
),
verbose_name="Données du changement"
"(stocker uniquement le strict minimum pour
gérer le changement)",

Suggestion : idem ci-dessus

Comment on lines +94 to +96
# On remplit review_at si la revue est effectuée ET
# que c'est la première fois qu'on change le statut (sinon
# on garde la valeur originale)
Copy link
Member

@fabienheureux fabienheureux Dec 16, 2024

Choose a reason for hiding this comment

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

Remarque : Je ne suis pas forcément pour ajouter ce type de commentaires dans le code qui paraphrasent ce qui est lisible à la lecture des conditions

(ex: pour un cluster d'acteur = cluster_id -> acteur_id). Ne pas stocker
d'autres données qui pourraient devenir obsolètes au moment de la revue.
Si on souhaite fournir de la donnée supplémentaire, il faut le faire à
la vollée (ex: au moment de l'affichage ou de l'export)
Copy link
Member

@fabienheureux fabienheureux Dec 16, 2024

Choose a reason for hiding this comment

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

Suggested change
la vollée (ex: au moment de l'affichage ou de l'export)
la volée (ex: au moment de l'affichage ou de l'export)

Petite typo

# Validations spécifiques aux différents types de changements
if self.change_type == "acteur_cluster":
if not isinstance(self.change_data, dict):
raise ValueError("acteur_cluster: change_data doit être un dict pour ")
Copy link
Member

Choose a reason for hiding this comment

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

Remarque : Je pense qu'il manque un bout du commentaire ici

@@ -1,6 +1,7 @@
from .acteur import * # noqa
from .action import * # noqa
from .categorie_objet import * # noqa
from .change_suggestion import * # noqa
Copy link
Member

Choose a reason for hiding this comment

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

Suggestion : ici on suit ce qui se faisait, mais tant qu'à faire ignorons explicitement la règle qui nous ennuie

Suggested change
from .change_suggestion import * # noqa
from .change_suggestion import * # noqa: F403

Cf https://www.flake8rules.com/rules/F403.html



class ChangeSuggestionAdmin(admin.ModelAdmin):
# Pour l'instant on consèrve le modèle admin par défaut
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
# Pour l'instant on consèrve le modèle admin par défaut
# Pour l'instant on conserve le modèle admin par défaut

Copy link
Member

@fabienheureux fabienheureux left a comment

Choose a reason for hiding this comment

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

J'ai fait quelques retours sur la forme (non bloquants).
Sur le fond, les séries de champs préfixés me font me dire qu'on aurait presque intérêt à avoir deux modèles distincts, change et review :

  • Un changement peut avoir n reviews
  • Une fois que toutes les reviews sont fermées / validées, on passe le changement en approuvé

Mais j'ai peut-être mal compris quelque chose ?

Concernant le JSONField, aucune objection si ce n'est que un jour on doit migrer des données (via des migrations Django), les JSONField demandent pas mal de travail, donc il faudra être vigilant à la rétrocompatibilité si on construit une UI autour de ces champs.


Mais globalement je trouve ça top !

Comment on lines +1 to +4
"""
Modèle de données Django pour les suggestions de changements
"""

Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
"""
Modèle de données Django pour les suggestions de changements
"""

Suggestion : je pense que c'est un reliquat, le commentaire est répété plus bas en docstring de la classe

Comment on lines +104 to +105
if not isinstance(self.change_data, (dict, list)):
raise ValueError("change_data doit être un dict ou list")
Copy link
Member

Choose a reason for hiding this comment

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

Question : c'est possible ça ? Que la valeur ne soit pas du bon type ?
Je pense que le validateur django (du fait de l'utilisation du JSONField) va exploser de lui même si tu tentes de lui passer autre chose. Mais à tester quand même

Suggestion : Aussi, comme on est dans clean, est-ce qu'on ne lèverait pas plutôt une ValidationError
Cf https://docs.djangoproject.com/en/5.1/ref/forms/validation/#raising-validationerror

raise ValueError("change_data doit être un dict ou list")

# Validations spécifiques aux différents types de changements
if self.change_type == "acteur_cluster":
Copy link
Member

@fabienheureux fabienheureux Dec 16, 2024

Choose a reason for hiding this comment

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

Suggestion :
Je ne me rends pas compte du nombre de change_type qu'on va gérer à terme, mais en prévision d'un nombre approchant la dizaine, je serais assez partisan de sortir la validation du modèle, et mapper ça tout en haut de notre module, car plus je review et moins c'est lisible pour moi ce qu'on fait.

Genre quelque chose comme

# models.py
from .validators import validate_acteur_cluster

# ... 

change_data_validators = {
  "acteur_cluster": validate_acteur_cluster
} 

# ... 

class ChangeSuggestion(models.Model):
  def clean(self):
    # ... 
    try: 
      change_data_validators[self.change_type](self.change_data)
    except KeyError:
      raise NotImplementedError(f"Pas de gestion change_data pour: {self.change_type}")
      
# validators.py 
def validate_acteur_cluster(value): 
  if not isinstance(value, dict):
    raise ValidationError("acteur_cluster: change_data doit être un dict pour ")

  acteur_id = value.get("acteur_id")
  cluster_id = value.get("cluster_id")

  if not acteur_id:
    raise ValidationError("acteur_cluster: change_data à besoin de acteur_id")

  if not cluster_id:
    raise ValidationError("acteur_cluster: change_data à besoin de cluster_id")

verbose_name="Type de changement",
)
change_data = models.JSONField(
verbose_name=dedent(
Copy link
Member

Choose a reason for hiding this comment

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

Suggestion (à tester) : les champs Django disposent d'un attribut validators auquel tu peux passer des validateurs sur ton champ.

Cf ce commentaire je me demande si ce n'est pas ce qu'on voudrait faire ici

  • au save, executer un validateur custom sur notre champ
  • faire redescendre toute la logique de validation au niveau du champ lui-même

Je précise à tester car je n'ai jamais testé avec un JSONField, mais je ne vois pas pourquoi ça ne pourrait pas fonctionner.
C'est un simple callable qu'on passe à notre définition de champ, qui sera appelé durant la validation du champ côté python

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants