Django:迭代自定义选择字段中的选项

Posted

技术标签:

【中文标题】Django:迭代自定义选择字段中的选项【英文标题】:Django: iterating over the options in a custom select field 【发布时间】:2010-12-30 19:56:44 【问题描述】:

我正在使用基于 this example 的自定义 MM/YY 字段和小部件。我想遍历小部件类中定义的各个月份和年份选项,以便将“selected='selected'”应用于与存储在数据库中的 MM/YY 值相对应的 MM/YY 值。这似乎是一种混乱的方式,所以如果您有更好的想法,请在此处发布。

class MonthYearWidget(forms.MultiWidget):
    def __init__(self, attrs=None):
        months = (
            ('01', 'Jan (01)'),
            ('02', 'Feb (02)'),
            ('03', 'Mar (03)'),
            ('04', 'Apr (04)'),
            ('05', 'May (05)'),
            ('06', 'Jun (06)'),
            ('07', 'Jul (07)'),
            ('08', 'Aug (08)'),
            ('09', 'Sep (09)'),
            ('10', 'Oct (10)'),
            ('11', 'Nov (11)'),
            ('12', 'Dec (12)'),
        )

        year = int(datetime.date.today().year)
        year_digits = range(year, year+10)
        years = [(year, year) for year in year_digits]

        widgets = (forms.Select(attrs=attrs, choices=months), forms.Select(attrs=attrs, choices=years))
        super(MonthYearWidget, self).__init__(widgets, attrs)

    def decompress(self, value):
        if value:
            return [value.month, value.year]
        return [None, None]

    def render(self, name, value, attrs=None):
        try:
            value = datetime.date(month=int(value[0]), year=int(value[1]), day=1)
        except:
            value = ''
        return super(MonthYearWidget, self).render(name, value, attrs)

class MonthYearField(forms.MultiValueField):
    def __init__(self, *args, **kwargs):
        forms.MultiValueField.__init__(self, *args, **kwargs)
        self.fields = (forms.CharField(), forms.CharField(),)
    def compress(self, data_list):
        if data_list:
            return datetime.date(year=int(data_list[1]), month=int(data_list[0]), day=1)
        return datetime.date.today()

然后这就是我在模板中遇到的问题。我无法弄清楚月份和年份的可迭代列表的名称是什么(如果有的话)。发现可迭代列表是问题所在;我已经计划使用 ifequal 语句来确定“selected='selected'”应该应用于哪个选项。到目前为止,我只尝试过几个月的迭代。

<form action="#" method="POST">
% csrf_token %
    <p> form.from_email.label_tag :   form.from_email </p>
    <p> form.working_month.label_tag :
        <select name="working_month_0" id="id_working_month_0">
        % for i in form.working_month.data_list %
            <option value=" i "> option.from_email </option>
        % endfor %
        </select>
    <p><input type="submit" value="Change Settings Now" /></p>
</form>

提前感谢大家提供的任何指导。

编辑:这是通用视图:

def option_edit(request,option_id):
    try:
        option = Option.objects.get(pk=option_id)
    except Option.DoesNotExist:
        raise Http404

    return create_update.update_object(
        request,
        form_class = OptionForm,
        template_name = 'options.html',
        template_object_name = 'option',
        object_id = option_id,
        post_save_redirect = '/some/address/' + option_id + '/edit/'
    )

...和表单类:

class OptionForm(ModelForm):
    class Meta:
        model = Option
    working_month = MonthYearField(widget=MonthYearWidget)

我认为该模型也很相关:

class Option(models.Model):
    from_email = models.EmailField()
    working_month = models.DateField()

除了自定义表单字段之外,我是否必须创建自定义模型字段,还是可以使用此设置?

【问题讨论】:

【参考方案1】:

django 表单的神奇之处在于您不需要做所有这些。通过按名称调用表单的选择字段,它将呈现它并根据在实例化时传递给表单的初始/实例数据选择正确的选项。

form.working_month

如果还是有问题,可以把表单类也发一下吗?

祝你好运!

编辑

在查看您发布的链接的第一条评论时,此问题已得到解决。评论者包含此代码

def __init__(self, *args, **kwargs):
  forms.MultiValueField.__init__(self, *args, **kwargs)
  self.fields = (forms.CharField(), forms.CharField(),)

【讨论】:

好吧,问题是 form.working_month 总是显示第一个选项,2009 年 1 月,即使数据库中的实际 MM/YY 数据是 2010 年 8 月。我已经发布了我正在使用的通用视图以及表单类。谢谢。 您是否使用实例填充表单?如果是这样,我认为问题出在您被覆盖的 render() 方法上——您需要它吗? 其他模型中的表单字段,以及此模型中的 form.from_email,正在使用正确的初始数据进行渲染。并且不会将 object_id 传递给通用视图用实例填充表单吗?我刚刚删除了覆盖的 render() 方法,但 form.working_month 仍然填充了第一个可用选项而不是正确的数据。 如果您遇到异常,我认为您应该(暂时)将渲染放回并打印到控制台(或其他调试方法)。 也许将月份中的选择更改为整数((1,'Jan (01)'),(2, 'Feb (02)'))【参考方案2】:

这里解决了您的问题的轻微变化

http://skyl.org/log/post/skyl/2010/01/subclass-django-forms-widgets-radiofieldrenderer-and-django-forms-widgets-radioselect-for-custom-rendering-of-individual-choices/

【讨论】:

以上是关于Django:迭代自定义选择字段中的选项的主要内容,如果未能解决你的问题,请参考以下文章

Django Admin,修改/自定义manytomany字段的选择框中的名称

Django 自定义表单字段错误地呈现值

Django - 自定义 ModelMultipleChoiceField 无法根据父模型对选择进行分类

Django allauth 自定义登录表单未呈现自定义用户模型中的所有字段

Django 酥脆的表单可以与自定义小部件一起使用吗?

自定义 Django 模型字段中的“对象没有属性”