2011-07-20 7 views
8

Mam formularz Django z elementem przycisku wyboru z dwoma opcjami. Chcę, aby formularz wyglądał mniej więcej tak:W formularzu Django w jaki sposób renderować przycisk opcji, aby wybory były rozdzielone na stronie?

 
() I prefer beer 
    The last sporting event I attended was: [   ] 
    My favorite NASCAR driver is:   [   ] 

() I prefer wine 
    The last opera/play I attended was:  [   ] 
    My favorite author is:     [   ] 

Innymi słowy, chcę podzielić dwa wybory opcji radiowych. Jak mogę to zrobić? Używając domyślnego renderowania form.as_table, wybory są rysowane obok siebie, których nie chcę.

(Przeprosiny NASCAR i miłośników opery.)

Odpowiedz

4

Widget RadioSelect odda swoje wyjście domyślnie na liście nieuporządkowanej.

#forms.py 
BEER = 0 
WINE = 1 
PREFERRED_DRINK_CHOICES = (
    (BEER, 'Beer'), 
    (WINE, 'Wine'), 
) 

class DrinkForm(forms.Form): 
    preferred_drink = forms.ChoiceField(choices=PREFERRED_DRINK_CHOICES, 
             widget=forms.RadioSelect()) 

#views.py 
def test(request): 
    form = DrinkForm(request.POST or None) 
    if request.method == 'POST': 
     if form.is_valid(): 
      print 'form was valid' 
    return render_to_response('test.html', {'form' : form}, 
     context_instance=RequestContext(request)) 

#test.html 
<form action="." method="post" enctype="multipart/form-data"> 
    <ul> 
     <li> 
      {{ form.name.label_tag }} 
      {{ form.name }} 
      {{ form.name.errors }} 
     </li> 
     <li> 
      {{ form.email.label_tag }} 
      {{ form.email }} 
      {{ form.email.errors }} 
     </li> 
     <li> 
      {{ form.preferred_drink.label_tag }} 
      {{ form.preferred_drink }} 
      {{ form.preferred_drink.errors }} 
     </li> 
     <li> 
     <input type="submit" value="Submit" /> 
     </li> 
    </ul> 
</form> 

wyświetli:

<form enctype="multipart/form-data" method="post" action="."> 
    <ul> 
    <li> 
      <label for="id_name">Name</label> 
      <input type="text" maxlength="50" name="name" id="id_name"> 
    </li> 
    <li> 
     <label for="id_email">Email</label> 
     <input type="text" id="id_email" name="email"> 
    </li> 
    <li> 
     <label for="id_preferred_drink_0">Preferred drink</label> 
     <ul> 
        <li> 
         <label for="id_preferred_drink_0"> 
          <input type="radio" name="preferred_drink" value="0" id="id_preferred_drink_0"> Beer</label> 
        </li> 
        <li> 
         <label for="id_preferred_drink_1"><input type="radio" name="preferred_drink" value="1" id="id_preferred_drink_1"> Wine</label> 
        </li> 
       </ul> 
     </li> 
    <li> 
     <input type="submit" value="Submit"> 
    </li> 
    </ul> 
</form> 

To uczyni każdy wybór radiową na własnej linii. Prawdopodobnie będziesz musiał dodać trochę kodu CSS, aby uzyskać renderowanie w pożądany sposób, ale powinno to zapewnić potrzebną strukturę. Oczywiście, możesz skrócić pisanie kodu HTML ręcznie ...

<form action="." method="post"> 
    <ul> 
     {{ form.as_ul }} 
     <li> 
      <input type="submit" value="Submit" /> 
     </li> 
    </ul> 
</form> 

... ale wolę pisać mój HTML ręcznie.

+0

Ale to nadal drukuje dwie opcje na sąsiednich liniach, prawda? To nie jest to, co próbuję zrobić. Chcę, aby dwa przyciski opcji były szeroko rozdzielone, z blokami pól pod każdym z nich, tak jak w przykładzie "nascar/opera". –

+0

Jeśli piszesz HTML ręcznie, możesz umieścić dodatkowe pola lub znaczniki tam, gdzie chcesz. użycie form.as_ul ograniczy to, co możesz zrobić. – Brandon

+0

Jaka jest składnia do renderowania pojedynczego wyboru elementu przycisku wyboru z wieloma opcjami wyboru? ** {{form.preferred_drink}} ** wyświetla wszystkie opcje. –

5

Zrobiłem małe kopanie i znalazłem ołowiu w odpowiedzi na ten , który wskazuje na nieco przestarzałe post in django-users.

Pożyczanie kodu z metody as_widget() w forms.py Stworzyłem metodę, którą mógłbym dodać do mojego formularza, aby pobrać opcje widżetu RadioSelect wykonane jako HTML.

class MyForm(forms.Form): 
    MY_CHOICES = (
     ('opt0', 'Option zero'), 
     ('opt1', 'Option one'), 
    ) 
    myfield = forms.ChoiceField(widget=forms.RadioSelect, choices=MY_CHOICES) 

    def myfield_choices(self): 
     """ 
     Returns myfield's widget's default renderer, which can be used to 
      render the choices of a RadioSelect widget. 
     """ 
     field = self['myfield'] 
     widget = field.field.widget 

     attrs = {} 
     auto_id = field.auto_id 
     if auto_id and 'id' not in widget.attrs: 
      attrs['id'] = auto_id 

     name = field.html_name 

     return widget.get_renderer(name, field.value(), attrs=attrs) 

Następnie w szablonie można uzyskać dostęp do indywidualnych wyborów przycisk radiowy tak:

<ul> 
    <li> 
     {{ myform.myfield_choices.0 }} 
     My custom HTML that goes with choice 0 
    </li> 
    <li> 
     {{ myform.myfield_choices.1 }} 
     Different HTML that goes with choice 1 
    </li> 
</ul> 

lub

{% for choice in myform.myfield_choices %} 
    <div> 
     {{ choice }} 
    </div> 
{% endfor %} 

Jestem całkiem pewien, że to zły pomysł. Prawdopodobnie przestanie działać w pewnym momencie, gdy django ewoluuje. Narusza DRY, kopiując kod z as_widget(). (TBH, nie poświęcałem czasu na pełne zrozumienie kodu z as_widget) Używam go jako tymczasowego hackowania. Być może istnieje lepszy sposób, który obejmuje niestandardowe tagi szablonów. Jeśli tak, proszę dać mi znać.

Powiązane problemy