Skip to main content
  1. About
  2. For Teams
AI Assist is now on Stack Overflow. Start a chat to get instant answers from across the network. Sign up to save and share your chats.
Asked
Viewed 7k times
11

model.py

class Form(models.Model):
    no = models.IntegerField()
    finish_date = models.DateField(blank=True, null=True)

serializers.py

class FormSerializer(serializers.ModelSerializer):
    class Meta:
        model = Form
        fields = '__all__'

if I try:

http http://127.0.0.1:8000/api/forms no=112 "finish_date"=""

It returns the error:

"finish_date": [
    "Date has wrong format. Use one of these formats instead: YYYY[-MM[-DD]]."
]

If I set "finish_date" to null , this post works. And StringField(blank=True, null=True) will not get the error.

How to solve?

1
  • Could you post the serializer you are using ?
    rajkris
    –  rajkris
    2017-10-22 06:57:27 +00:00
    Commented Oct 22, 2017 at 6:57

5 Answers 5

19

The problem is that the DateTimeField doesn't currently support the allow_blank keyword argument.

It does however support allow_null, so you have two options:

  1. Clean Data Before Sending

Scrub "finish_date": "" -> "finish_date": null *before sending to your server

If you are using JavaScript to submit your form, you'll probably have do something like this:

if (data["finish_date"] == "") {
    data["finish_date"] = null;
}
  1. Clean Data After Receiving

Scrub "finish_date": "" -> "finish_date": None in your serializer.

You can easily do this using the .to_internal_value() method on the ModelSerializer

class FormSerializer(serializers.ModelSerializer):
    class Meta:
        model = Form
        fields = '__all__'

    def to_internal_value(self, data):
        # check for "finish_date": "" and convert to None
        # This must be done before .validate()
        if data['finish_date'] == '':
            data['finish_date'] = None
        return super(FormSerializer, self).to_internal_value(data)

the .to_internal_value() method is mentioned a lot in the Django Rest Framework Fields API Reference

Sign up to request clarification or add additional context in comments.

1 Comment

I created my ModelSerializer so that you don't have to specify the field name every time. ```python from rest_framework import serializers class ModelSerializer(serializers.ModelSerializer): def to_internal_value(self, data): for field_name, value in data.items(): if not field_name in self.fields: continue field_object = self.fields[field_name] if all([ value == "", field_object.allow_null, any([ isinstance(field_object, serializers.DateField)
5

Now in the above model, you have a DateField, and the DateField accepts certain formats similar to the ones shown in the error in your post.When you post with:

http http://127.0.0.1:8000/api/forms no=112 "finish_date"=""

You are actually passing an empty string("") to the serializer, which is not a valid format for the DateField. Instead try the Post without passing the "finish_date" arg, I think it will work then. Or maybe you could pass with some default date in the past instead of passing an empty string .

5 Comments

how can i handle the default blank string in serializer itself, before entering validate it got the error, where i can override the model level validation ???
Any idea why Django is not accepting empty string when null=True, blank=True ? Most of the other fields accept empty when null=True and blank=True.
@SandeepBalagopal, most of the fields(like char, text), accept empty since '' is actually a valid string. Now when we use the combination null=True, blank=True in models and supply no value, the db stores null for the field(except for char and text field, where '' is stored). Now empty string is not a valid date format. So when we do not specify key('finish_date') of the date_field when posting, the db stores it as null. For a little bit more clarification refer: stackoverflow.com/a/8609425/8482471
@ShihabudheenKM, the query you have posted is actually a frequent one. Now the best way to approach the current situation is to pass a default value or not mentioning the date_field key or passing value as null, in the post request, which I think have been mentioned above. Now for your question, maybe we can try something like mentioned here: stackoverflow.com/a/46910040/8482471. But if you ask me I think it will be better to leave this method alone and maybe since this is an exceptional case, maybe just do this in the view itself. That way it will look cleaner. Just my thought.
The best thing is to scrub the data so that '' becomes null since the serializers.DateField doesn't yet support allow_blank. This can be done either before submitting or by the serializer in the .to_internal_value() method.
1

Modify your serializer with this code

class FormSerializer(serializers.ModelSerializer):

finish_date = serializers.DateTimeField(allow_null=True)

class Meta:
    model = Form
    fields = '__all__'

Comments

0

As of ver. 3x DJango Rest Framework does not provide DateField which allows blank values, you either do not have to send the field in the payload or explicitly set null as the field value, but you cannot set "" blank values.

To solve this issue, I have implemented my own custom field which is built on top of DRF DateField, so you do not have to worry about compromising on your existing requirements! ;)

# sample.py

from rest_framework import serializers


class DateField(serializers.DateField):
    """
    Date field which allows blank values.

    As of djangorestframework 3x, DRF does not provide a date field which
    allows blank ("") values, so this field is built on top of DRF DateField
    which provides functionality to accept blank values.
    """

    allow_blank = None

    def __init__(self, *args, **kwargs):
        self.allow_blank = kwargs.pop("allow_blank", False)
        super().__init__(format, *args, **kwargs)

    def to_internal_value(self, data):
        # calc length if blank values are allowed,
        # this improves performance a bit 
        if self.allow_blank:
            if len(data) == 0:
                return data
        return super().to_internal_value(data)
    
    def to_representation(self, value):
        # DRF by default returns None if no value is set
        # so no custom implementation is required
        return super().to_representation(value)

Usage:

from sample import DateField

my_date_field = DateField(
    allow_blank=True,
)

Comments

-1

If anyone is having a problem with this issue and using a javascript client to post data, try sending undefined as a blank date

1 Comment

Doesn't work for me. It will not fail, but instead of removing the earlier date the old date stays in database.

Your Answer

Post as a guest

Required, but never shown

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.

Morty Proxy This is a proxified and sanitized view of the page, visit original site.