форма входа радио Джанго макет

каков способ" djangoy " подойти к этой проблеме:

в моем классе формы, у меня есть формы.ChoiceField, виджет которого является формами.Виджет RadioSelect, один из вариантов которого должен быть представлен встроенным текстовым вводом (который также является полем в форме). Я использую пользовательскую проверку, чтобы игнорировать текстовое поле, когда его выбор радио Не выбран. При визуализации я хочу, чтобы он выглядел следующим образом:

<ul>
<li><label for="id_rad_0"><input type="radio" id="id_rad_0" value="none" name="rad" /> No Textbox</label></li>
<li><label for="id_rad_1"><input type="radio" id="id_rad_1" value="one" name="rad" /> One Textbox: <input type="text" name="bar" id="id_bar" /></label></li>
</ul>

однако я не могу просто создать это в моем шаблоне, потому что выбор радио не подвергается. Я не вижу способа сделать это без плотного соединения моей формы с моим шаблоном или поочередно, помещая всю логику представления в класс формы. Что такое право способ решить эту проблему?

редактировать

Я понимаю, что вышесказанное может быть просто неясной проблемой, но я не уверен, какую другую информацию я могу предоставить, чтобы вдохновить кого-то помочь мне в этом. Я много лучше бэкэнд-программист, чем веб - дизайнер, и я в этом проекте один, так что, может быть, это недостаток образования-это то, что я описал, просто плохой дизайн? Должен ли я просто спроектировать это по-другому? Я действительно открыт для любого предложения здесь, которое поможет мне пройти мимо этого.

Изменить 2

по запросу, текущий код, сокращенный, чтобы сохранить здравомыслие, имена изменены, чтобы защитить невинных:

# forms.py
from myapp.models import RatherComplicatedModel
from django import forms

class RatherComplicatedForm(forms.ModelForm):
    #various and sundry code...
    RADIO_CHOICES = (
        ('none', "No Textbox"),
        ('one', "One Textbox: "),
    )
    # although I've abbreviated the model, 'rad' does not appear in the model;
    # it merely provides input to the un-provided clean function
    rad = forms.ChoiceField(widget=forms.RadioSelect(),choices=RADIO_CHOICES)

    class Meta:
        model = RatherComplicatedModel

-

# models.py
from django.db import models

class RatherComplicatedModel(models.Model):
    #some other stuff...
    bar = models.IntegerField(blank=True,null=True)

4 ответов


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

<ul>
    {# Assuming {{ field }} here is {{ form.rad }} #}
    {% for choice in field.field.choices %}
    <li>
        <label for="id_{{ field.html_name }}_{{ forloop.counter0 }}">
            <input type="radio"
                id="id_{{ field.html_name }}_{{ forloop.counter0 }}"
                value="{{ choice.0 }}"
                name="{{ field.html_name }}" />
            {{ choice.1 }}
            {% if choice.0 == 'one' %}
                {# Necessary field here #}
                {{ form.bar }}
            {% else %}
                No Textbox
            {% endif %}
        </label>
    </li>
    {% endfor %}
</ul>

ответ Антона сработал, и некоторое время был достойным ответом - но, к сожалению, он стал недостижимым. Итак, беря пример с сравнения присоединен к билет Джанго #9230, Я просто патченные django.forms.forms.BoundField

from django import forms

def MonkeyPatchDjangoFormsBoundField():
    def prepare_widget_render(self, widget=None, attrs=None, only_initial=False):
        """
        Prepare the data needed for the widget rendering.
        """
        if not widget:
            widget = self.field.widget

        attrs = attrs or {}
        auto_id = self.auto_id
        if auto_id and 'id' not in attrs and 'id' not in widget.attrs:
            if not only_initial:
                attrs['id'] = auto_id
            else:
                attrs['id'] = self.html_initial_id

        if not only_initial:
            name = self.html_name
        else:
            name = self.html_initial_name

        return widget, name, attrs

    def as_widget(self, widget=None, attrs=None, only_initial=False):
        """
        Renders the field by rendering the passed widget, adding any HTML
        attributes passed as attrs.  If no widget is specified, then the
        field's default widget will be used.
        """
        widget, name, attrs = self.prepare_widget_render(widget, attrs, only_initial)
        return widget.render(name, self.value(), attrs=attrs)

    def __iter__(self):
        """
        Check if current widget has a renderer and iterate renderer.
        """
        widget, name, attrs = self.prepare_widget_render()
        if not hasattr(widget, 'get_renderer'):
            raise Exception, "Can not iterate over widget '%s'" % widget.__class__.__name__
        renderer = widget.get_renderer(name, self.value(), attrs=attrs)
        for entry in renderer:
            yield entry

    def __getitem__(self,idx):
        """
        Tries to use current widget's renderer, and then check attribute.
        """
        widget, name, attrs = self.prepare_widget_render()
        try:
            renderer = widget.get_renderer(name, self.value(), attrs=attrs)
            return renderer[idx]
        except Exception:
            return getattr(self,idx)

    forms.forms.BoundField.prepare_widget_render = prepare_widget_render
    forms.forms.BoundField.as_widget = as_widget
    forms.forms.BoundField.__iter__ = __iter__
    forms.forms.BoundField.__getitem__ = __getitem__

Это позволило мне быть в состоянии получить доступ к радио входов непосредственно, с помощью {{ form.field.0.tag }}, или через итерации - {% for radio in form.field %} {{ radio.tag }} {% endfor %}. Гораздо проще позаботиться!


выбор должен быть в модели:

class RatherComplicatedModel(models.Model):
    BAR_CHOICES = (
        (0, "No Textbox"),
        (1, "One Textbox: "),
    )
    #some other stuff...
    bar = models.IntegerField(blank=True, null=True, choices=BAR_CHOICES)

потом так:

class RatherComplicatedForm(forms.ModelForm):
    #various and sundry code...
    bar = forms.ChoiceField(widget=forms.RadioSelect(), 
                 choices=RatherComplicatedModel.BAR_CHOICES)
    class Meta:
        model = RatherComplicatedModel

Я хотел бы сделать это путем создания подклассов RadioFieldRenderer и присоединение его к пользовательских виджетов:

# forms.py
from django import forms
from django.forms.widgets import RadioSelect, RadioFieldRenderer
from django.template.loader import render_to_string
from myapp.models import RatherComplicatedModel


class MyRadioFieldRenderer(RadioFieldRenderer):
    def render(self):
        return render_to_string(
            'my_radio_widget.html',
                    {'field': self})


class MyRadioSelect(RadioSelect):
    renderer = MyRadioFieldRenderer


class RatherComplicatedForm(forms.ModelForm):
    RADIO_CHOICES = (
        ('none', "No Textbox"),
        ('one', "One Textbox: "),
    )
    rad = forms.ChoiceField(widget=MyRadioSelect(),choices=RADIO_CHOICES)

    class Meta:
        model = RatherComplicatedModel

затем шаблон:

#my_radio_widget.html
<ul>
    {% for choice in field %}
        <li>
            <label for="id_{{ field.name }}_{{ forloop.counter0 }}">
                <input type="radio"
                       name="{{ field.name }}"
                       value="{{ choice.choice_value }}"
                       id="id_{{ field.name }}_{{ forloop.counter0 }}"
                       {% if field.value == choice.choice_value %}
                           checked='checked'
                       {% endif %}/>
                {{ choice.choice_label }}
            </label>
        </li>
    {% endfor %}
</ul>