2009-02-12 7 views
3

Comme un exercice, je suis en train de créer un widget personnalisé django pour une horloge de 24 heures. Le widget sera un MultiWidget - une boîte de sélection pour chaque champ. J'essaie de suivre docs en ligne (un peu sparse) et en regardant le livre Pro Django, mais je n'arrive pas à le comprendre. Suis-je sur la bonne voie? Je peux enregistrer mes données à partir du formulaire, mais lorsque je préremplis le formulaire, le formulaire n'a pas les valeurs précédentes.Personnalisé django widget - decompress() arg pas rempli

Il semble que le problème est que l'argument 'valeur' ​​des méthodes decompress() est toujours vide, donc je n'ai rien à interpréter.

from django.forms import widgets 

import datetime 

class MilitaryTimeWidget(widgets.MultiWidget): 
    """ 
    A widget that displays 24 hours time selection. 
    """ 
    def __init__(self, attrs=None): 
     hours = [ (i, "%02d" %(i)) for i in range(0, 24) ] 
     minutes = [ (i, "%02d" %(i)) for i in range(0, 60) ] 
     _widgets = (
      widgets.Select(attrs=attrs, choices=hours), 
      widgets.Select(attrs=attrs, choices=minutes), 
      ) 
     super(MilitaryTimeWidget, self).__init__(_widgets, attrs) 

    def decompress(self, value): 
     print "******** %s" %value 
     if value: 
      return [int(value.hour), int(value.minute)] 
     return [None, None] 

    def value_from_datadict(self, data, files, name): 
     hour = data.get("%s_0" %name, None) 
     minute = data.get("%s_1" %name, None) 
     if hour and minute: 
      hour = int(hour) 
      minute = int(minute) 
      return datetime.time(hour=hour, minute=minute) 
     return None 

Dans ma forme, j'appelle le widget comme:

arrival_time = forms.TimeField(label="Arrival Time", required=False, widget=MilitaryTimeWidget()) 
+0

Je ne vais pas mettre cela comme une réponse, car il est orthogonal à votre question: mais je ne peux pas imaginer pourquoi vous voudriez cette interface utilisateur. En quoi cela est-il meilleur/plus rapide/plus facile qu'une boîte de saisie de texte que vous avez correctement analysée/validée dans votre formulaire? –

Répondre

0

Je ne peux pas reproduire le problème:

>>> class MyForm(forms.Form): 
...  t = forms.TimeField(widget=MilitaryTimeWidget()) 
... 
>>> print MyForm(data={'t_0': '13', 't_1': '34'}) 
******** 13:34:00 
<tr><th><label for="id_t_0">T:</label></th><td><select name="t_0" id="id_t_0"> 
<option value="0">00</option> 
[...] 
<option value="13" selected="selected">13</option> 
[...] 
<option value="23">23</option> 
</select><select name="t_1" id="id_t_1"> 
<option value="0">00</option> 
[...] 
<option value="34" selected="selected">34</option> 
[...] 
<option value="59">59</option> 
</select></td></tr> 

Vérifiez que votre request.POST est correcte.

En tant que sidenote, êtes-vous sûr que ce widget donne une bonne convivialité? Quatre clics de souris et le défilement possible du ... minutes combobox

+1

Je pense que mon problème est que je n'essaie pas de remplir le formulaire en utilisant les données POST, mais plutôt d'essayer de remplir en utilisant un de mes modèles. Puisqu'il me manque le arrival_time_0 et le arrival_time_1 (les noms donnés à chaque widget choisi) dans les données que je passe, il n'est pas peuplé. – ashchristopher

+1

Il semble assez lourd et non-pythonique de scinder sciemment ces données dans ma vue avant de passer dans le formulaire. Pensées? – ashchristopher

3

Remarque this line in the docstring for MultiWidget:

Vous aurez probablement envie d'utiliser cette classe avec MultiValueField.

C'est la racine de votre problème. Vous pourriez être en mesure d'obtenir l'approche de widget unique (Marty dit que c'est possible dans Pro Django, mais je ne l'ai jamais essayé, et je pense que c'est plus de travail), mais dans ce cas votre widget ne devrait pas être une sous-classe de MultiWidget.

Ce que vous devez faire (si vous voulez suivre le chemin MultiWidget/MultiValueField) est:

  • supprimer votre méthode de value_from_datadict
  • définir une sous-classe de MultiValueField avec une définition de la méthode compress() ce qui fait la tâche que vous faites actuellement dans value_from_datadict() (transformer une liste de nombres en un objet datetime.time)
  • Définissez votre Widget par défaut pour votre formulaire personnalisé Champ (en utilisant l'attribut de classe de widget)
  • créez un champ de modèle personnalisé Field qui renvoie votre formulaire personnalisé Field à partir de sa méthode formfield(), ou utilisez votre champ de formulaire personnalisé manuellement en tant que champ de remplacement dans un ModelForm.

Ensuite tout fonctionnera.

+0

On dirait que django.forms.fields.SplitDateTimeField et django.forms.widgets.SplitDateTimeWidget sont de bons modèles sur lesquels se baser. – akaihola

Questions connexes