2017-09-27 3 views
1

Voici un code qui fonctionne comme prévu dans Django 1.9:Migration Django 1,9 à 1,11: problèmes avec MultiValueField et le comportement MultiWidget

class MultipleBooleanField(forms.MultiValueField): 
    def __init__(self, *args, **kwargs): 
     self.fieldnames = kwargs.pop('fields') 
     fields = [ forms.BooleanField(required=False) for x in self.fieldnames ] 
     super(MultipleBooleanField, self).__init__(fields=fields, 
          require_all_fields=False, *args, **kwargs) 
     self.widget = MultipleBooleanWidget(widgets=[ f.widget for f in fields ]) 
     self.widget.fieldnames = self.fieldnames 

    def compress(self, datalist): 
     # return a list of the fieldnames, datalist is a list of booleans    
     print('compress datalist:', datalist) 
     if self.required and not any(datalist): 
      raise forms.ValidationError('You must choose at least one value') 
     return [ self.fieldnames[i] for i in range(len(datalist)) if datalist[i] ] 

class MultipleBooleanWidget(forms.MultiWidget): 
    def render(self, name, value, attrs=None, renderer=None): 
     if not value: 
      value = [ False for x in self.fieldnames ] 
     rendered_widgets = [ x.render(name, value[i]) for i,x in enumerate(self.widgets) ] 
     items = [ '%s %s' % (rendered_widgets[i], f) 
           for (i,f) in enumerate(self.fieldnames) ] 
     return ' '.join(items) 

    def decompress(self, value): 
     # return a list of booleans, value is a list of fieldnames 
     print('decompress value:', value) 
     if not value: 
      return [ False for x in self.fieldnames ] 
     return [ x in value for x in self.fieldnames ] 

Avec Django 1.11, il ne travaille pas plus, le ValidationError est toujours élevé. Le datalist est toujours une liste contenant seulement False. La méthode decompress n'est jamais appelée.

J'ai essayé d'implémenter une méthode value_from_datadict comme suggéré dans de très anciens messages, mais sans succès. Je regarde le code Djando et il semble que Django n'aime pas que le résultat du champ (la valeur de retour de compress) soit une liste, donc j'ai essayé de le transformer en une chaîne (comme des valeurs jointes par des virgules). Mais le comportement reste le même.

Des idées?

EDIT: regardant la source HTML, il semble que subwidgets ne sont pas rendus correctement: ils ont tous le même nom, et ne pas avoir id. Supposons que le nom du champ est Valeurs:

Dans Django 1.9, le HTML est:

<tr><th><label for="id_Valeurs_0">Valeurs :</label></th><td><input checked="checked" id="id_Valeurs_0" name="Valeurs_0" type="checkbox" /> Part du total com <input checked="checked" id="id_Valeurs_1" name="Valeurs_1" type="checkbox" /> Part du total Qté <input checked="checked" id="id_Valeurs_2" name="Valeurs_2" type="checkbox" /> ... 

Dans Django 1.11, le HTML est:

<tr><th><label for="id_Valeurs_0">Valeurs :</label></th><td><input type="checkbox" name="Valeurs" checked /> Part du total com <input type="checkbox" name="Valeurs" checked /> Part du total Qté <input type="checkbox" name="Valeurs" checked /> 

J'ai d'autres MultiValueField/MultiWidget qui fonctionnent correctement, INSCRIPTIONS très similaire. Je ne comprends vraiment pas où est le problème.

Répondre

1

Je trouve le problème: il vient du calcul de rendered_widgets dans la méthode render, il doit être:

rendered_widgets = [ x.render('%s_%d' % (name,i), value[i]) for i,x in enumerate(self.widgets) ] 

Avec cette solution, le rendu HTML a des noms corrects, mais ont toujours pas id. Mais ça fonctionne.

Je ne comprends pas pourquoi l'équipe django a supprimé la méthode format_output de MultiWidget: c'était utile, facile, de haut niveau. Avoir à composer avec render est douloureux, mais peut-être que j'ai raté quelque chose ...