JasonGenX
JasonGenX

Reputation: 5434

Django Rest Framework, ModelSerializers and custom fields validation

Using latest version of Django and DRF.

I have a rather complex requirement I can't find a solution for. I'll try to simplify it.

Let's say I have a model that has two fields. field_a and field_b

I have a ModelSerializer for it. I POST a request with its fields. The fields get validated with the model and then against my two serializer functions validate_field_a and validate_field_b. All is well.

Now I'd like my POST request to include a third field that is not a member of that model. let's call it field_c. I have a custom def create(self, validated_data): in my serializer which saves everything to the database.

with regards to field_c I would like to:

  1. Custom Validate it. just like I do with the other two fields.
  2. Require that it is mandatory for the whole request to succeed and if it's not, issue a "Field is required" error just like if I forgot to POST one of my required model fields.
  3. Have the chance to take field_c and save it onto a totally different unrelated Model's row in the db.

I can't seem to get around that. If I add field_c to the fields meta - it throws an exception saying justifiably that field_c is not in my model. If I don't include it in fields, the validate_field_c which I really want to put there doesn't even get called.

What can I do?

Upvotes: 2

Views: 2577

Answers (2)

Rieljun Liguid
Rieljun Liguid

Reputation: 1521

You can add the custom field in your serializer as a write_only field and override the create method so that you can handle the custom field's value.

Something like this:

class MySerializer(serializers.ModelSerializer):
    field_c = serializers.CharField(write_only=True)

    class Meta:
        model = MyModel
        fields = ('field_a', 'field_b', 'field_c')

    def validate_field_c(self, value):
        if value is 'test':
            raise ValidationError('Invalid')
        return value

    def create(self, validated_data, **kwargs):
        field_c = validated_data.pop('field_c')

        return MyModel.objects.create(**validated_data)

Upvotes: 5

Thomas Jiang
Thomas Jiang

Reputation: 1323

Don't use ModelSerializer for this - use a serializer that recreates the same fields as your model & include field_c as you would.

I understand that you want your model to do some of the work in the validation process but the design of DRF is such that it isolates these responsibilities. You can read more about it here. Basically, the serializer should be the one doing all the validation heavy-lifting.

Of course, this means that you'll have to explicitly define the validation methods in the serializer.

In your custom create() method you can create the model instance or do whatever you want in it as required.

Upvotes: -1

Related Questions