I have a MySQL table that has MANY relationships (about 50) and I would like to avoid:
I tried setting the nested items in the WebsiteSchema constructor, setting it in the include_items() method, but nothing works, the items property only exists if it has been defined completely in the class definition. I tried searching in the docs and Google but I cannot find how to do this, I have a hunch I should be using the OPTIONS_CLASS but I don't quite understand how it works.
Code showing what I tried:
from components.ma import ma
from schemas.item import ItemSchema
class WebsiteSchema(ma.SQLAlchemyAutoSchema):
# This line works obviously
# items = ma.Nested(ItemSchema, many=True)
items = None
# Not working
def __init__(self, **kwargs):
self.items = ma.Nested(ItemSchema, many=True)
super().__init__(**kwargs)
# Not working
def include_items(self):
self.items = ma.Nested(ItemSchema, many=True)
I'm afraid you have to do it at class creation, not instantiation.
Related: https://stackoverflow.com/q/42231334/4653485
Perhaps you could override __new__ if you want it more dynamic.
You could make use of Schema.from_dict to dynamically create new schemas at runtime. Something like:
class WebsiteSchema(ma.SQLAlchemyAutoSchema):
...common fields...
RELATIONSHIP_FIELDS = {
"items": ma.List(ma.Nested(ItemSchema()))
}
def make_schema(relationships: Sequence[str]):
return WebsiteSchema.from_dict({
name: RELATIONSHIP_FIELDS[name]
for name in relationships
})
# ------
schema = make_schema(["items"])()
schema.load({"items": [...]})
EDIT: fix accessing fields
I'm afraid you have to do it at class creation, not instantiation.
Related: https://stackoverflow.com/q/42231334/4653485
Perhaps you could override
__new__if you want it more dynamic.
Thanks for the ideas, __new__ isn't working either, type('WebsiteSchema', (WebsiteSchema,), dict(items=ma.Nested(ItemSchema, many=True))) returns "TypeError: dump() missing 1 required positional argument: 'obj'" and I have no idea why. type() would have been nice however :)
You could make use of
Schema.from_dictto dynamically create new schemas at runtime. Something like:class WebsiteSchema(ma.SQLAlchemyAutoSchema): ...common fields... RELATIONSHIP_FIELDS = { "items": fields.List(ItemSchema()) } def make_schema(relationships: Sequence[str]): return WebsiteSchema.from_dict({ name: RELATIONSHIP_FIELDS[name] for name in relationships }) # ------ schema = make_schema(["items"])() schema.load({"items": [...]})
Thanks friend, my Python skills are not advanced enough to know this was possible! What import are you using for fields however? Though it would be from marshmallow import fields, however with that import or any other I could think of, I have the ValueError: The list elements must be a subclass or instance of marshmallow.base.FieldABC. exception.
Oh, that was haste on my part. Since it looks like you're using flask-marshmallow, then you can access the fields from ma. I also fixed the List(Nested(...)) usage. I updated my code snippet.
Thanks a million! from_dict with the extra Python theory I didn't know about will be of tremendous help!