PUT/POST fails in case of blank input to optional fields in nested serializer

414 views
Skip to first unread message

Tanuka Dutta

unread,
Jul 27, 2015, 4:55:55 AM7/27/15
to Django REST framework
Hello,

I'm using Django ver 1.7 and DRF ver 3.1.3.

I'm facing two issues in case of nested serializers (have tried both explicit and ModelSerializers). 

1. If the parent serializer class has optional fields and I enter blank inputs for those fields through the browsable API when writing to the API endpoint of the child class, I get an error saying that those fields cannot be blank. There is no error if I write to the API endpoint for the parent class with the same fields as blank.

2. Input data does not seem to be passed down two levels of nesting. Even though I provide User related fields (username, password), I get an error saying this field is required.

Details below. Person model contains a OneToOne relationship with User, and Admin has a OneToOne relationship with Person. However, I would like to provide the end-user with a single screen to update all these details in one shot (similar to combining multiple ModelForms in one template). So I've created nested serializers.


class Person(models.Model):
    name = models.CharField(max_length=200)     
    GENDER_CHOICES = (
        ('M', 'Male'),
        ('F', 'Female'),
        ('T', 'Transgender'),
    )
    gender = models.CharField(max_length=1, choices=GENDER_CHOICES)
    address = models.CharField(max_length=1000)
    work_phone = models.CharField(max_length=15, blank=True, null=True,
                        validators=[RegexValidator(regex='^[0-9]+$', 
                        message='Phone number must contain only digits', 
                        code='nomatch')])
    home_phone = models.CharField(max_length=15, blank=True, null=True,
                        validators=[RegexValidator(regex='^[0-9]+$', 
                        message='Phone number must contain only digits', 
                        code='nomatch')])
    mobile = models.CharField(max_length=15, blank=True, null=True,
                        validators=[RegexValidator(regex='^[0-9]+$', 
                        message='Phone number must contain only digits', 
                        code='nomatch')])
    email = models.EmailField(blank=True)
    date_of_birth = models.DateField()
    user = OneToOneField(User, null=True, blank=True)   
    DOCUMENT_CHOICES = (
        ('DL', 'Driving License'),
        ('RC', 'Ration card'),
        ('PP', 'Passport'),
        ('NO',  'None'),                 
    )
   additional_document = models.CharField(max_length=2, choices=DOCUMENT_CHOICES)
   document_number = models.CharField(max_length=10, blank=True, null=True)
   document_scan = models.FileField(max_length=1000, blank=True, null=True)
   photo = models.ImageField(blank=True,null=True)

class Admin(models.Model):
    person = OneToOneField(Person)
    # More fields will be added later

class UserSerializer(serializers.Serializer):
    id = serializers.IntegerField(label='ID', read_only=True)
    username = serializers.CharField(max_length=30)
    password = serializers.CharField(max_length=128, style={'input_type': 'password'})

class PersonSerializer(serializers.Serializer):
    id = serializers.IntegerField(label="ID", read_only=True)
    user = UserSerializer()
    name = serializers.CharField(max_length=200)
    gender = serializers.ChoiceField(choices=['M', 'F', 'T'])
    address = serializers.CharField(max_length=1000)
    work_phone = serializers.CharField(max_length=15, required=False, allow_null=True)
    home_phone = serializers.CharField(max_length=15, required=False, allow_null=True)
    mobile = serializers.CharField(max_length=15, required=False, allow_null=True)
    email = serializers.EmailField(required=False, allow_blank=True)
    date_of_birth = serializers.DateField()
    additional_document = serializers.ChoiceField(choices=['NO','DL', 'RC', 'PP'])
    document_number = serializers.CharField(max_length=10, required=False, allow_null=True)
    document_scan = serializers.FileField(max_length=1000, required=False, allow_null=True)
    photo = serializers.ImageField(required=False, allow_null=True)


class AdminSerializer(serializers.Serializer):
    id = serializers.IntegerField(label="ID", read_only=True)
    person = PersonSerializer()
    # More fields will be added later

Each of the serializers has an explicit create() and update() method defined, which I've omitted for the sake of brevity. I can see that these are not getting invoked, so the error is probably encountered during validation itself.


When I perform a GET operation, the Person or Admin api endpoint returns all the nested objects correctly.

When I perform a PUT or POST operation on Person, it accepts blank inputs in the optional fields. However, if I keep the same fields as blank when performing a PUT or POST operation on the Admin object, it flags errors as follows:


HTTP 400 Bad Request
Content-Type: application/json
Vary: Accept
Allow: GET, PUT, PATCH, HEAD, OPTIONS

{
    "person": {
        "document_scan": [
            "The submitted data was not a file. Check the encoding type on the form."
        ],
        "photo": [
            "The submitted data was not a file. Check the encoding type on the form."
        ],
        "document_number": [
            "This field may not be blank."
        ],
        "user": [
            "This field is required."
        ],
        "home_phone": [
            "This field may not be blank."
        ]
    }
}

The fields document_scan, document_number and home_phone were left blank, but they are optional fields and the AdminSerializer should accept this.

The user related fields HAD been entered but I still get the error "This field is required" as if they are missing.

What am I missing here? I face the same issue if I use ModelSerializers.


Regards,

Tanuka

Tanuka Dutta

unread,
Jul 29, 2015, 3:01:07 AM7/29/15
to Django REST framework, tanuka...@gmail.com
Any ideas what might be causing this? I'm unable to proceed using DRF for any write operation because of these issues.

Regards,
Tanuka
...
Reply all
Reply to author
Forward
0 new messages