-
Notifications
You must be signed in to change notification settings - Fork 24
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
Règles plus restrictives pour la suppression de certain objets afin de ne pas créer d'incohérences de données #3150
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Super initiative.
Personnellement je suis plutôt dans l'équipe RESTRICT
par défaut avec un commentaire dans le cas contraire 😅
@@ -822,7 +822,7 @@ def displayed_choices_for_siae(siae): | |||
verbose_name="mis à jour par", | |||
null=True, | |||
blank=True, | |||
on_delete=models.SET_NULL, | |||
on_delete=models.RESTRICT, # For traceability and accountability, the dates can be edited |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Si on veut aller à fond là-dedans (et tous les autres "traceability & accountability du même genre) je dirais:
- ni nullable, ni blankable (pour tous ces
created_by
/updated_by
...) - RESTRICT ou CASCADE suivant le cas
- créer ou réutiliser un utilisateur singleton (genre
robot <machine@internal.com>
) pour tous les cas où on fait des updates par script.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Vu que tout le monde semblait être plutôt d'avis d'être restrictif ( 🥁 💇 ) j'ai modifié les on_delete
dans ce sens.
Pour les null
/blank
vu qu'il faut rester compatible avec les NULL
existant faudra gérer ça au cas par cas.
related_name="%(class)ss_declared", | ||
) | ||
declared_by_siae = models.ForeignKey( | ||
"siaes.Siae", | ||
verbose_name="SIAE du déclarant", | ||
null=True, | ||
on_delete=models.SET_NULL, | ||
on_delete=models.RESTRICT, # For traceability and accountability, people's organization can change |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 mais ça me donne envie de lancer un chantier "désactivation des SIAEs" plutot que de les supprimer, pour garder la traçabilité dans le temps. Non ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
La plupart du temps, on désactive les SIAE de toute façon.
https://www.notion.so/plateforme-inclusion/SIAE-ou-DDETS-demande-suppression-SIAE-cl-ture-compte-7e1337dd41b640faac0df86877e65150
@@ -1080,7 +1080,7 @@ class CommonProlongation(models.Model): | |||
verbose_name="prescripteur habilité qui a autorisé cette prolongation", | |||
null=True, | |||
blank=True, | |||
on_delete=models.SET_NULL, | |||
on_delete=models.RESTRICT, # For traceability and accountability |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pareil pour la désactivation des prescripteurs, je sens que retirer ces SET_NULL
va faire péter les scripts de syncho, l'admin, etc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Le support est prévenu. Mieux vaut une erreur que perdre de la données sur ces modèles critiques.
894c94c
to
2dad337
Compare
2dad337
to
1ffb0f1
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💯 👍 🥇
Mais pourquoi avons-nous attendu si longtemps pour merger cette PR ?
On ne veut pas vivre dans un monde aussi dangereux. Merci d’avoir ramené quelques gardes fous (et le petit coup de pression pour les intégrer 😁) 🙇
related_name="%(class)ss_declared", | ||
) | ||
declared_by_siae = models.ForeignKey( | ||
"siaes.Siae", | ||
verbose_name="SIAE du déclarant", | ||
null=True, | ||
on_delete=models.SET_NULL, | ||
on_delete=models.RESTRICT, # For traceability and accountability, people's organization can change |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
La plupart du temps, on désactive les SIAE de toute façon.
https://www.notion.so/plateforme-inclusion/SIAE-ou-DDETS-demande-suppression-SIAE-cl-ture-compte-7e1337dd41b640faac0df86877e65150
@@ -1080,7 +1080,7 @@ class CommonProlongation(models.Model): | |||
verbose_name="prescripteur habilité qui a autorisé cette prolongation", | |||
null=True, | |||
blank=True, | |||
on_delete=models.SET_NULL, | |||
on_delete=models.RESTRICT, # For traceability and accountability |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Le support est prévenu. Mieux vaut une erreur que perdre de la données sur ces modèles critiques.
itou/eligibility/models/geiq.py
Outdated
@@ -235,7 +235,7 @@ class GEIQAdministrativeCriteria(AbstractAdministrativeCriteria): | |||
verbose_name="critère parent", | |||
blank=True, | |||
null=True, | |||
on_delete=models.SET_NULL, | |||
on_delete=models.RESTRICT, # Prevent promoting a criteria form child to parent |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
on_delete=models.RESTRICT, # Prevent promoting a criteria form child to parent | |
on_delete=models.RESTRICT, # Prevent promoting a criteria from child to parent |
itou/job_applications/models.py
Outdated
@@ -505,7 +505,7 @@ class JobApplication(xwf_models.WorkflowEnabled, models.Model): | |||
sender = models.ForeignKey( | |||
settings.AUTH_USER_MODEL, | |||
verbose_name="utilisateur émetteur", | |||
on_delete=models.SET_NULL, | |||
on_delete=models.SET_NULL, # FIXME: Do we need traceability and accountability? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Le code a été adapté pour gérer un prescripteur qui a été supprimé dans l’admin, sans cris ni larmes. (avant, on avait une 500 car on récupérait un None
)
Je pense qu’on est OK tant qu’il reste le diagnostique et l’organisation prescriptrice ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hésitation résolue par le fait de passer en mode RESTRICT-first.
itou/job_applications/models.py
Outdated
@@ -529,7 +529,7 @@ class JobApplication(xwf_models.WorkflowEnabled, models.Model): | |||
verbose_name="organisation du prescripteur émettrice", | |||
null=True, | |||
blank=True, | |||
on_delete=models.SET_NULL, | |||
on_delete=models.SET_NULL, # FIXME: Do we need traceability and accountability? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Peut-être plus intéressant de garder, et on n’a sûrement moins de raisons (e.g. RGPD) de supprimer (sans transfert) une orga prescriptrice ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hésitation résolue par le fait de passer en mode RESTRICT-first.
itou/siae_evaluations/models.py
Outdated
@@ -635,14 +635,14 @@ class EvaluatedJobApplication(models.Model): | |||
job_application = models.ForeignKey( | |||
"job_applications.JobApplication", | |||
verbose_name="candidature", | |||
on_delete=models.CASCADE, | |||
on_delete=models.CASCADE, # FIXME: RESTRICT because CaP is an auditability tool? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep.
itou/siae_evaluations/models.py
Outdated
related_name="evaluated_job_applications", | ||
) | ||
|
||
evaluated_siae = models.ForeignKey( | ||
EvaluatedSiae, | ||
verbose_name="SIAE évaluée", | ||
on_delete=models.CASCADE, | ||
on_delete=models.CASCADE, # FIXME: RESTRICT because CaP is an auditability tool? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Il arrive qu'on souhaite retirer une SIAE d'une campagne (par exemple, parce qu'elle n'est plus accessible suite à une convention expirée) donc le CASCADE pourrait être pratique.
Après, les cas sont assez rares donc on pourra tout à fait le faire auto-prescription par auto-prescription avant de supprimer l'EvaluatedSiae
itou/siae_evaluations/models.py
Outdated
@@ -759,18 +759,20 @@ class EvaluatedAdministrativeCriteria(models.Model): | |||
administrative_criteria = models.ForeignKey( | |||
"eligibility.AdministrativeCriteria", | |||
verbose_name="critère administratif", | |||
on_delete=models.CASCADE, | |||
on_delete=models.CASCADE, # FIXME: RESTRICT because CaP is an auditability tool? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep. Au pire, on passera gérer ces cas manuellement si un jour on supprime un critère d’éligibilité.
itou/siae_evaluations/models.py
Outdated
proof = models.ForeignKey("files.File", on_delete=models.CASCADE, blank=True, null=True) | ||
proof = models.ForeignKey( | ||
"files.File", on_delete=models.CASCADE, blank=True, null=True | ||
) # FIXME: RESTRICT because CaP is an auditability tool? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ça, tu peux être sûr que RESTRICT
ne cassera rien. Donc pas d’hésitation.
itou/siae_evaluations/models.py
Outdated
related_name="evaluated_administrative_criteria", | ||
) | ||
|
||
evaluated_job_application = models.ForeignKey( | ||
EvaluatedJobApplication, | ||
verbose_name="candidature évaluée", | ||
on_delete=models.CASCADE, | ||
on_delete=models.CASCADE, # FIXME: RESTRICT because CaP is an auditability tool? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
J’hésite pour celui-ci. Les critères sélectionnés pour justifier une candidature ne sont pas si important, c’est déclaratif pour l’employeur et si on supprime la candidature à évaluer, les critères sélectionnés peuvent suivre. Je laisserais bien CASCADE
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Je resterais également sur CASCADE.
itou/siae_evaluations/models.py
Outdated
@@ -181,7 +181,7 @@ class EvaluationCampaign(models.Model): | |||
|
|||
institution = models.ForeignKey( | |||
"institutions.Institution", | |||
on_delete=models.CASCADE, | |||
on_delete=models.CASCADE, # FIXME: Seems dangerous to allow campaign deletion on institution deletion |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
RESTRICT
également
itou/siae_evaluations/models.py
Outdated
related_name="evaluated_administrative_criteria", | ||
) | ||
|
||
evaluated_job_application = models.ForeignKey( | ||
EvaluatedJobApplication, | ||
verbose_name="candidature évaluée", | ||
on_delete=models.CASCADE, | ||
on_delete=models.CASCADE, # FIXME: RESTRICT because CaP is an auditability tool? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Je resterais également sur CASCADE.
itou/siae_evaluations/models.py
Outdated
related_name="evaluated_job_applications", | ||
) | ||
|
||
evaluated_siae = models.ForeignKey( | ||
EvaluatedSiae, | ||
verbose_name="SIAE évaluée", | ||
on_delete=models.CASCADE, | ||
on_delete=models.CASCADE, # FIXME: RESTRICT because CaP is an auditability tool? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Il arrive qu'on souhaite retirer une SIAE d'une campagne (par exemple, parce qu'elle n'est plus accessible suite à une convention expirée) donc le CASCADE pourrait être pratique.
Après, les cas sont assez rares donc on pourra tout à fait le faire auto-prescription par auto-prescription avant de supprimer l'EvaluatedSiae
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Merci pour cette remise à plat ! 🎉
Je suis d'accord avec tous les changements suggérés par les relecteurs (donc j'approuve en anticipant les changements à venir).
This may happen when the siae was removed by the import_siae script. This removal should soon be blocked (see #3150)
This may happen when the siae was removed by the import_siae script. This removal should soon be blocked (see #3150)
This may happen when the siae was removed by the import_siae script. This removal should soon be blocked (see #3150)
This may happen when the siae was removed by the import_siae script. This removal should soon be blocked (see #3150)
This may happen when the siae was removed by the import_siae script. This removal should soon be blocked (see #3150)
This may happen when the siae was removed by the import_siae script. This removal should soon be blocked (see #3150)
1ffb0f1
to
d8d0ab9
Compare
c949994
to
3b8c6fa
Compare
3f65f59
to
1156086
Compare
1156086
to
dac1b2c
Compare
ForeignKey.on_delete
Note
Je met tout le monde en relecteur mais il n'y a pas forcément besoin de tout relire, vous pouvez seulement vous concentrer sur un ou des domaines en particuliers.
Warning
Ces changements étant particulièrement lié aux aspects métiers, donc diffus dans l'équipe et assez impactant, n'hésitez pas à regarder les parties modifiées ET non-modifiées !
Il y a au final assez peu de modification évidente et qui, je pense, ferons consensus [1]. Le but est donc de lancer les réflexions à partir d'une première proposition.
tl;dr : C'est le moment de sortir vos meilleures pinaillage 😁.
Pourquoi ?
Cela fait maintenant plusieurs fois que des problèmes de données liés à des
ForeignKey
sont détectés [1], faisons donc l'inventaire de celles-ci ainsi que de leur clauseon_delete
.On utilise quasiment que
CASCADE
etSET_NULL
:CASCADE
me semblant être un tropisme "la suppression n'intervient que dans l'admin et il y a un message de validation"SET_NULL
sont souvent là par simplicité au prix de l'auditabilité, a voir où on veux mettre le curseur au global et/ou en fonction des objets[1] Je pense au
CASCADE
pour lesMembershipAbstract.updated_by