Django Validate Date & Time in Forms

2019-07-19 11:23发布

I have a view where I validate date and time on form submit making sure the date + time are not past. Date and Time are two separate fields. It works, but I know its wrong way of doing it and the date+time should be validated in Django Forms.

This is in my view.py

(Probably not done the right way but it works)

my_date = request.session['reservationdate'] #in "mm/dd/yyyy" format
my_time = request.session['reservationtime'] #in "hh:mm" format
my_date_time = (my_date + ' ' + my_time + ':00') #convert to "mm/dd/yyyy hh:mm:ss"
my_date_time = datetime.strptime(my_date_time, '%m/%d/%Y %H:%M:%S') #convert to valid datetime
if datetime.now() <= my_date_time:
    #do this
else:
     ...

now my goal is to have something like the above in Django forms:

class MyForm(forms.ModelForm):  

def __init__(self, *args, **kwargs):
    super(MyForm, self).__init__(*args, **kwargs)

    self.fields['my_date'].required = True
    self.fields['my_time'].required = True
    ...

def clean_my_date(self):
    my_date = self.cleaned_data['my_date']
    my_time = self.cleaned_data['my_time']
    my_date_time = (my_date + ' ' + my_time + ':00')
    my_date_time = datetime.strptime(my_date_time, '%m/%d/%Y %H:%M:%S')
    if datetime.now() <= my_date_time:
        raise forms.ValidationError(u'Wrong Date!')
    return my_date

 class Meta:
    model = MyModel
    fields = ['my_date', 'my_time', ...]

Edit:

working code:

def clean_my_time(self):
   my_date = self.cleaned_data['my_date']
   my_time = self.cleaned_data['my_time']
   my_date_time = ('%s %s' % (my_date, my_time))
   my_date_time = datetime.strptime(my_date_time, '%Y-%m-%d %H:%M:%S')
   if datetime.now() >= my_date_time:
        raise forms.ValidationError(u'Wrong Date or Time! "%s"' % my_date_time)
   return my_time

Thanks to all for the help especially xyres for his work and for being patient with me!

2条回答
来,给爷笑一个
2楼-- · 2019-07-19 11:47

You are trying to validate over multiple fields. This point is well covered by the django documentation, see https://docs.djangoproject.com/en/1.7/ref/forms/validation/#cleaning-and-validating-fields-that-depend-on-each-other.

The job has to be done in the clean method. Assuming django 1.7, your code could look like

class MyForm(forms.ModelForm):  

    def __init__(self, *args, **kwargs):
        super(MyForm, self).__init__(*args, **kwargs)

        self.fields['my_date'].required = True
        self.fields['my_time'].required = True
        ...

    def clean(self):
        cleaned_data = super(MyForm, self).clean()
        # here all fields have been validated individually,
        # and so cleaned_data is fully populated
        my_date = cleaned_data.get('my_date')
        my_time = cleaned_data.get('my_time')
        if my_date and my_time:
            my_date_time = (my_date + ' ' + my_time + ':00')
            my_date_time = datetime.strptime(my_date_time, '%m/%d/%Y %H:%M:%S')
            if datetime.now() <= my_date_time:
                msg = u"Wrong Date time !"
                self.add_error('my_date', msg)
                self.add_error('my_time', msg)
        return cleaned_data

    class Meta:
        model = MyModel
        fields = ['my_date', 'my_time', ...]
查看更多
Ridiculous、
3楼-- · 2019-07-19 12:06

I'll try to answer one last time. Instead of doing def clean_my_date(...), do this:

def clean_my_time(self):
    # rest of your code remains same

If the above solution doesn't work, try this answer.

Update

Since the above code worked, I feel I should try and explain why and how.

Let's look at the order of fields in your form

fields = ['my_date', 'my_time', ...]

As, you can see my_time field comes after my_date field. So, when your code was like

def clean_my_date(self) 

the clean() method of your form gets called and it returns a dictionary object called cleaned_data. This cleaned_data dict has all the keys i.e. fields of your form upto my_date field. Any field that is after my_date won't be in cleaned_data. As, my_time field is after my_date field, it was not in cleaned_data. That is why you got a KeyError.

After changing your code to

def clean_my_time(self) 

the clean() method returned cleaned_data with all the fields upto my_time. As my_date comes before my_time, it is, therefore, present in cleaned_data. Hence, no error.

So it depends on the order of your form fields. If you want to validate two fields together, do it in the clean_my_field(self) method of the field that comes later in order. The answer posted by Jérôme Thiard is also a good alternative.

查看更多
登录 后发表回答