Marshmallow: Override field schema based on data

Created on 12 Apr 2019  路  2Comments  路  Source: marshmallow-code/marshmallow

I'm just getting started with marshmallow so if there's a more elegant way to solve the issue please let me know.
Fields will be varied based on the user type (student/staff)
```.json
{
"type": "student",
"name": "Student 1",
"class": "V Std",
"section": "A Class"
}

if type `Staff` we need to validate `designation` and `experience` skip `class` and `section`
```.json
{
   "type": "staff",   
   "name": "Staff 1",
   "designation": "Professor",
   "experience": "2 Year"
}

I have the following simple model and schema.
```.py
class AddUser(Resource):
def post(self):
content = request.get_json(silent=True)
try:
data = UserSchema().load(content)
print(data)

  except ValidationError as err:
     return err.messages, 400

class UserSchema(Schema):
type = fields.Str(required=True,validate=OneOf(['student', 'staff'], error='Invalid User Type'), error_messages={'required': 'User type required'})
name = fields.Str(required=True)
class = fields.Str()
section = fields.Str()
designation = fields.Str()
experience = fields.Str()

@post_load
# @pre_load
# @validates_schema
def unwrap_envelope(self, data):
student = {
class: fields.Str(required=True),
section: fields.Str(required=True)
}

  staff = {
   designation: fields.Str(required=True),
   experience: fields.Str(required=True)
 }


 # Fields are getting updated but it is **not raising the error**

 if data['type'] == 'student':
   self.declared_fields.update(student)
 elseif data['type'] == 'staff':
   self.declared_fields.update(staff)

 return data

```

polymorphism question

Most helpful comment

I think what you're looking for is polymorphism.

It's not straightforward to achieve and marshmallow does not come with an easy way to do it. You can check "marshmallow-oneofschema" and "marshmallow-polyfield". Those two third-party libraries are meant for that. They both have their pros and cons, so none of them was included in marshmallow core.

All 2 comments

Used Schema Level Validation but errors will be raised with separately. Is there any alternative way to this.

```.py
@validates_schema
def unwrap_envelope(self, data):
errors = {}
if data['type'] == 'student':
if not data.get('class') or not str(data.get('class')).strip():
errors['title'] = ['Class should not be empty']
if not data.get('section') or not str(data.get('section')).strip():
errors['section'] = ['Section should not be empty']

 elseif data['type'] == 'staff':
   if not data.get('designation') or not str(data.get('designation')).strip():
     errors['designation'] = ['Designation should not be empty']
   if not data.get('experience') or not str(data.get('experience')).strip():
     errors['experience'] = ['Experience should not be empty']

 if errors:
     raise ValidationError(errors)

 return data

```

Helpful, Could combine the errors raised by default field validation and returns from the validates schema

I think what you're looking for is polymorphism.

It's not straightforward to achieve and marshmallow does not come with an easy way to do it. You can check "marshmallow-oneofschema" and "marshmallow-polyfield". Those two third-party libraries are meant for that. They both have their pros and cons, so none of them was included in marshmallow core.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ambye85 picture ambye85  路  4Comments

tadams42 picture tadams42  路  3Comments

k0nsta picture k0nsta  路  4Comments

sloria picture sloria  路  3Comments

Ovyerus picture Ovyerus  路  3Comments