2012-07-19 15 views
5

Así que estoy usando jQuery UI en skin the radio buttons pero no puedo hacer que Django renderice mi formulario de la forma en que debe hacerlo.Personalizar formularios de Django con el widget RadioSelect

Necesito tener esta estructura:

<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> 

Entonces, para resumir lo que necesito los botones de radio dentro de una clase (de radio) donde tienen un input y una label for.

cuando me hacen la forma en mi plantilla con {{ profile_form.notify_new_friends }} consigo el siguiente:

<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> 

¿Qué es exactamente lo que quiero, excepto para la lista de partes. Así que traté de bucle sobre ella que me da las etiquetas con formato diferente:

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

que me da:

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

lo tanto, el problema aquí es que se deja de usar label for y comienza a utilizar simplemente label a WRAPP se todo con.

También intenté hacer algo como esto, pero luego label y label_tag no representan nada.

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

Así que ¿alguien sabe cómo puedo hacer esto correctamente !?

FYI, esta es mi 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 - ¿Has leído esto? –

+0

@ AlexanderA.Sosnovskiy sí, pero me había perdido el 'choice_label' para obtener el título de la etiqueta, pero lamentablemente hacer' {{radio.tag}} 'no me proporciona una identificación y, por lo tanto, no puedo hacer' label for' lo cual necesito hacer – olofom

+0

id de campo se auto generan try, {{field.auto_id}} –

Respuesta

1

Puesto que no parece ser una buena manera de hacer esto que elegí para reorganizar el código generado usando 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(); 

Esto hizo que se vaya a partir de:

<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> 

y mi estilo jQuery UI funciona bien.

+0

Creo que si hay posibilidades de hacerlo sin javascript, debemos evitar js ... Especialmente en la carga de la página: peor rendimiento, peor SEO. Si usamos javascript para la manipulación, debería ser una manipulación dinámica que cause una interacción similar a la razón. – kspacja

+0

No creo que un JavaScript que simplemente reorganice el mismo contenido en la página pueda afectar el SEO. Aparte de eso, esta solución potencialmente funciona muy bien en el administrador de Django, donde el SEO es irrelevante y controlar el resultado HTML requeriría anular múltiples clases de Django como se menciona en la respuesta de tnajdek. – bpscott

5

En mi código que he descubierto que cambiando el widget de

forms.RadioSelect 

a

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

mágicamente hace que el tag valor resultante de incluir el atributo id con el índice del elemento añadido. Si utiliza

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

en forma se obtiene una label envuelta alrededor de una input.Si desea que el más convencional input seguido por label, lo que necesita hacer esto:

{% 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

Desafortunadamente esto es más complicado de lo que debería ser, parece que necesita para anular al menos 2 clases: RadioRenderer y RadioInput. Lo siguiente debería ayudarte a comenzar, pero es posible que debas modificarlo un poco.

Primero cree un widget de entrada de botón de radio personalizado. El único propósito de nosotros reemplazando el método render es deshacerse de la estructura molesto Django hace cumplir (<label><input /></label>) donde en vez queremos que nuestro (<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)) 

Ahora tenemos que sobreescribir RadioRenderer con el fin de:

  1. forzar que se use nuestro widget de entrada de radio personalizada
  2. Retire <li> wraping todos los campos de entrada única y <ul> envolver todos los campos de entrada:

Algo a lo largo de estas líneas debe hacer:

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])) 

Finalmente Instruir Django utilizar encargo procesador

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

Por favor, tenga en cuenta: Esto ahora da salida a los botones de radio junto con abarcando <td> por lo tanto usted necesita construir una tabla a su alrededor en su plantilla, algo en esta línea:

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