Marshmallow: question: add `allow_none=True` in Meta

Created on 31 May 2016  路  2Comments  路  Source: marshmallow-code/marshmallow

Hi,
I'm trying to use Meta instead of re-declaring fields from a marshmallow-sqlalchemy project. I'd like to declare some fields optional. I don't see a way to do that in Meta, so I was trying to add it to initialization a la:

class UserSchema(ma.Schema):
    class Meta:
        # fields from SQL model. Keeping it DRY with Meta
        fields = ('username', 'first_name')

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.fields['first_name'].allow_none = True

# inspecting user_schema.fields['first_name'].allow_none is True after this line
user_schema = UserSchema(strict=True)
...< a different file>

from user.models import user_schema

# if I check user_schema.fields['first_name'].allow_none, it's still True here 
# in this new file outside the class UserAPI

class UserAPI(Resource):
    @login_required
    def post(self):
           # For some reason user_schema.fields['first_name'].allow_none = False here. No idea why!
            user, errors=user_schema.load(json_data)

When I inspect user_schema, it seems that this sets allow_none=True as expected.

But when I use it as part of flask-restless, for some reason I cannot explain the value is reset to False in my API extension above. I don't touch the object values anywhere, yet it mysteriously changes values! No idea what I'm missing.

  • Is there a better way to set allow_none than the above (I'd like to be DRY wrt to the model definition)
  • Any idea why the value would be reset to false? What am I missing?
question

Most helpful comment

We are holding off on adding dump_only as a class Meta options for the reasons given here and here.

It's not clear that these class Meta options (required, dump_only...) belong in marshmallow core, since they are only relevant for libraries that auto-generate fields. This has been pointed out here. So for now we won't add required as a class Meta option and leave it up to consuming libraries to add it.

You can add allow_none as a class Meta option like so:

from marshmallow import Schema, SchemaOpts, fields

class BaseSchemaOpts(SchemaOpts):

    def __init__(self, meta):
        super().__init__(meta)
        self.allow_none = getattr(meta, 'allow_none', ())

class BaseSchema(Schema):

    OPTIONS_CLASS = BaseSchemaOpts

    def on_bind_field(self, field_name, field_obj):
        super().on_bind_field(field_name, field_obj)
        if field_name in self.opts.allow_none:
            field_obj.allow_none = True

class MySchema(BaseSchema):
    foo = fields.Field(required=True)
    bar = fields.Field(required=True)

    class Meta:
        allow_none = ('foo', )


schema = MySchema(strict=True)
assert schema.fields['foo'].allow_none is True
assert schema.fields['bar'].allow_none is False

All 2 comments

Hi! I have a similar problem, I'd like to allow_none globally, but it's not possible without some hacking.
It would be really cool, if Meta class had this param and Fields/Schema respected it. I didn't find a fast&easy way how to implement it though. Would you consider implementing it, please?

We are holding off on adding dump_only as a class Meta options for the reasons given here and here.

It's not clear that these class Meta options (required, dump_only...) belong in marshmallow core, since they are only relevant for libraries that auto-generate fields. This has been pointed out here. So for now we won't add required as a class Meta option and leave it up to consuming libraries to add it.

You can add allow_none as a class Meta option like so:

from marshmallow import Schema, SchemaOpts, fields

class BaseSchemaOpts(SchemaOpts):

    def __init__(self, meta):
        super().__init__(meta)
        self.allow_none = getattr(meta, 'allow_none', ())

class BaseSchema(Schema):

    OPTIONS_CLASS = BaseSchemaOpts

    def on_bind_field(self, field_name, field_obj):
        super().on_bind_field(field_name, field_obj)
        if field_name in self.opts.allow_none:
            field_obj.allow_none = True

class MySchema(BaseSchema):
    foo = fields.Field(required=True)
    bar = fields.Field(required=True)

    class Meta:
        allow_none = ('foo', )


schema = MySchema(strict=True)
assert schema.fields['foo'].allow_none is True
assert schema.fields['bar'].allow_none is False

Was this page helpful?
0 / 5 - 0 ratings

Related issues

j4k0bk picture j4k0bk  路  3Comments

jayennis22 picture jayennis22  路  4Comments

imhoffd picture imhoffd  路  3Comments

k0nsta picture k0nsta  路  4Comments

DenisKuplyakov picture DenisKuplyakov  路  4Comments