flask- marshmallow serialization and deserialization

flask- marshmallow serialization and deserialization

Official document: marshmallow.readthedocs.io/en/latest/

marshmallow (cotton candy) is a lightweight data conversion module, also called serialization (converting P data model objects into storable or transferable data types) and deserialization (converting transferable data types into data Model object)

  • Serializing

    Serialization can convert data model objects into storable or transferable data types, for example: objects/object->list/dict, dict/list->string

  • Deserialization (deseriazing)

    The deserializer converts storable or transferable data types into data model objects, for example: list/dict->objects/object, string->dict/list

  • Data verification (validate)

    In the deserialization phase, type verification or custom verification is performed on the content of the data to be converted.

    Installation and basic configuration

Module installation

pip install -U marshmallow-sqlalchemy pip install -U flask-sqlalchemy -i https://pipy.douban.com/simple pip install -U flask-marshmallow Copy code

Module initialization (looks like ma is not used)

from flask import Flask from flask_sqlalchemy import SQLAlchemy from flask_marshmallow import Marshmallow from datetime import datetime app = False (__name__) app.config[ "SQLALCHEMY_DATABASE_URI" ] = "mysql://root:123@127.0.0.1:3306/mofang?charset= utf8mb4" app.config[ "SQLALCHEMY_TRACK_MODIFICATIONS" ] = False db = SQLAlchemy() ma = Marshmallow db.init_app(app) ma.init_app(app) class User ( db.Model ): __tablename__ = "tb_user" id = db.Column(db.Integer,primary_key= True ,comment= "primary key id" ) username = db.Column(db.String( 255 ), index= True , comment= "Username" ) password = db.Column(db.String( 255 ), comment= "Login password" ) mobile = db.Column(db.String( 15 ), index= True , comment= "mobile phone number" ) sex = db.Column(db.Boolean, default= True , comment= "Gender" ) email = db.Column(db.String( 255 ), index = True , comment = "Email" ) created_time = db.Column(db.DateTime, default=datetime.now, comment= "Created time" ) updated_time = db.Column(db.DateTime, default=datetime.now, onupdate=datetime.now, comment= "Update time" ) def __repr__ ( self ): return "<%s: %s>" %(self.__class__.name, self.username) @app.route( "/" ) def index (): return "" if __name__ = "__main__" : with app.app_context(): db.drop_all() db.create_all() app.run (Debug = True , Port = 6000 ) copying the code

Basic Constructor (BaseSchema)

Marshmallow converts the data format mainly through the constructor. During the use of marshmallow, all constructors must inherit the Schema base class indirectly or indirectly.

Complete conversion based on schema serialization

from datetime import datetime from flask import Flask from flask_sqlalchemy import SQLAlchemy from flask_marshmallow import Marshmallow app = Flask(__name__) app.config[ "SQLALCHEMY_DATABASE_URI" ]= "mysql://root:123@127.0.0.1:3306/mofangapp?charset=utf8mb4" app.config[ "SQLALCHEMY_TRACK_MODIFICATIONS" ] = False db = SQLAlchemy() db.init_app(app) ma = Marshmallow() ma.init_app(app) class User ( db.Model ): __tablename__ = "tb_user" id = db.Column(db.Integer, primary_key = True , comment = "primary key ID" ) username = db.Column(db.String( 255 ), index= True , comment= "Username" ) password = db.Column(db.String( 255 ), comment= "Login password" ) mobile = db.Column(db.String( 15 ), index= True , comment= "mobile phone number" ) sex = db.Column(db.Boolean, default= True , comment= "gender" ) email = db.Column(db.String( 255 ), index = True , comment = "Email" ) created_time = db.Column(db.DateTime, default=datetime.now, comment= "Created time" ) updated_time = db.Column(db.DateTime, default=datetime.now, onupdate=datetime.now, comment= "Update time" ) def __repr__ ( self ): return "<%s: %s>" % (self.__class__.__name__, self.username) # marshmallow The conversion data format is mainly done through the architecture conversion class. # During the use of marshmallow, all schema conversion classes must directly or indirectly inherit from the Schema base class UserSchema ( Schema ): username = fields.String() mobile = fields.String() # sex = fields.Boolean() email = fields.Email() created_time = fields.DateTime() @app.route( "/" ) def index (): user = User( username= "xiaoming" , mobile= "13312345677" , sex = True , email= "133123456@qq.com" , created_time=datetime.now(), updated_time=datetime.now() ) # Call marsh to convert the model into the basic python data format [dictionary/list] us = UserSchema() # To serialize multiple data, you can use many=True ret1 = us.dump(user) # Format the output into a dictionary ret2 = us .dumps(user) # Format the output into a json string print ( ">>>> us.dump(user) --> dictionary" ) print (ret1) print ( ">>>> us.dumps(user)- -> json string" ) print (ret2) """Run result: >>>> us.dump(user) --> Dictionary {'created_time': '2021-03-02T11:07:45.520209','updated_time': '2021-03-02T11:07:45.520221','username':'xiaoming','email': '133123456@qq. com','sex': True,'mobile': '13312345677'} >>>> us.dumps(user) --> json string {"created_time": "2021-03-02T11:07:45.520209", "updated_time": "2021-03-02T11:07:45.520221", "username": "xiaoming", "email": "133123456@qq. com", "sex": true, "mobile": "13312345677"} """ print ( type (ret1), type (ret2)) user1 = User( username= "xiaoming1 " , mobile= "13312345677" , sex = True , email= "133123456@qq.com" , created_time=datetime.now(), updated_time=datetime.now() ) user2 = User( username= "xiaoming2 " , mobile= "13312345677" , sex = True , email= "133123456@qq.com" , created_time=datetime.now(), updated_time=datetime.now() ) user_list = [user,user1,user2] us = UserSchema() data_list = us.dump(user_list,many= True ) print (data_list) """Run result: [{'mobile': '13312345677','created_time': '2021-03-02T11:12:50.128294','email': '133123456@qq.com','username':'xiaoming'}, {'mobile ': '13312345677','created_time': '2021-03-02T11:12:50.129576','email': '133123456@qq.com','username':'xiaoming1 '), {'mobile': ' 13312345677','created_time': '2021-03-02T11:12:50.129642','email': '133123456@qq.com','username':'xiaoming2 '}] """ return "Basic usage: model serialization" if __name__ == ' __main__ ' : with app.app_context(): db.create_all() app.run(debug = True , Host = "0.0.0.0" , Port = 5999 ) copying the code

schema reuse attribute data type

Types ofdescription
fields.
Dict
(keys, type]] = None, values, )
Dictionary type, often used to receive json type data
fields.
List
(cls_or_instance, type], **kwargs)
List type, often used to receive array data
fields.
Tuple
(tuple_fields, *args, **kwargs)
Tuple type
fields.
String
(*, default, missing, data_key, )
String type
fields.
UUID
(*, default, missing, data_key, )
UUID format type string
fields.
Number
(*, as_string, **kwargs)
Numerical basic types
fields.
Integer
(*, strict, **kwargs)
Integer
fields.
Decimal
(places, rounding, *, allow_nan, )
Numerical
fields.
Boolean
(*, truthy, falsy, **kwargs)
Boolean
fields.
Float
(*, allow_nan, as_string, **kwargs)
Floating point type
fields.
DateTime
(format, **kwargs)
Date and time type
fields.
Time
(format, **kwargs)
Time type
fields.
Date
(format, **kwargs)
Date type
fields.
Url
(*, relative, schemes, Set[str]]] = None, )
URL string type
fields.
Email
(*args, **kwargs)
Mailbox string type
fields.
IP
(*args[, exploded])
IP address string type
fields.
IPv4
(*args[, exploded])
IPv4 address string type
fields.
IPv6
(*args[, exploded])
IPv6 address string type
fields.
Method
(serialize, deserialize, **kwargs)
Field based on the return value of the Schema class method
fields.
Function
(serialize, Any], Callable[[Any, )
Return value field based on function
fields.
Nested
(nested, type, str, Callable[[], )
Foreign key type

Commonly used attributes of Schema data types

Attribute namedescription
defaultSet the default value of the field in the serialization phase
missingSet the default value of the field in the deserialization phase
validateThe built-in data validator or built-in validation set called during the deserialization phase
requiredSet the required fields of the current field
allow_noneWhether it is allowed to be empty None, ""
load_onlyWhether the current field is used in the deserialization phase, which is equivalent to the previous write_only
dump_onlyWhether the current field is used in the serialization stage, which is equivalent to the previous read_only
error_messagesDictionary type, can be used to replace the default field exception prompt, format:
error_messages={"required": "User name is required."}

Nested use of constructor

from flask import Flask from flask_sqlalchemy import SQLAlchemy from flask_marshmallow import Marshmallow from marshmallow import Schema,fields from datetime import datetime app = Flask(__name__) app.config[ "SQLALCHEMY_DATABASE_URI" ]= "mysql://root:123@127.0.0.1:3306/mofang?charset=utf8mb4" app.config[ "SQLALCHEMY_TRACK_MODIFICATIONS" ] = False db = SQLAlchemy() ma = Marshmallow() db.init_app(app) ma.init_app(app) class Author ( object ): def __init__ ( self, name, email ): self.name = name self.email = email self.created_time = datetime.now() self.books = [] # One-to-many foreign key self.courses = [] # Many-to-many foreign key class Book ( object ): def __init__ ( self, title, author ): self.title = title self.author = author # Used to replace foreign key relationships in MySQL class Course ( object ): """Writing Course""" def __init__ ( self,name ): self.name = name self.students = [] class Book2Schema ( Schema ): title = fields.String() class AuthorSchema ( Schema ): name = fields.String() email = fields.String() # Two-way nesting, for example, find all books belonging to the author. Note: When the amount of data is large, the data return will be very slow. # books = fields.List(fields.Nested(lambda: BookSchema(exclude=["author"]))) books = fields. List (fields.Nested( lambda : Book2Schema())) class BookSchema ( Schema ): title = fields.String() # Use the lambda anonymous function, so that the AuthorSchema object will only be found when using the author, otherwise it may be called sequentially, resulting in the situation that the object cannot be found. # Used to serialize the foreign key object, and the foreign key object can be in the specified format Serialization, and the format specified by the foreign key can complete any supported marshmallow operation author = fields.Nested( lambda : AuthorSchema()) class CourseSchema ( Schema ): name = fields.Str() # equivalent to fields.String() students = fields. List (fields.Nested( lambda : Author3Schema(exclude=[ "courses" ]))) class Author3Schema ( Schema ): name = fields.String() email = fields.String() # Method 1: General nesting # courses = fields.List(fields.Nested(lambda: CourseSchema(exclude=["students"]))) # Method 2: Use its own constructor as a foreign key method, and specify serialization fields # = fields.Nested courses (CourseSchema, only = ( "name",), MANY = True) # three ways: can also be the basis of the two on the way, do not specify a field # courses = fields.Nested (CourseSchema (many =True)) # Method 4: Use the Pluck field to replace the nested data with a single value, and return the list data, with only name as a member, where name is the field in the foreign key model, or it can be another field name. name is just an example courses = fields.Pluck(CourseSchema, "name" , many= True ) @app.route( "/index1" ) def index1 (): """Many-to-1 nested serialization""" author = Author( name= "Xiao Ming" , email= "xiaomnig@qq.com" , ) book = Book( title = "The Adventures of Xiao Ming" , author = author, ) bs = BookSchema() book_dict1 = bs.dump(book) book_dict2 = bs.dumps(book) print (book_dict1) print (book_dict2) return "Basic usage: nested serialization" @app.route( "/index2" ) def index2 (): """1-to-many nested serialization""" author = Author( name= "Xiao Ming" , email= "xiaomnig@qq.com" ) author.books = [ Book( title= "The Adventures of Xiao Ming Part 1" , author=author, ), Book( title= "The Adventures of Xiao Ming Part 2" , author=author, ), Book( title= "The Adventures of Xiao Ming Part 3" , author=author, ), Book( title= "The Adventures of Xiao Ming Part 4" , author=author, ), ] aus = AuthorSchema() ret1 = aus.dump(author) ret2 = aus.dumps(author) print (ret1) print (ret2) return "Basic usage: nested serialization" @app.route( "/index3" ) def index3 (): """Many-to-many nested serialization""" author1 = Author( name= "xiaoming" , email= "xiaomnig@qq.com" ) course1 = Course(name= "Prose Novel" ) author1.courses = [ course1, Course(name= "Romantic Novel" ), Course(name= "wuxia novel" ), ] course1.students = [ author1, Author( name= "xiaoli" , email= "xiaoli@qq.com" ) ] aus = Author3Schema() ret1 = aus.dump(author1) print (ret1) cs = CourseSchema() ret2 = cs.dump(course1) print (ret2) return "Basic usage: nested serialization" if __name__ == ' __main__ ' : app.run (Debug = True , Port = 7000 , Host = "0.0.0.0" ) Copy the code

Self-association

The existence of primary and foreign keys in a data table is self-association.

from flask import Flask from flask_sqlalchemy import SQLAlchemy from flask_marshmallow import Marshmallow from marshmallow import Schema,fields from datetime import datetime app = Flask(__name__) app.config[ "SQLALCHEMY_DATABASE_URI" ]= "mysql://root:123@127.0.0.1:3306/mofang?charset=utf8mb4" app.config[ "SQLALCHEMY_TRACK_MODIFICATIONS" ] = False db = SQLAlchemy() ma = Marshmallow() db.init_app(app) ma.init_app(app) class Area ( object ): def __init__ ( self, id , name ): self. id = id self.name = name self.sub = [] class AreaSchema ( Schema ): id = fields.Integer() name = fields.String() # Method 1: General Nesting # sub = fields.List(fields.Nested(lambda: AreaSchema(exclude=["sub"]))) # Method 2: Use its own constructor as a foreign key method, and specify serialization The fields # sub = fields.Nested("self", only=("id","name",), many=True) # Method three: on the basis of method two, no fields can be specified # sub = fields .Nested(lambda: AreaSchema(many=True)) # Method 4: Use Pluck field to replace nested data with a single value, return list data, only name as a member, here name is the field in the foreign key model, It can also be another field name, name is just an example sub = fields.Pluck( "self" , "name" , many= True ,) @app.route( "/" ) def index (): """self-nested serialization""" area1 = Area( id = 1 , name= "Guangdong Province" ) area2 = Area( id = 2 , name = "Guangzhou City" ) area3 = Area( id = 3 , name= "Baiyun District" ) area4 = Area( id = 4 , name= "Liwan District" ) area5 = Area( id = 5 , name= "Hebei Province" ) area6 = Area( id = 6 , name = "Shijiazhuang City" ) area7 = Area( id = 7 , name = "Qiaodong District" ) area8 = Area( id = 8 , name = "Qiaoxi District" ) area1.sub = [area2] area2.sub = [area3,area4] area5.sub = [area6] area6.sub = [area7,area8] ars = AreaSchema() ret1 = ars.dump(area1) ret2 = ars.dump(area2) print (ret1) print (ret2) return "Basic usage: self-nested serialization" if __name__ == ' __main__ ' : app.run (Debug = True , Port = 7000 , Host = "0.0.0.0" ) Copy the code

Schema-based deserialization conversion

from flask import Flask from flask_sqlalchemy import SQLAlchemy from flask_marshmallow import Marshmallow from marshmallow import Schema,fields,validate from datetime import datetime app = Flask(__name__) app.config[ "SQLALCHEMY_DATABASE_URI" ]= "mysql://root:123@127.0.0.1:3306/mofang?charset=utf8mb4" app.config[ "SQLALCHEMY_TRACK_MODIFICATIONS" ] = False db = SQLAlchemy() ma = Marshmallow() db.init_app(app) ma.init_app(app) class UserSchema ( Schema ): name = fields.Str(validate=validate.Length( min = 1 )) email = fields.Email() permission = fields.Str(validate=validate.OneOf([ "read" , "write" , "admin" ])) age = fields.Int(validate=validate.Range( min = 18 , max = 40 )) @app.route( "/" ) def index (): us = UserSchema() user_data = { "email" : "ronnie@stones.com" , "permission" : "admin" } ret1 = us.load(user_data) print (ret1) return "Basic usage: model sequence decolonization" if __name__ == ' __main__ ' : app.run (Debug = True , Port = 7000 , Host = "0.0.0.0" ) Copy the code
from flask import Flask from flask_sqlalchemy import SQLAlchemy from flask_marshmallow import Marshmallow from marshmallow import Schema,fields,validate from datetime import datetime app = Flask(__name__) app.config[ "SQLALCHEMY_DATABASE_URI" ]= "mysql://root:123@127.0.0.1:3306/mofang?charset=utf8mb4" app.config[ "SQLALCHEMY_TRACK_MODIFICATIONS" ] = False db = SQLAlchemy() ma = Marshmallow() db.init_app(app) ma.init_app(app) class UserSchema ( Schema ): name = fields.Str(required = True , validate=validate.Length( min = 1 )) email = fields.Email() permission = fields.Str(validate=validate.OneOf([ "read" , "write" , "admin" ])) age = fields.Int(validate=validate.Range( min = 18 , max = 40 )) @app.route( "/" ) def index (): us = UserSchema() user_data = { "email" : "ronnie@stones.com" , "permission" : "admin" } ret1 = us.load(user_data,partial=( "name" ,)) print (ret1) return "Basic usage: model sequence decolonization" if __name__ == ' __main__ ' : app.run (Debug = True , Port = 7000 , Host = "0.0.0.0" ) Copy the code

The setting field is only enabled during the serialization or deserialization phase

class UserSchema ( Schema ): name = fields.Str() IS password # password = fields.Str (LOAD_ONLY = True ) # write-only field is equivalent to "the Write-only" CREATED_TIME = fields.DateTime (dump_only = True ) # read-only field is equivalent to "read-only" copy the code

Code:

from flask import Flask from flask_sqlalchemy import SQLAlchemy from flask_marshmallow import Marshmallow from marshmallow import Schema,fields,validate from datetime import datetime app = Flask(__name__) app.config[ "SQLALCHEMY_DATABASE_URI" ]= "mysql://root:123@127.0.0.1:3306/mofang?charset=utf8mb4" app.config[ "SQLALCHEMY_TRACK_MODIFICATIONS" ] = False db = SQLAlchemy() ma = Marshmallow() db.init_app(app) ma.init_app(app) class User ( object ): def __init__ ( self,name,email,age,password,permission ): self.name=name self.email=email self.age=age self.password=password self.permission=permission self.created_time = datetime.now() class UserSchema ( Schema ): name = fields.Str(required = True , validate=validate.Length( min = 1 )) email = fields.Email() age = fields.Int(validate=validate.Range( min = 18 , max = 40 )) password = fields.Str(required = True , load_only = True ) permission = fields.Str(validate=validate.OneOf([ "read" , "write" , "admin" ])) created_time = fields.DateTime(dump_only = True ) @app.route( "/" ) def index (): us = UserSchema() user_data = { "email" : "ronnie@stones.com" , "permission" : "admin" , "password" : "123456" } ret1 = us.load(user_data,partial=( "name" ,)) print (ret1) user = User( name= "xiaoming" , age = 18 , **user_data, ) ret2 = us.dump(user) print (ret2) return "Basic usage: model sequence decolonization" if __name__ == ' __main__ ' : app.run (Debug = True , Port = 7000 , Host = "0.0.0.0" ) Copy the code

Hook method in the deserialization phase

Marshmallow provides a total of 4 hook methods:

pre_dump ([fn, pass_many]) to be registered in the prior serialized object method call, it will be called before the serialized object. pre_load([fn, pass_many]) Register the method to be called before deserializing the object , it will be called before verifying the data.

post_dump ([fn, pass_many, pass_original ]) to be registered in the serialized object method call, it will be called after the object serialization. post_load([fn, pass_many, pass_original]) The method to be called after registering the deserialized object , it will be called after verifying the data.

from flask import Flask from flask_sqlalchemy import SQLAlchemy from flask_marshmallow import Marshmallow from werkzeug.security import generate_password_hash from marshmallow import Schema,fields,validate,pre_load,pre_dump,post_dump,post_load from datetime import datetime app = Flask(__name__) app.config[ "SQLALCHEMY_DATABASE_URI" ]= "mysql://root:123@127.0.0.1:3306/mofang?charset=utf8mb4" app.config[ "SQLALCHEMY_TRACK_MODIFICATIONS" ] = False db = SQLAlchemy() ma = Marshmallow() db.init_app(app) ma.init_app(app) class User ( db.Model ): __tablename__ = "tb_user" id = db.Column(db.Integer, primary_key = True , comment = "primary key ID" ) name = db.Column(db.String( 255 ), index= True , comment= "Username" ) age = db.Column(db.Integer, comment= "age" ) password = db.Column(db.String( 255 ), comment= "Login password" ) mobile = db.Column(db.String( 20 ), comment= "mobile phone number" ) created_time = db.Column(db.DateTime, default=datetime.now, comment= "Created time" ) def __repr__ ( self ): return "<%s: %s>" % (self.__class__.__name__, self.name) class UserSchema ( Schema ): name = fields.String(validate=validate.Length( min = 1 )) age = fields.Integer(required = True ) password = fields.Str(load_only= True ) # Equivalent to write-only field "write-only" # created_time = fields.DateTime(dump_only=True) # Equivalent to read-only field "read-only" mobile = fields.String() created_time = fields.DateTime( format = '%Y-%m-%d %H:%M:%S' ) @pre_load def pre_load ( self,data,**kwargs ): """The pre-hook for deserialization will execute """ before data verification # print(f"kwargs={kwargs}") data[ "created_time " ] = datetime.now().strftime( '%Y-%m-%d %H:%M:%S' ) # Must return data return data @post_load def post_load ( self,data,**kwargs ): """Deserialization post-hook, will execute """ after data verification # print(f"kwargs={kwargs}") # When entering the database Previously, password encryption data[ "password" ] = generate_password_hash(data[ "password" ]) # Before entering the database, delete unnecessary fields, such as verification code, confirm password return User(**data) # You can also manually convert the dictionary into a model object here# Note that there is no database submitted here, so here is just an instantiation of a model object, and the database operation has not been completed. # If you want to reverse Synchronize to the database after serialization, the code is as follows: # instance = User(**data) # db.session.add(instance) # db.session.commit() # return instance @pre_dump def pre_dump ( self,data,**kwargs ): """Serialized pre-hook, will be executed before data conversion""" data.mobile = "130____0001" return data @post_dump def post_dump ( self,data,**kwargs ): """The serialized post hook will execute after data conversion. """ data[ "age" ] = f" {data[ 'age' ]} Years" return data @app.route( "/" ) def index (): us = UserSchema() instance = us.load({ "name" : "xiaomingf" , "age" : 19 , "password" : "123456" , "mobile" : "13000000001" }) data = us.dump(instance) print (data) return "Basic usage: call hook method" if __name__ == ' __main__ ' : app.run (Debug = True , Port = 7000 , Host = "0.0.0.0" ) Copy the code

Validate the data during the deserialization phase

Data verification based on the built-in validator

Built-in validatordescription
validate.
Email
(*, error)
E-mail verification
validate.
Equal
(comparable, *, error)
Determine whether the values are equal
validate.
Length
(min, max, *, equal, error)
Value length/size verification
validate.
OneOf
(choices, labels, *, error)
Option verification
validate.
Range
([min, max])
Range verification
validate.
Regexp
(regex, bytes, Pattern][, flags])
Regular verification
validate.
URL
(*, relative, schemes, Set[str]]] = None, )
Verify that it is a URL

The built-in validator is mainly written in the field options, the code:

from datetime import datetime from flask import Flask from flask_marshmallow import Marshmallow from marshmallow import Schema,fields,validate,post_dump,post_load,pre_dump,pre_load from flask_sqlalchemy import SQLAlchemy from werkzeug.security import generate_password_hash app = Flask(__name__) app.config[ "SQLALCHEMY_DATABASE_URI" ]= "mysql://root:123@127.0.0.1:3306/mofangapp?charset=utf8mb4" app.config[ "SQLALCHEMY_TRACK_MODIFICATIONS" ] = False db = SQLAlchemy() db.init_app(app) ma = Marshmallow() ma.init_app(app) class User ( db.Model ): __tablename__ = "tb_user" id = db.Column(db.Integer, primary_key = True , comment = "primary key ID" ) name = db.Column(db.String( 255 ), index= True , comment= "Username" ) email = db.String(db.String( 255 )) age = db.Column(db.Integer, comment= "age" ) password = db.Column(db.String( 255 ), comment= "Login password" ) mobile = db.Column(db.String( 20 ), comment= "mobile phone number" ) def __repr__ ( self ): return "<%s: %s>" % (self.__class__.__name__, self.name) class UserSchema ( Schema ): name = fields.String(validate=validate.Length( min = 1 )) age = fields.Integer(required = True ,validate=validate.Range( min = 16 , max = 100 )) email = fields.String(validate=validate.Email()) password = fields.Str(load_only= True ,validate=validate.Length( min = 6 , max = 16 )) # Equivalent to write-only field "write-only" mobile = fields.String(validate=validate.Regexp( "^ 1[3-9]\d{9}$" ,error= "The format of the mobile phone number is incorrect!" )) @app.route( "/" ) def index (): user_data = { "email" : "xiaoming@qq.com" , "name" : " " , "age" : 20 , "password" : "123456" , "mobile" : "13312345678" } # Error us = UserSchema() # Deserialization instance = us.load(user_data) print (instance) return "hello" if __name__ == ' __main__ ' : app.run (Debug = True , Host = "0.0.0.0" , Port = 5999 ) copying the code

Custom verification method

Parameter passing through context or constructor instance object

import random from datetime import datetime from flask import Flask from flask_marshmallow import Marshmallow from marshmallow import Schema,fields,validate,validates,validates_schema,ValidationError,post_load,pre_load from flask_sqlalchemy import SQLAlchemy app = Flask(__name__) app.config[ "SQLALCHEMY_DATABASE_URI" ]= "mysql://root:123@127.0.0.1:3306/mofangapp?charset=utf8mb4" app.config[ "SQLALCHEMY_TRACK_MODIFICATIONS" ] = False db = SQLAlchemy() db.init_app(app) ma = Marshmallow() ma.init_app(app) class User ( db.Model ): __tablename__ = "tb_user" id = db.Column(db.Integer, primary_key = True , comment = "primary key ID" ) name = db.Column(db.String( 255 ), index= True , comment= "Username" ) email = db.String(db.String( 255 )) age = db.Column(db.Integer, comment= "age" ) password = db.Column(db.String( 255 ), comment= "Login password" ) mobile = db.Column(db.String( 20 ), comment= "mobile phone number" ) def __repr__ ( self ): return "<%s: %s>" % (self.__class__.__name__, self.name) class UserSchema ( Schema ): name = fields.String() age = fields.Integer() email = fields.String() password = fields.Str() # Password password2 = fields.String() # Confirm password mobile = fields.String(validate=validate.Regexp( "^1[3-9]\d{9}$" ,error= " The format of the phone number is incorrect!" )) # Validate the value of a single specified field @validates( "mobile" ) def validate_mobile ( self,mobile ): if (mobile == "13312345678" ): raise ValidationError( "The phone number has been registered!!!" ) return mobile # Validation for multiple fields @validates_schema def validate ( self,data,**kwargs ): if (data[ "password" ] != data[ "password2" ]): # Note: After validation fails, it must be raised Something went wrong! ! ! It cannot be return!!!! raise ValidationError(field_name= "password2" ,message= "Password and confirmation password are inconsistent!" ) return data @post_load def post_load ( self,data,**kwargs ): """Hook method after deserialization verification""" print ( "num=%s" % self.num) print (self.context) del data[ "password2" ] # delete unnecessary fields return User(**data) @app.route( "/" ) def index (): user_data = { "email" : "xiaoming@qq.com" , "name" : " " , "age" : 20 , "password" : "123456" , "mobile" : "13312345671" , "password2" : "123456" } num = random.randint( 1 , 100 ) # If there is some data that needs to be passed to the constructor for calling during development in the future, you can pass parameters through context when instantiating the constructor, and call it through self.context inside the constructor us = UserSchema(context={ "num" :num}) # If there is some data that needs to be passed to the constructor for invocation during development in the future, it can be passed as an attribute of the constructor object us.num = num # Deserialization instance = us.load(user_data) print (instance) return "hello" if __name__ == ' __main__ ' : app.run (Debug = True , Host = "0.0.0.0" , Port = 5999 ) copying the code

Model Constructor (ModelSchema)

Official document: github.com/marshmallow...

marshmallow-sqlalchemy.readthedocs.io/en/latest/

Note: flask_marshmallow has removed the two model builder classes ModelSchema and TableSchema after version 0.12.0. The official recommends the use of SQLAlchemyAutoSchema and SQLAlchemySchema. The two classes are similar in usage.

Create model builder based on SQLAlchemySchema

from flask import Flask from flask_sqlalchemy import SQLAlchemy from flask_marshmallow import Marshmallow app = Flask(__name__) app.config[ "SQLALCHEMY_DATABASE_URI" ]= "mysql://root:123@127.0.0.1:3306/mofang?charset=utf8mb4" app.config[ "SQLALCHEMY_TRACK_MODIFICATIONS" ] = False db = SQLAlchemy() ma = Marshmallow() db.init_app(app) ma.init_app(app) class User ( db.Model ): __tablename__ = "tb_user" id = db.Column(db.Integer, primary_key = True , comment = "primary key ID" ) name = db.Column(db.String( 255 ), nullable= False , index= True , comment= "Username" ) email = db.Column(db.String( 255 )) age = db.Column(db.Integer, comment= "age" ) password = db.Column(db.String( 255 ), comment= "Login password" ) mobile = db.Column(db.String( 20 ), comment= "mobile phone number" ) def __repr__ ( self ): return "<%s: %s>" % (self.__class__.__name__, self.name) from marshmallow_sqlalchemy import SQLAlchemySchema,auto_field from marshmallow import post_load,fields,validate class UserSchema ( SQLAlchemySchema ): """Model Constructor""" # The primary key will be automatically set to the default self-reading [dump_only] id = auto_field() # auto_field General It can be called an inherited field, it will automatically inherit the field declarations and constraints of the same name in the corresponding model name = auto_field() email = auto_field() age = auto_field() password = auto_field(validate=validate.Length( min = 6 , max = 16 )) # # In the process of using auto_field, in addition to copying the information and data type of the corresponding field of the model, we can also add supplementary instructions mobile = auto_field( required= True ,validate=validate.Regexp( "^1[3-9]\d{9}$" )) password2 = fields.String() # If there is no declared field in the model, fill it in by yourself according to the previous custom constructor class Meta : model = User # Model class name table = models.Album.__table__ load_instance = True # In the deserialization stage, True will directly return the model object, False will return the dictionary include_relationships = True # When outputting the model object, the foreign key will be at the same time. Whether it is also processed together include_fk = True # Whether the serialization phase also returns the primary key, that is, whether to return the ID @post_load def post_load ( self,instance,**kwargs ): """Hooks executed after deserialization""" db.session.add(instance) db.session.commit() return instance @app.route( "/" ) def index (): user_data = { "name" : " 1" , "mobile" : "13312345676" , "age" : 18 , "email" : "133@qq.com " , "password" : "123456" , "password2" : "123456" } us = UserSchema(session=db.session) instance = us.load(user_data) # Note: If we are currently calling the model constructor, we must pass in the session attribute, which is the session object print (instance) of the current database return "Basic usage: the validator used in the deserialization phase" if __name__ == ' __main__ ' : with app.app_context(): db.create_all() app.run (Debug = True , Port = 7000 , Host = "0.0.0.0" ) Copy the code

Create model builder based on SQLAlchemyAutoSchema

usage:

class constructor class name ( SQLAlchemyAutoSchema ): class Meta : model = model class name # table = models.Album.__table__ include_relationships = True # When exporting model objects, foreign keys are also processed at the same time include_fk = True # sequence sequence stage Whether to also return the primary key load_instance = True # In the deserialization phase, directly return the model object sqla_session = db.session # Database connection session object # fields= ["id","name"] # Start field list exclude = [ "the above mentioned id" , "name" ] # exclude a list of fields copy the code

Code:

from flask import Flask from flask_sqlalchemy import SQLAlchemy from flask_marshmallow import Marshmallow app = Flask(__name__) app.config[ "SQLALCHEMY_DATABASE_URI" ]= "mysql://root:123@127.0.0.1:3306/mofang?charset=utf8mb4" app.config[ "SQLALCHEMY_TRACK_MODIFICATIONS" ] = False db = SQLAlchemy() ma = Marshmallow() db.init_app(app) ma.init_app(app) class User ( db.Model ): __tablename__ = "tb_user" id = db.Column(db.Integer, primary_key = True , comment = "primary key ID" ) name = db.Column(db.String( 255 ), nullable=False , index= True , comment= "Username" ) email = db.Column(db.String( 255 )) age = db.Column(db.Integer, comment= "age" ) password = db.Column(db.String(255 ), comment= "Login password" ) mobile = db.Column(db.String( 20 ), comment="mobile phone number" ) def __repr__ ( self ): return "<%s: %s>" % (self.__class__.__name__, self.name) from marshmallow_sqlalchemy import SQLAlchemyAutoSchema,auto_field from marshmallow import post_load,fields,validate class UserSchema ( SQLAlchemyAutoSchema ): """Model Constructor""" password2 = fields.String() # If there are no declared fields in the model, follow the previous self The way to define the constructor is to fill in the class Meta : model = User # # Whitelist fields, the fields used in the serializer must be declared here # fields = ["id","name","password2", "email","age","mobile"] # Field list # Blacklist fields, fields that are not used in the serializer, are mutually exclusive with the whitelist. If this attribute is set, the remaining fields are all used exclude = [ "age" ] # The list of fields disabled by the constructor load_instance = True # In the deserialization phase, True will return the model object directly, and False will return the dictionary include_relationships = True # When outputting the model object at the same time, whether the foreign key is also processed include_fk = True # Whether the serialization phase also returns the primary key, That is, whether to return ID sqla_session = db.session # The session object of the current database connection @post_load def post_load ( self,instance,**kwargs ): """Hooks executed after deserialization""" db.session.add(instance) db.session.commit() return instance @app.route( "/" ) def index (): user_data = { "name" : " 1" , "mobile" : "13312345676" , "email" : "133@qq.com" , "password" : "123456" , "password2" : "123456"} us = UserSchema() instance = us.load(user_data) # Note: If we are currently calling the model constructor, we must pass in the session attribute, which is the session object print (instance. id ) of the current database return "Basic usage: the validator used in the deserialization phase" if __name__ == ' __main__ ' : with app.app_context(): db.create_all() app.run (Debug = True , Port = 7000 , Host = "0.0.0.0" ) Copy the code