2010-08-18 2 views
43

La documentation manque un peu par rapport à cette fonctionnalité.Comment utiliser le MultiWidget de Django?

from django import forms 

class TwoInputWidget(forms.MultiWidget): 
    """An example widget which concatenates two text inputs with a space""" 
    def __init__(self, attrs=None): 
     widgets = [forms.TextInput, forms.TextInput] 

Je peux voir que je dois créer un « widgets » propriété avec une liste d'autres widgets, mais après cela, il est un peu Sherlock Holmes.

Quelqu'un pourrait-il m'expliquer comment utiliser le widget MultiWidget?

+0

Cette solution est un peu un hack, mais est plus en ligne avec la façon dont nous nous attendons à accéder aux sous-champs dans le modèle. http://stackoverflow.com/questions/24866936/render-only-one-part-of-a-multiwidget-in-django – farthVader

Répondre

51

Question intéressante et je pense peut-être mériter un peu plus d'attention dans les docs.

Voici un exemple de a question I've just asked:

class DateSelectorWidget(widgets.MultiWidget): 
    def __init__(self, attrs=None, dt=None, mode=0): 
     if dt is not None: 
      self.datepos = dt 
     else: 
      self.datepos = date.today()  

     # bits of python to create days, months, years 
     # example below, the rest snipped for neatness. 

     years = [(year, year) for year in year_digits] 

     _widgets = (
      widgets.Select(attrs=attrs, choices=days), 
      widgets.Select(attrs=attrs, choices=months), 
      widgets.Select(attrs=attrs, choices=years), 
      ) 
     super(DateSelectorWidget, self).__init__(_widgets, attrs) 

    def decompress(self, value): 
     if value: 
      return [value.day, value.month, value.year] 
     return [None, None, None] 

    def format_output(self, rendered_widgets): 
     return u''.join(rendered_widgets) 

Qu'as-je fait?

  • subclassed django.forms.widgets.MultiWidget
  • Mis en œuvre un constructeur qui crée plusieurs widgets.WidgetName widgets dans un tuple . Ceci est important car la super classe utilise l'existence de ce tuple pour prendre soin de plusieurs choses pour vous.
  • Ma sortie de format est traversable, mais l'idée est que vous pouvez ajouter du code HTML personnalisé ici si vous souhaitez
  • J'ai aussi mis en œuvre decompress parce que vous devez - vous devriez vous attendre à des valeurs passées de la base de données dans un seul objet value. decompress rompt ceci pour l'affichage dans le widget. Comment et ce que vous faites ici est à vous et dépend du widget.

choses que j'ai pas, mais pourrait avoir, overriden:

  • render, c'est en fait responsable du rendu des widgets, vous devez certainement appeler le super rendu méthode si vous sous-classe cela. Vous pouvez changer la façon dont les choses sont affichées juste avant le rendu en le sous-classant.

Exemple, django markitup « s méthode render:

def render(self, name, value, attrs=None): 
    html = super(MarkItUpWidget, self).render(name, value, attrs) 

    if self.auto_preview: 
     auto_preview = "$('a[title=\"Preview\"]').trigger('mouseup');" 
    else: auto_preview = '' 

    html += ('<script type="text/javascript">' 
      '(function($) { ' 
      '$(document).ready(function() {' 
      ' $("#%(id)s").markItUp(mySettings);' 
      ' %(auto_preview)s ' 
      '});' 
      '})(jQuery);' 
      '</script>' % {'id': attrs['id'], 
          'auto_preview': auto_preview }) 
    return mark_safe(html) 
  • value_from_datadict - Voir ma question here. value_from_datadict extrait la valeur associée à ce widget du dictionnaire de données de toutes les données soumises avec ce formulaire. Dans le cas d'un multi-widget représentant un seul champ, vous devez reconstruire cette valeur à partir de vos sous-widgets multiples, ce qui correspond à la façon dont les données auront été soumises.
  • _get_media peut vous être utile si vous souhaitez récupérer des médias à l'aide de la représentation django des médias. L'implémentation par défaut effectue un cycle des widgets demandant le support. si vous le sous-classez et que vous utilisez des widgets sophistiqués, vous devez appeler le super; Si votre widget nécessite un média, vous devez l'ajouter en utilisant ceci.

Par exemple, widget django de markitup Est-ce:

def _media(self): 
     return forms.Media(
      css= {'screen': (posixpath.join(self.miu_skin, 'style.css'), 
          posixpath.join(self.miu_set, 'style.css'))}, 
      js=(settings.JQUERY_URL, 
       absolute_url('markitup/jquery.markitup.js'), 
       posixpath.join(self.miu_set, 'set.js'))) 
    media = property(_media) 

Encore une fois, il crée un tuple de chemins vers l'emplacement correct, tout comme mon widget de a créé un tuple de widgets dans la __init__ méthode.

Je pense que cela couvre les parties importantes de la classe MultiWidget. Ce que vous essayez de faire dépend de ce que vous avez créé/quels widgets vous utilisez, c'est pourquoi je ne peux pas entrer dans les détails facilement. Cependant, si vous voulez voir la classe de base pour vous et jeter un oeil sur les commentaires, jetez un oeil à the source.

+1

Certainement le meilleur guide de sujet sur la création de champs de formulaire multi-widget que j'ai vu à ce jour, et je crois que j'en ai vu pas mal! –

+0

Pouvez-vous donner un exemple d'utilisation d'un widget multiple dans un formulaire de modèle pour deux champs de ce formulaire? Ou est-ce que le multi-widget conçu pour séparer les champs ne les combine pas? –

+0

La méthode 'format_output' était obsolète et n'existe plus dans la classe Widget. – Cerin

0

Lisez ce blog entry et le Django associé snippet. J'espère que cela vous donne quelques idées.

+0

Merci. L'extrait fournit plus d'indices. Mais c'est toujours un travail de détective. Je glane comment l'utiliser en lisant le code et en voyant les échantillons. J'espère encore que quelqu'un qui a déjà résolu ce mystère puisse nous donner un petit guide pratique à consommer. –

Questions connexes