2010-03-04 3 views
2

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.

Répondre

1

Je suis probablement malentendu quelque chose mais il me semble que votre fonction analyze ne devrait pas prendre form.cleaned_data en entrée mais plutôt dataset_id.

Si l'exemple n'est pas complet, pourquoi créez-vous un formulaire dans un ensemble de données afin de l'analyser?

+0

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()? –

+0

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. –

+0

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. –

3

form.is_valid() vérifie la form.data dict, qui est envoyé par l'intermédiaire du constructeur pour Form(data=request.POST)

ModelForm.instance associe les données d'une rangée de table particulière, de sorte qu'une sauvegarde exécute nécessairement une mise à jour et non un insert. Ceci est également passé via le constructeur.

Ces deux éléments sont cependant indépendants l'un de l'autre. Si vous voulez créer un formulaire avec les données ancienne instance, vous devez faire ce qui suit:

ToolForm(data=oldinstance.__data__, instance=oldinstance) 

Cependant, vous ne voulez peut-être pas vraiment pour lier les données tout de suite.

ToolForm(instance=oldinstance) 

Remplit les bonnes valeurs de l'instance, lorsqu'ils sont rendus dans le code HTML et mettre à jour le dossier, que si ToolForm exemple is_changed()

+0

Il semble étrange que 'form = ToolForm (instance = oldset)' ne donne pas un formulaire qui peut être vérifié en utilisant is_valid(). Cependant, j'accepte ce que vous dites. Je pense que vous vouliez dire __dict__, pas __data__. Quelques nouvelles complications sur l'utilisation de __dict__ avec des instances de modèle (Voir ici: http://www.google.com/url?q=http://docs.djangoproject.com/fr/dev/releases/1.2-alpha-1 /% 23dict-on-model-instances & usg = AFQjCNGcuOScV33WhD6ww1d7AK-BwVyfSA & ei = hgaQS5j7G4j6sgOd8eS5CA & sa = X & oi = section_link & resnum = 1 & ct = legacy.), Pourrait faire de model_to_dict un meilleur choix. –

0

Nous avons changé l'argument de la fonction d'analyse pour être une instance de modèle au lieu de la forme .cleaned_data. Cela dissocie l'analyse de la validation de la forme et est beaucoup plus raisonnable. Conceptuellement, la deuxième partie du code ci-dessus ressemble maintenant à ceci maintenant:

if (request.method != 'POST') and (dataset_id): 
     oldset = get_object_or_404(ToolDataset, pk=dataset_id) 
     form = ToolForm(instance=oldset) 
     results = analyze(oldset) 

Bien sûr, le déballage des données à la tête de la fonction d'analyse devait être réécrite quelque peu.

Tout cela semble évident maintenant. Merci à tous pour votre intérêt!

Questions connexes