2010-06-07 4 views
1

J'ai un modèleComment définir le titre et la classe dans le code HTML pour les options d'un ModelChoiceField?

class MyModel(models.Model): 
    name = models.CharField(max_length=80, unique=True) 
    parent = models.ForeignKey('self', null=True, blank=True) 

Je veux rendre un ModelChoiceField pour ce modèle qui ressemble à:

<select name="mymodel" id="id_mymodel"> 
    <option value="1" title="Value 1" class="">Value 1</option> 
    <option value="2" title="Value 2" class="Value 1">Value 2</option> 
</select> 

Les différences entre cette sortie et la sortie par défaut pour un ModelChoiceField sont le titre et la classe éléments dans l'étiquette OPTION. Ils n'existent pas dans la sortie par défaut de ModelChoiceField.

Pour ma:

  • L'élément de titre est censé être le nom de l'option.
  • L'élément de classe est supposé être self.parent.name. (c'est mon problème)

Ainsi, dans le code HTML ci-dessus, la valeur 1 n'a pas de parent et la valeur 2 a un parent de la valeur 1.

Quel est le meilleur mécanisme pour changer ModelChoiceField ' s Sortie HTML par défaut?


EDIT: Je comprends comment créer un nouveau widget pour le rendu HTML. Le problème est de savoir comment afficher une valeur à partir du modèle sous-jacent dans chacune des options.

Répondre

2

Vous pouvez faire votre propre widget:

from django.forms.widgets import Select 

class MySelect(Select): 

    def __init__(self, attrs=None, choices=(), model): 
     self.model = model 
     super(Select, self).__init__(attrs) 

    def render_options(self, choices, selected_choices): 
     def render_option(option_value, option_label): 
      option_value = force_unicode(option_value) 
      option = self.model.objects.get(pk=option_value) 
      selected_html = (option_value in selected_choices) and u' selected="selected"' or '' 
      return u'<option value="%s"%s class="%s">%s</option>' % (
       escape(option_value), selected_html, 
       str(obj.parent.name), 
       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) 

Si vous voulez aussi au hasard l'étiquette du terrain: la classe de champ a une méthode label_from_instance.

+0

Je ne pense pas que vous avez vu la modification de ma question (quelques minutes avant que vous ajoutiez votre réponse). Comment proposez-vous que j'accède au modèle sous-jacent pour obtenir l'information parent? – cethegeek

+1

Si vous regardez mon code: Vous passez le modèle sous-jacent au widget lorsque vous l'initialisez et obtenez le parent (et d'autres informations) via option = self.model.objects.get (pk = option_value), alors vous pouvez rendre n'importe quel de l'information dans cet objet d'option; n'est-ce pas ce que tu voulais? et oui j'ai lu votre edit et l'ai compris comme ça ... –

+1

Désolé, j'aurais du lire ton code de plus près que moi. Je t'ai mis à jour. Je préférerais avoir une solution qui n'atteindrait pas le db une fois pour chaque option cependant ... Je pense que je vais adapter votre idée et passer une dict avec les valeurs dont j'ai besoin dans le widget. – cethegeek

1

Regardez mon exemple sur la façon de créer des champs personnalisés dans this post

+0

Voir la modification à ma question Merci, mais le problème n'est pas simplement de rendre un balisage, mais de rendre les données de l'objet sous-jacent dans le balisage. – cethegeek

Questions connexes