2010-08-18 14 views
43

La documentazione è un po 'carente rispetto a questa funzionalità.Come si usa MultiWidget di 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] 

posso vedere che ho bisogno di creare un "widget" proprietà con una lista di altri widget, ma dopo che diventa un po 'Sherlock Holmes.

Qualcuno potrebbe spiegarmi come utilizzare il widget di MultiWidget?

+0

Questa soluzione è un po 'di un hack, ma è più in linea con il modo in cui ci aspettiamo di accedere sottocampi nel modello. http://stackoverflow.com/questions/24866936/render-only-one-part-of-a-multiwidget-in-django – farthVader

risposta

51

Interessante domanda e penso che forse meriti un po 'più di attenzione nei documenti.

Ecco un esempio da 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) 

Cos'hai ho fatto?

  • sottoclasse django.forms.widgets.MultiWidget
  • Implementato un costruttore che crea diversi widgets.WidgetName widget in un tupla. Questo è importante perché la super classe usa l'esistenza di questa tupla per prendersi cura di diverse cose per te.
  • Il mio formato di output è pass-through, ma l'idea è che è possibile aggiungere HTML personalizzato qui se desiderate
  • Ho anche implementato decompress perché è necessario - si dovrebbe aspettare di essere passati i valori dalla banca dati in un singolo oggetto value. decompress interrompe questa operazione per la visualizzazione nel widget. Come e cosa fai qui dipende da te e dipende dal widget.

cose che non ho, ma potrebbe avere, sovrascritto:

  • render, questo è in realtà responsabile per il rendering widget, quindi è sicuramente bisogno di chiamare il super metodo Render se sottoclasse questo. Puoi cambiare il modo in cui le cose vengono visualizzate appena prima del rendering suddividendole in sottoclassi.

Esempio, Django markitup 's rendere metodo:

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 - Vedere la mia domanda here. value_from_datadict estrae il valore associato a questo widget dal dizionario dei dati di tutti i dati inviati con questo modulo. Nel caso di una multiwidget che rappresenta un singolo campo, è necessario ricostruire quel valore dai tuoi subparti multipli, che è il modo in cui i dati saranno stati inviati.
  • _get_media potrebbe essere utile per te se desideri recuperare i media utilizzando la rappresentazione di media di django. L'implementazione predefinita esegue il ciclo dei widget che richiedono il supporto; se la si sottoclasse e si utilizzano widget fantastici, è necessario chiamare il super; se il tuo widget ha bisogno di qualsiasi media, devi aggiungerlo usando questo.

Per esempio, widget di markitup s' django fa questo:

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) 

Ancora una volta, è la creazione di una tupla di percorsi nella posizione corretta, proprio come il mio widget di ha creato una tupla di widget nel Metodo __init__.

Penso che la ricopre per importanti parti della classe MultiWidget. Quello che stai cercando di fare dipende da ciò che hai creato/dai widget che stai usando, ed è per questo che non posso entrare facilmente nei dettagli. Tuttavia, se vuoi vedere la classe base per te stesso e dare un'occhiata ai commenti, dai un'occhiata a the source.

+1

Sicuramente la migliore guida all'argomento sulla creazione di campi modulo multi-widget che ho visto fino ad oggi, e credo di averne visti parecchi! –

+0

Potete fornire un esempio di come utilizzare un multi-widget in un modulo del modello per due campi in tale forma? O il multi-widget è progettato per suddividere i campi e non combinarli? –

+0

Il metodo 'format_output' è stato deprecato e non esiste più nella classe Widget. – Cerin

0

Leggere attraverso questo blog entry e l'associato Django snippet. Spero che questo ti dia qualche idea.

+0

Grazie. Lo snippet fornisce più indizi. Ma è ancora un lavoro da investigatore. Sto spigolando come usarlo leggendo il codice e vedendo i campioni. Sto ancora sperando che qualcuno che ha già risolto questo mistero possa offrire un po 'di guida per noi da consumare. –