Django 子类化多组件 - 使用自定义多组件在提交时重建日期

16 投票
1 回答
3722 浏览
提问于 2025-04-16 09:47

我在大学的django书籍放在那儿,现在我在努力解决这个问题。

我像这样创建了一个django.forms.widgets.MultiWidget的子类:

class DateSelectorWidget(widgets.MultiWidget):
    def __init__(self, attrs=None, dt=None, mode=0):  
        if dt is not None:
            self.datepos = dt
        else:
            self.datepos = date.today()    

        # bits of python to create days, months, years
        # example below, the rest snipped for neatness.

        years = [(year, year) for year in year_digits]

        _widgets = (
            widgets.Select(attrs=attrs, choices=days), 
            widgets.Select(attrs=attrs, choices=months),
            widgets.Select(attrs=attrs, choices=years),
            )
        super(DateSelectorWidget, self).__init__(_widgets, attrs)

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

    def format_output(self, rendered_widgets):
        return u''.join(rendered_widgets)

这样我就得到了一个看起来很不错的日期选择字段,如下所示:

看起来不错的日期选择器

我的问题其实很简单。当我把这个表单提交到处理方法时(这个处理方法大致是这样的:

forminstance = ModelNameForm(request.POST, instance=modelinstance)
    if forminstance.is_valid():
        forminstance.save()

这个过程失败了,因为Django不知道如何将我的多重小部件转换回基础字段类型,而这个类型在models.py中被设置为DateField(),这点很明显。

现在,Django源代码中关于MultiWidget的评论给了我一个有用的提示:

你可能想要将这个类与MultiValueField一起使用。

但问题是——我可能并不想。我想保留我的DateField(),因为它非常有用,没有必要重复它。那么我需要做的就是以某种方式将这些多个字段转换回一个有效的日期字符串(格式为yyyy-mm-dd),以便插入到数据库中。

我的问题是:

怎么做呢?实现这个的最佳方法是什么?

1 个回答

12

我自己解决了问题!

我实现了这个方法:

def value_from_datadict(self, data, files, name):
    datelist = [widget.value_from_datadict(data, files, name + '_%s' % i) \ 
                                      for i, widget in enumerate(self.widgets)]
    try:
        D = date(day=int(datelist[0]), month=int(datelist[1]), \
             year=int(datelist[2]))
        return str(D)
    except ValueError:
        return ""

value_from_datadict 这个函数可以从整个帖子的数据字典中提取出所有子组件的数据。我做的就是把不同的日期部分提取出来,然后用日期构造函数来验证这个日期。如果日期有效,我们就把它按照正确的格式打印出来;如果不有效,就返回一个空字符串,这样

forminstance.is_valid()

就能捕捉到错误。

我真喜欢这样做!

撰写回答