Search code examples
djangodjango-formsdatepickermodelformdjango-widget

How to make a date picker that does not select previous dates in Django


I want to make a date picker that does not select previous dates using Django.

class DateInput(forms.DateInput):
    input_type = 'date'

class TimeInput(forms.TimeInput):
    input_type = 'time'
"""class used for booking a time slot."""
class BookingForm(forms.ModelForm):
    class Meta:
        model = Booking
        fields = ['check_in_date', 'check_in_time', 'check_out_time',
                    'person', 'no_of_rooms']

        widgets = {
                    'check_in_date': DateInput(),
                    'check_in_time': TimeInput(),
                    'check_out_time': TimeInput(),
                }

    """Function to ensure that booking is done for future and check out is after check in"""
    def clean(self):
        cleaned_data = super().clean()
        normal_book_date = cleaned_data.get("check_in_date")
        normal_check_in = cleaned_data.get("check_in_time")
        normal_check_out_time = cleaned_data.get("check_out_time")
        str_check_in = str(normal_check_in)
        format = '%H:%M:%S'
        try:
            datetime.datetime.strptime(str_check_in, format).time()
        except Exception:
            raise ValidationError(
                _('Wrong time entered.'),
                code='Wrong time entered.',
            )


        # now is the date and time on which the user is booking.
        now = timezone.now()
        if (normal_book_date < now.date() or
            (normal_book_date == now.date() and
            normal_check_in < now.time())):
            raise ValidationError(
                "You can only book for future.", code='only book for future'
            )
        if normal_check_out_time <= normal_check_in:
            raise ValidationError(
                "Check out should be after check in.", code='check out after check in'
            )

The above code is written in forms.py file. As you can see, I made a date picker but the problem is that the user can select any date but I want him to select only current or future dates. Perhaps, it can be done using JavaScript or bootstrap but I want to know can we do it in Django?


Solution

  • You can specify a min attribute [mdn-doc] for the date input type:

    from django.utils.timezone import now
    
    
    class FutureDateInput(forms.DateInput):
        input_type = 'date'
    
        def get_context(self, name, value, attrs):
            attrs.setdefault('min', now().strftime('%Y-%m-%d'))
            return super().get_context(name, value, attrs)

    You will need to do validation in the form/model, since this will only limit this at the client side.