.. This file is a part of the AnyBlok / Marshmallow project .. .. Copyright (C) 2017 Jean-Sebastien SUZANNE .. .. This Source Code Form is subject to the terms of the Mozilla Public License, .. v. 2.0. If a copy of the MPL was not distributed with this file,You can .. obtain one at http://mozilla.org/MPL/2.0/. .. contents:: Memento ======= Declare your **AnyBlok model** ------------------------------ :: from anyblok.column import Integer, String from anyblok.relationship import Many2One, Many2Many from anyblok import Declarations @Declarations.register(Declarations.Model) class City: id = Integer(primary_key=True) name = String(nullable=False) zipcode = String(nullable=False) def __repr__(self): return ''.format(self=self) @Declarations.register(Declarations.Model) class Tag: id = Integer(primary_key=True) name = String(nullable=False) def __repr__(self): return ''.format(self=self) @Declarations.register(Declarations.Model) class Customer: id = Integer(primary_key=True) name = String(nullable=False) tags = Many2Many(model=Declarations.Model.Tag) def __repr__(self): return ''.format(self=self) @Declarations.register(Declarations.Model) class Address: id = Integer(primary_key=True) street = String(nullable=False) city = Many2One(model=Declarations.Model.City, nullable=False) customer = Many2One( model=Declarations.Model.Customer, nullable=False, one2many="addresses") .. warning:: The **AnyBlok model** must be declared in a blok Declare your schema ------------------- :: from anyblok_marshmallow import ModelSchema from marshmallow import fields class CitySchema(ModelSchema): class Meta: model = 'Model.City' class TagSchema(ModelSchema): class Meta: model = 'Model.Tag' class AddressSchema(ModelSchema): # follow the relationship Many2One and One2One city = fields.Nested(CitySchema) class Meta: model = 'Model.Address' class CustomerSchema(ModelSchema): # follow the relationship One2Many and Many2Many # - the many=True is required because it is *2Many # - exclude is used to forbid the recurse loop addresses = fields.Nested(AddressSchema, many=True, exclude=('customer', )) tags = fields.Nested(TagSchema, many=True) class Meta: model = 'Model.Customer' # optionally attach an AnyBlok registry # to use for serialization, desarialization and validation registry = registry # optionally return an AnyBlok model instance post_load_return_instance = True customer_schema = CustomerSchema() (De)serialize your data and validate it --------------------------------------- :: customer = registry.Customer.insert(name="JS Suzanne") tag1 = registry.Tag.insert(name="tag 1") customer.tags.append(tag1) tag2 = registry.Tag.insert(name="tag 2") customer.tags.append(tag2) rouen = registry.City.insert(name="Rouen", zipcode="76000") paris = registry.City.insert(name="Paris", zipcode="75000") registry.Address.insert(customer=customer, street="Somewhere", city=rouen) registry.Address.insert(customer=customer, street="Another place", city=paris) dump_data = customer_schema.dump(customer).data # { # 'id': 1, # 'name': 'JS Suzanne', # 'tags': [ # { # 'id': 1, # 'name': 'tag 1', # }, # { # 'id': 2, # 'name': 'tag 2', # }, # ], # 'addresses': [ # { # 'id': 1 # 'street': 'Somewhere' # 'city': { # 'id': 1, # 'name': 'Rouen', # 'zipcode': '76000', # }, # }, # { # 'id': 2 # 'street': 'Another place' # 'city': { # 'id': 2, # 'name': 'Paris', # 'zipcode': '75000', # }, # }, # ], # } customer_schema.load(dump_data).data # , ])> errors = customer_schema.validate(dump_data) # dict with all the validating errors .. note:: By default: the deserialization return a dict with deserialized data, here we get an instance of the model because the ``CustomerSchema`̀` add **post_load_return_instance = True** in their Meta Give the registry ----------------- The schema need to have the registry. If no registry found when the de(serialization) or validation then the **RegistryNotFound** exception will be raised. Add the **registry** by the Meta ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This is the solution given in the main exemple:: class CustomerSchema(ModelSchema): class Meta: model = 'Model.Customer' registry = registry Add the **registry** during init ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This solution is use during the instanciation :: customer_schema = CustomerSchema(registry=registry) Add the **registry** by the context ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This solution is use during the instanciation or after :: customer_schema = CustomerSchema(context={'registry': registry}) or :: customer_schema = CustomerSchema() customer_schema.context['registry'] = registry Add the **registry** when the de(serialization or validatoris called ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: customer_schema.dump(customer, registry=registry) customer_schema.load(dump_data, registry=registry) customer_schema.validate(dump_data, registry=registry) **post_load_return_instance** option ------------------------------------ As the registry this option can be passed by initialization of the schema, by the context or during the call of methods The value of this options can be: * False: **default**, the output is a dict * True: the output is an instance of the model. The primary keys must be in value * array of string: the output is an instance of the model, each str entry must be an existing column .. warning:: If the option is not False, and the instance can no be found, then the **instance** error will be added in the errors dict of the method .. warning:: The post load is only for load method!!! Overriding Generated Fields --------------------------- :: from anyblok_marshmallow import ModelSchema from marshmallow import fields class Customer(ModelSchema): date_created = field_for(Author, 'date_created', dump_only=True) class Meta: model = 'Model.Customer'