В форме Django, как мне сделать радио-кнопку, чтобы выбор был разделен на странице? - PullRequest
8 голосов
/ 20 июля 2011

У меня есть форма Django с элементом переключателя с двумя вариантами выбора. Я хочу, чтобы форма отображалась более или менее так:

( ) 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:                  [           ]

Другими словами, я хочу разделить два варианта переключателя. Как я могу это сделать? При использовании рендеринга формы form.as_table по умолчанию варианты отображаются рядом друг с другом, что мне не нужно.

(Извинения перед NASCAR и оперными энтузиастами.)

Ответы [ 2 ]

5 голосов
/ 28 июля 2011

Я немного покопался и нашел ответ в этом подобном посте , который указывает на несколько устаревший пост в django-users .

Заимствуя некоторый код из метода as_widget () в forms.py , я разработал метод, который я мог бы добавить в свою форму для получения вариантов виджетов RadioSelect, отображаемых как 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)

Затем в шаблоне вы можете получить доступ к отдельным переключателям, например:

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

или

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

Я почти уверен, что это плохая идея.Вероятно, в какой-то момент он перестанет работать, так как django развивается.Это нарушает DRY, копируя код из as_widget ().(TBH, я не нашел времени, чтобы полностью понять код из as_widget) Я использую его только как временный взлом.Возможно, есть лучший способ, который использует пользовательские теги шаблонов.Если это так, пожалуйста, дайте мне знать.

4 голосов
/ 21 июля 2011

Виджет RadioSelect по умолчанию выводит свои выходные данные в неупорядоченный список.

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

Будет выводить:

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

Это сделает каждый выбор радиостанции отдельной строкой. Возможно, вам понадобится добавить немного CSS, чтобы получить рендеринг именно так, как вы хотите, но это должно дать вам необходимую структуру. Конечно, вы можете написать текст вручную, просто сделав ...

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

... но я предпочитаю писать свой HTML вручную.

...