I am making a flask restful API, what I'm having trouble with is marshmallow-sqlalchemy, and webargs.
In short here is my sqlalchemy model:
class User(Model):
id = Column(String, primary_key=True)
name = Column(String(64), nullable=False)
email = Column(String(120), nullable=False)
password = Column(String(128))
creation_date = Column(DateTime, default=datetime.utcnow)
and this is my schema:
class UserSchema(ModelSchema):
class Meta:
model = User
strict = True
sqla_session = db.session
user_schema = UserSchema()
and an example of my routes using flask-classful and webargs:
class UserView(FlaskView):
trailing_slash = False
model = User
schema = user_schema
@use_kwargs(schema.fields)
def post(self, **kwargs):
try:
entity = self.model()
for d in kwargs:
if kwargs[d] is not missing:
entity.__setattr__(d, kwargs[d])
db.session.add(entity)
db.session.commit()
o = self.schema.dump(entity).data
return jsonify({'{}'.format(self.model.__table__.name): o})
except IntegrityError:
return jsonify({'message': '{} exist in the database. choose another id'
.format(self.model.__table__.name)}), 409
@use_kwargs(schema.fields)
def put(self, id, **kwargs):
entity = self.model.query.filter_by(id=id).first_or_404()
for d in kwargs:
if kwargs[d] is not missing:
entity.__setattr__(d, kwargs[d])
db.session.commit()
o = self.schema.dump(entity).data
return jsonify({'{}'.format(self.model.__table__.name): o})
UserView.register(app)
The problem:
As you can see in my sqlalchemy model, some fields are not nullable, thus my marshmallow schemda marks them as required. My get, index, delete and post methods all work perfectly. But I included post for one reason:
when I try to post a new user with no name for example, a 422 http code is raised because name field is required, which is something I want and it is done perfectly.
BUT when editing fields with put request, I wish EVERYTHING in my schema becomes optional.. right now if I wanted to update a user, I must provide not only the id.. but ALL other information required by default even if I didn't change them at all.
In short, how to mark all fields as "optional" when the method is "put"?
EDIT: just like the solution provided by @Mekicha, I made the following changes:
Change the schema to make the required fields in my model accept the value None. like this:
class UserSchema(ModelSchema):
class Meta:
model = User
...
name = fields.Str(missing=None, required=True)
email = fields.Email(missing=None, required=True)
...
change my put and post method condition from this:
if kwargs[d] is not missing:
to this:
if kwargs[d] is not missing and kwargs[d] is not None:
Since you want to make the fields optional during
put, how about setting themissingattribute for the fields. From the doc:I think a combination of
missingandallow_none(which defaults toTruewhenmissing=None) as pointed out here: https://github.com/marshmallow-code/marshmallow/blob/dev/src/marshmallow/fields.py#L89 should work for you