Django Rest Framework: adding DateTimeField format serializer validation

Til Web Development

Here’s an example of adding date and time validation to a DateTimeField in a serializer in the Django Rest Framework (DRF).

A first pass, using only the default formats of DateTimeField(), would look like the following:

class CustomSearchFieldsSerializer(serializers.Serializer):
   start_time = serializers.DateTimeField()
   end_time = serializers.DateTimeField()
 
   def validate(self, data):</code>
       # extra validation to ensure that the end date is always after the start date
       if data['start_time'] > data['end_time']:
           raise serializers.ValidationError("finish must occur after start")
       return data

Sending a request to that endpoint with the following query parameters (note it only has a date, not time):

/api/v1/custom-search/?start_time=2022-11-01&end_time=2022-11-07

Returns the following 400 Bad Request:

{
   "start_time": [
       "Datetime has wrong format. Use one of these formats instead: YYYY-MM-DDThh:mm[:ss[.uuuuuu]][+HH:MM|-HH:MM|Z]."
   ],
   "end_time": [
       "Datetime has wrong format. Use one of these formats instead: YYYY-MM-DDThh:mm[:ss[.uuuuuu]][+HH:MM|-HH:MM|Z]."
   ]
}

Not exactly what we want… I want this to be flexible and accept date only as a valid option.

Doing some research on the Django Rest Framework (DRF) documentation, I learned that I could customize the accepted formats. The next iteration looks like this:

class CustomSearchFieldsSerializer(serializers.Serializer):
   start_time = serializers.DateTimeField(required=False,
                                          input_formats=["%Y-%m-%dT%H:%M:%SZ", "%Y-%m-%dT%H:%M:%S", "%Y-%m-%d"])
   end_time = serializers.DateTimeField(required=False,
                                        input_formats=["%Y-%m-%dT%H:%M:%SZ", "%Y-%m-%dT%H:%M:%S", "%Y-%m-%d"])

The valid input formats can be passed as strings in a list. We add a few options, including a date-only format (the last option in the list).

Note: setting the flag “required” to False: this will make this field optional (in this case, the request could have no start and/or end time, which will then require the setting of some default values in the business logic to limit the query).

For the purposes of the task I was working on, I settled on the following formats:

input_formats=["%Y-%m-%d", "iso-8601"]

The first one accepts date only and the second follows the iso-8601 format, which is also the default format when nothing is set - the exact behaviour that we saw in the very first iteration. iso-8601 is an international standard for the representation of date and time formats.


If you found this helpful, please share this article.

The post Django Rest Framework: adding DateTimeField format serializer validation was originally published at flaviabastos.ca