Nat*_*ate 7 python django django-forms
什么是"djangoy"方法来解决这个问题:
在我的表单类中,我有一个forms.ChoiceField,它的widget是一个forms.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>
Run Code Online (Sandbox Code Playgroud)
但是,我不能简单地在我的模板中生成这个,因为无法公开无线电选择.如果没有将表单紧密地耦合到我的模板,或者将所有表示逻辑放在表单类中,我就看不到这样做的方法.解决这个问题的正确方法是什么?
编辑
我意识到上述可能只是一个模糊的问题,但我不确定我能提供什么其他信息以激励某人帮助我.我是一个比网页设计师更好的后端程序员,而且我一个人在这个项目,所以也许是缺乏教育 - 我所描述的只是糟糕的设计?我应该以不同的方式设计这个吗?我对这里的任何建议都很开放,这将有助于我超越这个.
编辑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
Run Code Online (Sandbox Code Playgroud)
-
# models.py
from django.db import models
class RatherComplicatedModel(models.Model):
#some other stuff...
bar = models.IntegerField(blank=True,null=True)
Run Code Online (Sandbox Code Playgroud)
如果我正确理解您的问题,您可以访问模板中的选择元组:
<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>
Run Code Online (Sandbox Code Playgroud)
安东的答案有效,并且在一段时间内是一个不错的答案 - 但不幸的是它变得无法维护。因此,从django 票证 #9230附带的diff中获取线索,我只是进行了猴子修补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__
Run Code Online (Sandbox Code Playgroud)
这使我能够通过使用{{ form.field.0.tag }}或通过迭代 -直接访问无线电输入{% for radio in form.field %} {{ radio.tag }} {% endfor %}。更容易照顾!
| 归档时间: |
|
| 查看次数: |
11101 次 |
| 最近记录: |