Nous avons un modèle Django, ToolDataset, et un ModelForm, ToolForm. Dans le modèle, chaque instance ou ligne de base de données est appelée ensemble de données et la clé primaire est appelée dataset_id. Première fois, l'utilisateur remplit un formulaire non lié et le soumet. Conceptuellement, c'est le code de la vue qui est utilisé pour valider, enregistrer et analyser l'ensemble de données:Pourquoi l'instance de modèle Django valide connue échoue is_valid() après la récupération de la base de données?
if (request.method == 'POST') and (not dataset_id):
form = ToolForm(request.POST)
if form.is_valid():
new_dataset = form.save()
dataset_id = new_dataset.pk
results = analyze(form.cleaned_data)
else:
<validation error code>
Je pense que cela est jusqu'à présent tout à fait normal. Notez que les données de formulaire ne sont pas enregistrées et aucun dataset_id n'est affecté sauf si les données sont valides.
Maintenant, un certain temps passe, et l'utilisateur veut revenir à cet ancien jeu de données particulier, peut-être pour modifier les données et les ré-analyser. Ainsi, quel que soit le moyen utilisé, une URL ressemblant à www.finesite.com/Tool/X/, où X est dataset_id correspond à la ligne de données particulière avec laquelle l'utilisateur souhaite travailler. Grâce à l'URLconf, une branche différente du code de la vue est invoquée, que nous pensions que devrait ressembler à ceci:
if (request.method != 'POST') and (dataset_id):
oldset = get_object_or_404(ToolDataset, pk=dataset_id)
form = ToolForm(instance=oldset)
if form.is_valid():
results = analyze(form.cleaned_data)
else:
<validation error code that we expected would never run>
Eh bien, il se trouve, cet ensemble de données, qui était valide quand on a stocké, n » t valider maintenant, ce qui est une surprise. Nous avons utilisé le shell manage.py pour inspecter un peu le formulaire. Voilà une partie de ce que nous avons trouvé:
>>> form.is_valid()
False
>>> form.errors
{}
>>> form.non_field_errors()
[]
>>> form.is_bound
False
L'exécution form.as_p()
cède ce qui semble être une forme complète.
Un associé très compétent a trouvé une fonction d'API non documentée appelée model_to_dict() dans django/forms/models.py. Il a suggéré de remplacer ce,
form = BXEEP_L_Form(model_to_dict(oldset), instance=oldset),
pour cela,
form = BXEEP_L_Form(instance=oldset).
Il travaille maintenant - le formulaire est valide et lié, selon la coquille - mais je suis plein de questions. Pourquoi cela fonctionne-t-il? Pourquoi est-ce nécessaire? Y a-t-il une manière plus standard de faire ceci? Il semble étrange d'avoir à utiliser une fonction interne non documentée pour un cas d'utilisation qui semble si banal et simple.
Si j'utilisais dataset_id comme argument de ma fonction d'analyse, ce serait un argument beaucoup plus petit à passer, mais alors la fonction d'analyse devrait faire une requête de base de données, et je pense que le résultat net serait de ralentir choses un peu. La vue, qui contrôle réellement le processus global, a utilisé get_object_or_404 pour extraire ces données en partie afin qu'elles puissent être rendues à la page. Puisque ces données sont maintenant en main, pourquoi interroger la base de données deux fois. Pourquoi ne pas simplement le passer à analyser()? –
Un jeu de données contient des paramètres pour un problème de conception technique. Quand un utilisateur retourne à un ensemble de données après un laps de temps, c'est probablement parce qu'il veut optimiser la conception (modifier les paramètres) ou simplement revoir les anciens résultats. Dans les deux cas, l'analyse doit être effectuée de nouveau afin qu'il puisse voir l'état actuel de la conception grâce à une série de mesures de performance calculées, connues sous le nom de contrôles unitaires, qui ne sont pas sauvegardées et ne peuvent donc pas être affichées avant d'être recalculées. la fonction d'analyse. –
Je vois la signification de votre premier point maintenant. La meilleure idée est de faire de l'argument de la fonction analysis une instance de modèle au lieu de form.cleaned_data. Alors la fonction d'analyse peut aller de l'avant sans que is_valid() ne doive s'exécuter à nouveau. is_valid() est pour valider l'entrée de l'utilisateur, donc son utilisation ici est inutile, comme cela a été accompli plus tôt. Il n'y a aucun inconvénient à ce changement, sauf un peu de réécriture. Voir ci-dessous. –