2011-02-23 14 views
13
PLANNING_CHOICES = (
    ('0',u'Every morning'), 
    ('1',u'Every night'), 
    ('2',u'Never'), 
) 

    planning = forms.ChoiceField(
           required=True,  
           choices = PLANNING_CHOICES, 
           ) 

Tener una planificación tales campo de formulario con nombre, tengo que añadir el atributo título de opciones y al final se renderiza como esto:Django opciones de campo de formulario, añadiendo un atributo

   <select> 
        <option value="0" title="bla1">Every morning</option> 
        <option value="1" title="bla2">Every night</option> 
        <option value="2" title="bla3">Never</option> 
       </select> 

¿Cómo puede lograrse ?

Respuesta

19

Tendría que subclasificar el campo para tomar cualquier medio de especificar el título que desea y el widget para mostrar el nuevo atributo.

Si tuviera algo como esto (nota: no probado del todo):

from django import forms 
from django.utils.html import escape 
from django.utils.encoding import force_unicode 

class SelectWithTitles(forms.Select): 
    def __init__(self, *args, **kwargs): 
     super(SelectWithTitles, self).__init__(*args, **kwargs) 
     # Ensure the titles dict exists 
     self.titles = {} 

    def render_option(self, selected_choices, option_value, option_label): 
     title_html = (option_label in self.titles) and \ 
      u' title="%s" ' % escape(force_unicode(self.titles[option_label])) or '' 
     option_value = force_unicode(option_value) 
     selected_html = (option_value in selected_choices) and u' selected="selected"' or '' 
     return u'<option value="%s"%s%s>%s</option>' % (
      escape(option_value), title_html, selected_html, 
      conditional_escape(force_unicode(option_label))) 

class ChoiceFieldWithTitles(forms.ChoiceField): 
    widget = SelectWithTitles 

    def __init__(self, choices=(), *args, **kwargs): 
     choice_pairs = [(c[0], c[1]) for c in choices] 
     super(ChoiceFieldWithTitles, self).__init__(choices=choice_pairs, *args, **kwargs) 
     self.widget.titles = dict([(c[1], c[2]) for c in choices]) 

... usted debe ser capaz de hacer esto:

PLANNING_CHOICES_WITH_TITLES = (
    ('0', 'Every morning', 'bla1'), 
    ('1', 'Every night', 'bla2'), 
    ('2', 'Never',   'bla3'), 
) 

planning = forms.ChoiceFieldWithTitles(
    required=True, choices=PLANNING_CHOICES_WITH_TITLES) 
+0

wow gracias insin, ¡he aprendido mucho de tu respuesta! – Hellnar

+0

No es que 'render_option' sea una característica no documentada y se haya eliminado de Django 1.11 en adelante. – djbp

3

No puede. No sin demasiados hackers, al menos.

Probablemente sea bueno usar form_utils.BetterForm, un paquete externo en lugar de django.forms.Form si desea tener esto y más control sobre el marcado generado.

5

Así es como he resuelto el problema

#models.py 
class Publisher(models.Model): 
    slug = models.Slugfield() 

class Book(forms.ModelForm): 
    publisher = models.ForeignKey(Publisher) 

#forms.py 
from django import forms 
from django.utils.encoding import force_unicode 
from django.utils.html import escape, conditional_escape 

class SelectWithData(forms.Select): 
    def render_option(self, selected_choices, option_value, option_label): 
     obj_data = { 
      obj.id: { 
       data_attr: getattr(obj, data_attr) for data_attr in self.data_attrs 
      } for obj in self.queryset 
     } 

     data_text = u'' 
     for data_attr in self.data_attrs: 
      data_text += u' data-{}="{}" '.format(
       data_attr, 
       escape(force_unicode(obj_data[option_value][data_attr])) 
      ) 

     option_value = force_unicode(option_value) 
     selected_html = (option_value in selected_choices) and u' selected="selected"' or '' 
     return u'<option value="{}"{}{}>{}</option>'.format(
      escape(option_value), 
      data_text, 
      selected_html, 
      conditional_escape(force_unicode(option_label)) 
     ) 


class ModelChoiceFieldWithData(forms.ModelChoiceField): 
    widget = SelectWithData 

    def __init__(self, queryset, **kwargs): 
     data_attrs = kwargs.pop('data_attrs') 
     super(ModelChoiceFieldWithData, self).__init__(queryset, **kwargs) 
     self.widget.queryset = queryset 
     self.widget.data_attrs = data_attrs 


class BookForm(forms.ModelForm): 

    publisher = ModelChoiceFieldWithData(
     queryset=Publisher.objects.all(), 
     data_attrs=('slug',), 
    ) 

#html 

<select id="id_publisher" name="publisher" required="required" title=""> 
    <option value="1" data-slug="first" selected="selected">First Publisher</option> 
    <option value="2" data-slug="second">Second Publisher</option> 
</select> 
Cuestiones relacionadas