简体   繁体   中英

Marshmallow Parent Schema - How to share a validation decorator between child schemas?

I have a parent marshmallow schema "ParentSchema" and 2 nested children schemas "ChildSchema1" and "ChildSchema2". Both nested children schemas are taking advantage of the @validates_schema decorator for field validation from marshmallow. They look like this:

ParenSchema.py

from marshmallow import Schema, fields
from schemas.childSchema1 import ChildSchema1
from schemas.childSchema2 import ChildSchema2

    class ParentSchema(Schema):
        child1 = fields.Nested(ChildSchema1)
        child2 = fields.Nested(ChildSchema2)
        foo = fields.String()
        bar = fields.String()

ChildSchema1.py

from marshmallow import Schema, pprint, post_load
from marshmallow import fields, ValidationError, validates, validates_schema

class ChildSchema1(Schema):
    field1 = fields.String()
    field2 = fields.String()
    common_field = fields.String()

    @validates("common_field")
    def validate_common_field(self, common_field):
        try:
            # Validation logic
        except:
            raise ValidationError('common_field is not valid')

ChildSchema2.py

from marshmallow import Schema, pprint, post_load
from marshmallow import fields, ValidationError, validates, validates_schema

class ChildSchema2(Schema):
    common_field = fields.String()
    field3 = fields.String()

    @validates("common_field")
    def validate_common_field(self, common_field):
        try:
            # Exact Same Validation logic as common_field from ChildSchema1
        except:
            raise ValidationError('common_field is not valid')

Given that both ChildSchema1 and ChildSchema2 have a field of the same name, with the same validator function, I'd love to follow DRY Principle and pull that function out to ParentSchema.py.

A solution I found is creating a separate class to host the shared validation functions:

def validate_common_field(self, common_field):
    try:
        # Exact Same Validation logic as common_field from ChildSchema1
    except:
        raise ValidationError('common_field is not valid')

And consume that from ChildSchema1 and ChildSchema2 by removing the @validates decorator and using the validate parameter in the schema field like this.

ChildSchema1.py

from marshmallow import Schema, pprint, post_load
from marshmallow import fields, ValidationError, validates, validates_schema
from validators import *

class ChildSchema1(Schema):
    field1 = fields.String()
    field2 = fields.String()
    common_field = fields.String(validate=validate_common_field)

validators.py from marshmallow import ValidationError, validates

def validate_common_field(self, common_field):
        try:
            # Validation logic
        except:
            raise ValidationError('common_field is not valid')

Your approach with a separate function is fine.

If the common field is shared by both children, you could also use inheritance to reflect that and factorize the field and the logic.

class ChildSchema(Schema):
    common_field = fields.String()

    @validates("common_field")
    def validate_common_field(self, common_field):
        try:
            # Validation logic
        except:
            raise ValidationError('common_field is not valid')

class ChildSchema1(ChildSchema):
    field1 = fields.String()
    field2 = fields.String()

class ChildSchema2(ChildSchema):
    field3 = fields.String()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM