Code source de src.utils_flask_sqla.schema

from marshmallow.fields import Nested
from marshmallow_sqlalchemy.fields import RelatedList, Related

# from flask_marshmallow.fields import RelatedList


[docs] class SmartRelationshipsMixin: """ This mixin automatically exclude from serialization: * Nested, RelatedList and Related fields * all fields with exclude=True in their metadata (e.g. ``fields.String(metadata={'exclude': True})``) Adding only Nested fields to ``only`` will not exclude others fields and serialize specified Nested fields. Adding exclude=True fields to ``only`` will serialize only specified fields (default marshmallow behaviour). You can use '+field_name' syntax on `only` to serialize default excluded fields (with metadata exclude = True) without other fields. Examples : .. code-block:: python class FooSchema(SmartRelationshipsMixin): id = fields.Int() name = field.Str() default_excluded_field = fields.Str(metadata={"exclude": True}) relationship = fields.Nested(OtherSchema) # or field.RelatedList() / field.Related() FooSchema().dump() -> {"id": 1, "name": "toto" } FooSchema(only=["+default_excluded_field"]).dump() -> {"id": 1, "name": "toto", default_excluded_field: "test" } FooSchema(only=["relationship"]).dump() -> {"id": 1, "name": "toto", relationship : {OtherSchema...} } FooSchema(only=["id", "relationship"]).dump() -> {"id": 1, relationship : {OtherSchema...} } """ def __init__(self, *args, **kwargs): included_fields = set() excluded_fields = set() nested_fields = set() for name, field in self._declared_fields.items(): # excluded fields at meta level are not even generated by auto-schema if field is None: continue if ( isinstance(field, Nested) or isinstance(field, RelatedList) or isinstance(field, Related) ): nested_fields.add(name) elif field.metadata.get("exclude", False): excluded_fields.add(name) elif ( hasattr(self.opts, "model") and hasattr(self.opts.model.__mapper__.column_attrs, name) and getattr(self.opts.model.__mapper__.column_attrs, name).deferred ): excluded_fields.add(name) else: included_fields.add(name) only = kwargs.pop("only", None) only = set(only) if only is not None else set() additional_fields = {field[1:] for field in only if field.startswith("+")} only = {field[1:] if field.startswith("+") else field for field in only} firstlevel_only = {field.split(".", 1)[0] for field in only} exclude = kwargs.pop("exclude", None) exclude = set(exclude) if exclude is not None else set() exclude |= (excluded_fields | nested_fields) - firstlevel_only # If only contains only nested & additional fields, we need to add included_fields to serialize nested, additional & included fields. # If only does not contains nested or additional fields, we do nothing and marshmallow will serialize only specified fields. if only and not firstlevel_only - nested_fields - additional_fields: only |= included_fields if only: kwargs["only"] = only if exclude: kwargs["exclude"] = exclude self.opts.exclude = set(self.opts.exclude) - set(firstlevel_only) super().__init__(*args, **kwargs)