Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
296 views
in Technique[技术] by (71.8m points)

python - Django subclassing multiwidget - reconstructing date on post using custom multiwidget

So my django book is back at university and I'm struggling to work this one out.

I've subclassed django.forms.widgets.MultiWidget like so:

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)

Which gives me a nifty looking date selection field like so: Nifty looking date selection thing

My queston is very simple really. When I submit said form to its handling method (which uses a process like this:

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

This fails, because Django doesn't know how to take my multi-widget and convert it back to the underlying field type, which is set in models.py to DateField(), clearly.

Now, the comments around the MultiWidget in the django source give me this useful hint:

You'll probably want to use this class with MultiValueField.

But the thing is - I probably don't. I want to keep my DateField() because it is very useful and there is no point duplicating it. What I need to do then is somehow convert these multiple fields back into a single valid datestring (yyyy-mm-dd) for insertion into the database.

My question is then:

How? What is the best way to achieve this?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Answered my own question!

I implemented this method:

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 pulls the data of all the sub-widgets from the entire post datadict. What I've done is to extract out the various date counterparts, and use the date constructor to validate the date. If it is valid, we print the string out in the correct format, otherwise, we return an empty string which

forminstance.is_valid()

will catch.

I love it when I do this!


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...