2009-12-10 5 views
5

Estoy usando Django todos los días durante tres meses y es realmente genial. Rápido desarrollo de aplicaciones web.En forma Django, SelectField personalizado y SelectMultipleField

Todavía tengo una cosa que no puedo hacer exactamente como quiero. Es el Campo SelectField y SelectMultiple.

Quiero ser capaz de poner algunos args a una opción de Seleccionar.

finalmente éxito con el optgroup:

class EquipmentField(forms.ModelChoiceField): 
    def __init__(self, queryset, **kwargs): 
     super(forms.ModelChoiceField, self).__init__(**kwargs) 
     self.queryset = queryset 
     self.to_field_name=None 

     group = None 
     list = [] 
     self.choices = [] 

     for equipment in queryset: 
      if not group: 
       group = equipment.type 

      if group != equipment.type: 
       self.choices.append((group.name, list)) 
       group = equipment.type 
       list = [] 
      else: 
       list.append((equipment.id, equipment.name)) 

Pero por otro ModelForm, tengo que cambiar el color de fondo de todas las opciones, utilizando la propiedad color del modelo.

¿Sabes cómo puedo hacer eso?

Gracias.

Respuesta

5

Lo que necesita hacer es cambiar la salida que controla el widget. El valor predeterminado es el widget de selección, por lo que puede subclasificarlo. Se ve así:

class Select(Widget): 
    def __init__(self, attrs=None, choices=()): 
     super(Select, self).__init__(attrs) 
     # choices can be any iterable, but we may need to render this widget 
     # multiple times. Thus, collapse it into a list so it can be consumed 
     # more than once. 
     self.choices = list(choices) 

    def render(self, name, value, attrs=None, choices=()): 
     if value is None: value = '' 
     final_attrs = self.build_attrs(attrs, name=name) 
     output = [u'<select%s>' % flatatt(final_attrs)] 
     options = self.render_options(choices, [value]) 
     if options: 
      output.append(options) 
     output.append('</select>') 
     return mark_safe(u'\n'.join(output)) 

    def render_options(self, choices, selected_choices): 
     def render_option(option_value, option_label): 
      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</option>' % (
       escape(option_value), selected_html, 
       conditional_escape(force_unicode(option_label))) 
     # Normalize to strings. 
     selected_choices = set([force_unicode(v) for v in selected_choices]) 
     output = [] 
     for option_value, option_label in chain(self.choices, choices): 
      if isinstance(option_label, (list, tuple)): 
       output.append(u'<optgroup label="%s">' % escape(force_unicode(option_value))) 
       for option in option_label: 
        output.append(render_option(*option)) 
       output.append(u'</optgroup>') 
      else: 
       output.append(render_option(option_value, option_label)) 
     return u'\n'.join(output) 

Es un montón de código. Pero lo que necesita hacer es crear su propio widget con un método de renderizado alterado. Es el método de renderizado el que determina el html que se crea. En este caso, es el método render_options que necesita cambiar. Aquí podría incluir algún control para determinar cuándo agregar una clase, que podría diseñar.

Otra cosa, en su código anterior no parece que añada las últimas opciones de grupo. También es posible que desee agregar un order_by() al queryset, ya que necesita que se ordene por tipo. Podrías hacer eso en el método init, para que no tengas que hacerlo todo cuando uses el campo de formulario.

+0

Ok, entonces debería crear un SelectWidget completo. Lo intentaré, gracias. – Natim

0

No debe meterse con los campos de formulario para agregar algunos atributos personalizados a la etiqueta html representada. Pero deberías subclasificar y agregar estos al Widget.

Desde el docs: customizing-widget-instances

Puede enviar attrs diccionario para los widgets de formulario, que hacen como atributos en los widgets de formulario de salida.

class CommentForm(forms.Form): 
    name = forms.CharField(
       widget=forms.TextInput(attrs={'class':'special'})) 
    url = forms.URLField() 
    comment = forms.CharField(
       widget=forms.TextInput(attrs={'size':'40'})) 
Django will then include the extra attributes in the rendered output: 

>>> f = CommentForm(auto_id=False) 
>>> f.as_table() 
<tr><th>Name:</th><td><input type="text" name="name" class="special"/></td></tr> 
<tr><th>Url:</th><td><input type="text" name="url"/></td></tr> 
<tr><th>Comment:</th><td><input type="text" name="comment" size="40"/></td></tr> 
+0

Esto es para campo común. Y ya lo hago, pero ¿cómo lo haces para la opción de un SelectWidget? – Natim

Cuestiones relacionadas