django 表单无线电输入布局 [英] django form radio input layout

查看:26
本文介绍了django 表单无线电输入布局的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

解决此问题的djangoy"方法是什么:

What is the "djangoy" way to approach this problem:

在我的表单类中,我有一个 forms.ChoiceField,它的小部件是一个 forms.RadioSelect 小部件,其中一个选择需要用内嵌文本输入(这也是表单中的一个字段)来呈现.当未选择单选选项时,我正在使用自定义验证来忽略文本字段.渲染时,我希望它如下所示:

In my form class, I have a forms.ChoiceField whose widget is a forms.RadioSelect widget, one of whose choices needs to be presented with an inline text input (which is also a field in the form). I'm using custom validation to ignore the text field when its radio choice is not selected. When rendered, I want it to appear like below:

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

但是,我不能简单地在我的模板中生成它,因为没有公开收音机选项.如果不将我的表单与我的模板紧密耦合,或者将所有的表示逻辑放在表单类中,我就看不出有什么方法可以做到这一点.解决这个问题的正确方法是什么?

However, I can't simply produce this in my template, because the radio choices are not exposed. I can't see a way to do this without tightly coupling my form to my template, or alternately, putting all of the presentation logic in the form class. What is the right way to solve this problem?

编辑

我意识到上述问题可能只是一个晦涩的问题,但我不确定我可以提供哪些其他信息来激励某人帮助我解决这个问题.我是一个比网页设计师更好的后端程序员,而且我一个人在做这个项目,所以也许是缺乏教育 - 我所描述的只是糟糕的设计吗?我应该以不同的方式设计它吗?我真的很乐意接受这里的任何建议,以帮助我克服这个问题.

I realize that the above might just be an obscure problem, but I'm not sure exactly what other information I can provide in order to inspire someone to help me with this. I'm a much better backend programmer than web designer, and I'm on this project alone, so maybe it's a lack of education - is what I described simply poor design? Should I just be designing this a different way? I'm really open to any suggestion here that will help me move past this.

编辑 2

根据请求,将当前代码缩短以保持理智,更改名称以保护无辜者:

Per request, the current code, shortened to save sanity, names changed to protect the innocent:

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

推荐答案

Anton 的答案奏效了,并且在一段时间内是一个不错的答案 - 但不幸的是它变得无法维护.因此,从 a diff 附加到 django ticket #9230,我只是修补了django.forms.forms.BoundField

Anton's answer worked, and was a decent answer for a while there - but unfortunately it became unmaintainable. So, taking a cue from a diff attached to django ticket #9230, I just monkey patched 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 %}.更容易打理!

This allowed me to be able to access the radio inputs directly, by using {{ form.field.0.tag }}, or through iteration - {% for radio in form.field %} {{ radio.tag }} {% endfor %}. Much easier to take care of!

这篇关于django 表单无线电输入布局的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆