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

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

问题描述

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



在我的表单类中,我有一个form.ChoiceField,其小部件是一个form.RadioSelect小部件,需要用内联文本输入(也是表单中的字段)显示其选择之一。未选择单选时,我正在使用自定义验证来忽略文本字段。渲染后,我希望它显示如下:

 < ul> 
< li>< label for = id_rad_0><输入类型= radio id = id_rad_0 value = none name = rad />没有文本框< / label>< / li>
< li>< label for = id_rad_1>< input type = radio id = id_rad_1 value = one name = rad />一个文本框:< input type = text name = bar id = id_bar />< / label>< / li>
< / ul>

但是,我不能简单地在模板中生成此内容,因为没有公开广播选择。如果不将表单紧密耦合到模板,或者将所有表示逻辑都放在表单类中,我将看不到做到这一点的方法。解决此问题的正确方法是什么?



编辑



我意识到上面的内容可能只是一个晦涩的问题,但是我不确定究竟可以提供什么其他信息来激励某人帮助我。我是比Web设计师更好的后端程序员,而且我一个人在做这个项目,所以也许这缺乏教育-我所说的仅仅是糟糕的设计吗?我应该以其他方式设计吗?我真的很愿意在这里提出任何建议,以帮助我超越这一点。



编辑2



每个请求都会缩短当前代码以节省理智,更改名称以保护无辜的人:

 #从myapp.models导入的form.py 
从Django导入的RatherComplicatedModel
导入的表单

类RatherComplicatedForm(forms.ModelForm):
#各种代码...
RADIO_CHOICES =(
('none',无文本框),
('one',一个文本框:),

#尽管我ve缩写为模型, rad未出现在模型中;
#它仅向未提供的清理函数提供输入
rad = form.ChoiceField(widget = forms.RadioSelect(),choices = RADIO_CHOICES)

class Meta:
模型= RatherComplicatedModel

-

 #models.py 
从django.db导入模型

类RatherComplicatedModel(models.Model):
#其他一些东西。 。
bar = models.IntegerField(blank = True,null = True)


解决方案

安东的答案行之有效,并且在那里曾经是一个不错的答案-但不幸的是,它变得难以维持。因此,从附加到 a diff 中获取提示= https://code.djangoproject.com/ticket/9230 rel = nofollow> django票#9230 ,我只是猴子修补了 django.forms.forms.BoundField

 从Django导入表单

def MonkeyPatchDjangoFormsBoundField():
def prepare_widget_render(self,widget = None,attrs = None,only_initial = False):

准备小部件呈现所需的数据。

如果不是小部件:
小部件= self.field.widget

attrs = attrs或{}
auto_id = self.auto_id
如果auto_id和'id'不在attrs中和'id'不在widget.attrs中:
如果不是only_initial:
attrs ['id'] = auto_id
其他:
attrs ['id'] = self.html_initial_id

如果不是only_ini tial:
名称= self.html_name
其他:
name = self.html_initial_name

返回小部件,名称,属性

def as_widget (自身,widget = None,attrs = None,only_initial = False):

通过渲染传递的窗口小部件,添加任何作为attrs传递的HTML
属性,来渲染字段。如果未指定任何窗口小部件,则将使用
字段的默认窗口小部件。

小部件,名称,属性= self.prepare_widget_render(小部件,attrs,only_initial)
返回widget.render(名称,self.value(),attrs =属性)

def __iter __(self):

检查当前窗口小部件是否具有渲染器和迭代渲染器。

小部件,名称,属性= self.prepare_widget_render()
如果没有hasattr(widget,'get_renderer'):
引发异常,无法遍历小部件'%s'%widget .__ class __.__ name__
renderer = widget.get_renderer(name,self.value(),attrs = attrs)
用于在渲染器中输入:
yield entry

def __getitem __(self,idx):

尝试使用当前小部件的渲染器,然后检查属性。

小部件,名称,属性= self.prepare_widget_render()
尝试:
renderer = widget.get_renderer(name,self.value(),attrs = attrs)
return renderer [idx]
例外:
return getattr(self,idx)

form.forms.BoundField.prepare_widget_render = prepare_widget_render
表单。 form.BoundField.as_widget = as_widget
forms.forms.BoundField .__ iter __ = __iter__
forms.forms.BoundField .__ getitem __ = __getitem__

这使我能够使用 {{form.field.0.tag}} ,或通过迭代- {%for form.field%}中的radio {{radio.tag}} {%endfor%} 。要容易得多! / p>

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

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?

edit

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.

edit 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'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__

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天全站免登陆