2012-07-19 2 views
5

Quindi sto utilizzando l'interfaccia utente di jQuery su skin the radio buttons ma non riesco a ottenere da Django il rendering del mio modulo come deve essere fatto.Personalizzare i moduli Django con il widget RadioSelect

ho bisogno di avere questa struttura:

<table> 
    <tr> 
     <td><label for="notify_new_friends">Notify when new friends join</label></td> 
     <td class="radio"> 
      <input type="radio" name="notify_new_friends" id="notify_new_friends_immediately" value="1" checked="checked"/><label for="notify_new_friends_immediately">Immediately</label> 
      <input type="radio" name="notify_new_friends" id="notify_new_friends_never" value="0"/><label for="notify_new_friends_never">Never</label> 
     </td> 
    </tr> 
</table> 

Quindi, per riassumere che ho bisogno i pulsanti di scelta all'interno di una classe (radio), dove hanno un input e label for.

Quando mi rendo forma nel mio modello con {{ profile_form.notify_new_friends }} ottengo il seguente:

<ul> 
    <li><label for="id_notify_new_friends_0"><input type="radio" id="id_notify_new_friends_0" value="0" name="notify_new_friends" /> Immediately</label></li> 
    <li><label for="id_notify_new_friends_1"><input type="radio" id="id_notify_new_friends_1" value="1" name="notify_new_friends" /> Never</label></li> 
</ul> 

Che è esattamente quello che voglio, tranne per la lista-parte. Così ho provato loop su di essa, che mi dà le etichette formattate in modo diverso:

{% for item in profile_form.notify_new_friends %} 
    {{ item }} 
{% endfor %} 

che mi dà:

<label><input type="radio" name="notify_new_friends" value="0" /> Immediately</label> 
<label><input type="radio" name="notify_new_friends" value="1" /> Never</label> 

Così il problema qui è che si smette di usare label for e inizia utilizzando solo label a Wrapp è tutto con.

Ho anche provato a fare qualcosa di simile, ma poi il label e il label_tag non rendono nulla.

{{ profile_form.notify_new_friends.0 }} 
{{ profile_form.notify_new_friends.0.label_tag }} 
{{ profile_form.notify_new_friends.0.label }} 

Quindi qualcuno sa come posso rendere questo correttamente !?

Cordiali saluti, questo è il mio forms.py:

self.fields['notify_new_friends'] = forms.ChoiceField(label='Notify when new friends join', widget=forms.RadioSelect, choices=NOTIFICATION_CHOICES) 
+0

https://docs.djangoproject.com/en/dev/ref/forms/widgets/#radioselect - hai letto questo? –

+0

@ AlexanderA.Sosnovskiy sì, ma mi mancava il 'choice_label' per ottenere il titolo dell'etichetta, ma sfortunatamente facendo' {{radio.tag}} 'non mi fornisce un ID e quindi non posso fare' label for' che devo fare. Gli ID campo – olofom

+0

sono generati automaticamente, {{field.auto_id}} –

risposta

1

Dal momento che non sembra essere un buon modo per fare questo ho scelto di riorganizzare il codice generato utilizzando jQuery.

// First remove the ul and li tags 
$('.radio ul').contents().unwrap(); 
$('.radio li').contents().unwrap(); 
// Then move the input to outside of the label 
$('.radio > label > input').each(function() { 
    $(this).parent().before(this); 
}); 
// Then apply the jQuery UI buttonset 
$(".radio").buttonset(); 

Questo fatto andare da:

<ul> 
    <li><label for="id_notify_new_friends_0"><input type="radio" id="id_notify_new_friends_0" value="0" name="notify_new_friends" /> Immediately</label></li> 
    <li><label for="id_notify_new_friends_1"><input type="radio" id="id_notify_new_friends_1" value="1" name="notify_new_friends" /> Never</label></li> 
</ul> 

a:

<input type="radio" id="id_notify_new_friends_0" value="0" name="notify_new_friends" /><label for="id_notify_new_friends_0"> Immediately</label></li> 
<input type="radio" id="id_notify_new_friends_1" value="1" name="notify_new_friends" /><label for="id_notify_new_friends_1"> Never</label></li> 

e il mio stile jQuery UI funziona bene.

+0

Penso che se ci sono possibilità di farlo senza javascript, dovremmo evitare js ... Soprattutto sul caricamento della pagina - prestazioni peggiori, SEO peggiore. Se usiamo javascript per la manipolazione, dovrebbe essere una manipolazione dinamica che causa una ragione come l'interazione. – kspacja

+0

Non credo che un JavaScript che semplicemente riorganizza lo stesso contenuto della pagina possa influenzare il SEO. A parte questo, questa soluzione funziona potenzialmente molto bene nell'amministratore di Django, dove la SEO è irrilevante e il controllo dell'output HTML richiederebbe l'override di più classi di Django come menzionato nella risposta di tnajdek. – bpscott

5

Nel mio codice ho scoperto che la modifica del widget dal

forms.RadioSelect 

a

forms.RadioSelect(attrs={'id': 'value'}) 

magicamente fa sì che il tag valore risultante per includere l'attributo id con l'indice dell'elemento aggiunto. Se si utilizza

{% for radio in form.foo %} 
    <li> 
     {{ radio }} 
    </li> 
{% endfor %} 

in forma si ottiene un label avvolto intorno ad un input.Se si desidera che il più convenzionale input seguito da label, è necessario fare questo:

{% for radio in form.value %} 
    <li> 
     {{ radio.tag }} 
     <label for="value_{{ forloop.counter0 }}">{{ radio.choice_label }}</label> 
    </li> 
{% endfor %} 
0
Try like this , I got it.. 

from django.forms.widgets import RadioFieldRenderer 
from django.utils.encoding import force_unicode 
from django.utils.safestring import mark_safe 


class RadioCustomRenderer(RadioFieldRenderer): 
    def render(self): 
     return mark_safe(u'%s' % u'\n'.join([u'%s' % force_unicode(w) for w in self])) 

in form 

widgets = { 
      'validity': forms.RadioSelect(renderer=RadioCustomRenderer), 
     } 
1

Purtroppo questo è più complicato di quanto dovrebbe essere, a quanto pare è necessario sostituire almeno 2 classi: RadioRenderer e RadioInput. Quanto segue dovrebbe aiutarti a iniziare, ma potrebbe essere necessario modificarlo un po '.

Per prima cosa creare un widget di input per pulsante di opzione personalizzato. L'unico scopo di noi l'override del metodo Render è quello di sbarazzarsi di struttura fastidioso Django fa rispettare (<label><input /></label>) dove invece vogliamo la nostra (<label /><input />):

class CustomRadioInput(RadioInput): 
    def render(self, name=None, value=None, attrs=None, choices=()): 
     name = name or self.name 
     value = value or self.value 
     attrs = attrs or self.attrs 
     if 'id' in self.attrs: 
      label_for = ' for="%s_%s"' % (self.attrs['id'], self.index) 
     else: 
      label_for = '' 
      choice_label = conditional_escape(force_unicode(self.choice_label)) 
      return mark_safe(u'%s<label%s>%s</label>' % (self.tag(), label_for, choice_label)) 

Ora abbiamo bisogno di ignorare RadioRenderer al fine di:

  1. forzarlo per usare il nostro widget di ingresso radio personalizzato
  2. Rimuovere <li> wraping ogni campo di input singolo e <ul> il confezionamento di tutti i campi di input:

Qualcosa in questo senso dovrebbe fare:

class RadioCustomRenderer(RadioFieldRenderer): 
    def __iter__(self): 
     for i, choice in enumerate(self.choices): 
      yield CustomRadioInput(self.name, self.value, self.attrs.copy(), choice, i) 

    def __getitem__(self, idx): 
     choice = self.choices[idx] 
     return CustomRadioInput(self.name, self.value, self.attrs.copy(), choice, idx) 

    def render(self): 
     return mark_safe(u'%s' % u'\n'.join([u'%s' % force_unicode(w) for w in self])) 

Infine istruire Django utilizzare renderer personalizzato

notify_new_friends = forms.ChoiceField(label='Notify when new friends join', widget=forms.RadioSelect(renderer=RadioCustomRenderer), choices=NOTIFICATION_CHOICES) 

Si prega di tenere a mente: Emette ora pulsanti di opzione insieme che comprende <td>, quindi, si è necessario creare una tabella attorno al modello, qualcosa del genere:

<table> 
    <tr> 
    <td><label for="{{field.auto_id}}">{{field.label}}</label></td> 
    <td>{{ field.errors }} {{field}}</td> 
    </tr> 
</table>