форма входа радио Джанго макет
каков способ" 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>