摘要:創(chuàng)建實(shí)例時(shí)如果傳遞了,表示需要接收輸入數(shù)據(jù)集合,裝飾器注冊(cè)預(yù)處理和后處理方法時(shí)需要傳遞參數(shù)。
預(yù)處理和后處理方法
數(shù)據(jù)的預(yù)處理和后處理方法通過(guò)pre_load, post_load, pre_dump和post_dump裝飾器注冊(cè):
from marshmallow import Schema, fields, pre_load class UserSchema(Schema): name = fields.Str() slug = fields.Str() @pre_load def slugify_name(self, in_data): in_data["slug"] = in_data["slug"].lower().strip().replace(" ", "-") return in_data schema = UserSchema() result, errors = schema.load({"name": "Steve", "slug": "Steve Loria "}) result["slug"] # => "steve-loria"預(yù)處理和后處理的many參數(shù)
預(yù)處理和后處理方法默認(rèn)一次接收一個(gè)對(duì)象/數(shù)據(jù),在運(yùn)行時(shí)處理傳遞給schema對(duì)象的many參數(shù)。
創(chuàng)建schema實(shí)例時(shí)如果傳遞了many=True,表示需要接收輸入數(shù)據(jù)集合,裝飾器注冊(cè)預(yù)處理和后處理方法時(shí)需要傳遞參數(shù)pass_many=True。預(yù)處理和后處理方法接收輸入數(shù)據(jù)(可能是單個(gè)數(shù)據(jù)或數(shù)據(jù)集合)和布爾類型的many參數(shù):
from marshmallow import Schema, fields, pre_load, post_load, post_dump class BaseSchema(Schema): # Custom options __envelope__ = { "single": None, "many": None } __model__ = User def get_envelope_key(self, many): """Helper to get the envelope key.""" key = self.__envelope__["many"] if many else self.__envelope__["single"] assert key is not None, "Envelope key undefined" return key @pre_load(pass_many=True) def unwrap_envelope(self, data, many): key = self.get_envelope_key(many) return data[key] @post_dump(pass_many=True) def wrap_with_envelope(self, data, many): key = self.get_envelope_key(many) return {key: data} @post_load def make_object(self, data): return self.__model__(**data) class UserSchema(BaseSchema): __envelope__ = { "single": "user", "many": "users", } __model__ = User name = fields.Str() email = fields.Email() user_schema = UserSchema() user = User("Mick", email="[email protected]") user_data = user_schema.dump(user).data # {"user": {"email": "[email protected]", "name": "Mick"}} users = [User("Keith", email="[email protected]"), User("Charlie", email="[email protected]")] users_data = user_schema.dump(users, many=True).data # {"users": [{"email": "[email protected]", "name": "Keith"}, # {"email": "[email protected]", "name": "Charlie"}]} user_objs = user_schema.load(users_data, many=True).data # [在預(yù)處理和后處理方法中拋出異常, ]
字段驗(yàn)證產(chǎn)生的錯(cuò)誤字典的_schema鍵包含了ValidationError異常的信息:
from marshmallow import Schema, fields, ValidationError, pre_load class BandSchema(Schema): name = fields.Str() @pre_load def unwrap_envelope(self, data): if "data" not in data: raise ValidationError("Input data must have a "data" key.") return data["data"] sch = BandSchema() sch.load({"name": "The Band"}).errors # {"_schema": ["Input data must have a "data" key."]}
如果不想存儲(chǔ)在_schema鍵中,可以指定新的鍵名傳遞給ValidationError的第二個(gè)參數(shù):
from marshmallow import Schema, fields, ValidationError, pre_load class BandSchema(Schema): name = fields.Str() @pre_load def unwrap_envelope(self, data): if "data" not in data: raise ValidationError("Input data must have a "data" key.", "_preprocessing") return data["data"] sch = BandSchema() sch.load({"name": "The Band"}).errors # {"_preprocessing": ["Input data must have a "data" key."]}預(yù)處理和后處理方法的調(diào)用順序
反序列化的處理流程:
@pre_load(pass_many=True) methods
@pre_load(pass_many=False) methods
load(in_data, many) (validation and deserialization)
@post_load(pass_many=True) methods
@post_load(pass_many=False) methods
序列化的處理流程(注意pass_many的區(qū)別):
@pre_dump(pass_many=False) methods
@pre_dump(pass_many=True) methods
dump(obj, many) (serialization)
@post_dump(pass_many=False) methods
@post_dump(pass_many=True) methods
不保證相同裝飾器和pass_many參數(shù)裝飾的方法的調(diào)用順序
錯(cuò)誤處理重寫(xiě)schema的handle_error方法來(lái)自定義錯(cuò)誤處理功能。handle_error接收一個(gè)ValidationError異常實(shí)例,一個(gè)原始對(duì)象(序列化)或輸入數(shù)據(jù)(反序列化):
import logging from marshmallow import Schema, fields class AppError(Exception): pass class UserSchema(Schema): email = fields.Email() def handle_error(self, exc, data): """Log and raise our custom exception when (de)serialization fails.""" logging.error(exc.messages) raise AppError("An error occurred with input: {0}".format(data)) schema = UserSchema() schema.load({"email": "invalid-email"}) # raises AppErrorSchema級(jí)別的驗(yàn)證
使用marshmallow.validates_schema裝飾器可以為Schema注冊(cè)一個(gè)schema級(jí)別的驗(yàn)證函數(shù),其異常信息保存在錯(cuò)誤字典的_schema鍵中:
from marshmallow import Schema, fields, validates_schema, ValidationError class NumberSchema(Schema): field_a = fields.Integer() field_b = fields.Integer() @validates_schema def validate_numbers(self, data): if data["field_b"] >= data["field_a"]: raise ValidationError("field_a must be greater than field_b") schema = NumberSchema() result, errors = schema.load({"field_a": 1, "field_b": 2}) errors["_schema"] # => ["field_a must be greater than field_b"]驗(yàn)證原始輸入數(shù)據(jù)
通常驗(yàn)證器會(huì)忽略未聲明的field的數(shù)據(jù)輸入。如果要訪問(wèn)原始輸入數(shù)據(jù)(例如如果發(fā)送了未知字段視為驗(yàn)證失敗),可以給validates_schema裝飾器傳遞一個(gè)pass_original=True參數(shù):
from marshmallow import Schema, fields, validates_schema, ValidationError class MySchema(Schema): foo = fields.Int() bar = fields.Int() @validates_schema(pass_original=True) def check_unknown_fields(self, data, original_data): unknown = set(original_data) - set(self.fields) if unknown: raise ValidationError("Unknown field", unknown) schema = MySchema() errors = schema.load({"foo": 1, "bar": 2, "baz": 3, "bu": 4}).errors # {"baz": "Unknown field", "bu": "Unknown field"}存儲(chǔ)特定field的錯(cuò)誤
如果要在指定field上保存schema級(jí)別的驗(yàn)證錯(cuò)誤,可以給ValidationError的第二個(gè)參數(shù)傳遞field名稱(列表):
class NumberSchema(Schema): field_a = fields.Integer() field_b = fields.Integer() @validates_schema def validate_numbers(self, data): if data["field_b"] >= data["field_a"]: raise ValidationError( "field_a must be greater than field_b", "field_a" ) schema = NumberSchema() result, errors = schema.load({"field_a": 1, "field_b": 2}) errors["field_a"] # => ["field_a must be greater than field_b"]重寫(xiě)屬性訪問(wèn)的方式
marshmallow默認(rèn)使用utils.get_value函數(shù)獲取各種類型的對(duì)象的屬性以進(jìn)行序列化。
通過(guò)重寫(xiě)get_attribute方法可以重寫(xiě)對(duì)象屬性的訪問(wèn)方式:
class UserDictSchema(Schema): name = fields.Str() email = fields.Email() # If we know we"re only serializing dictionaries, we can # use dict.get for all input objects def get_attribute(self, key, obj, default): return obj.get(key, default)自定義class Meta選項(xiàng)
class Meta是配置和修改Schema行為的一種方式。通過(guò)繼承自SchemaOpts可以添加自定義class Meta選項(xiàng)(Schema.Meta API docs查看原生選項(xiàng))。
下面的代碼通過(guò)自定義class Meta選項(xiàng)實(shí)現(xiàn)了預(yù)處理和后處理的many參數(shù)這一節(jié)中例子的功能。
首先通過(guò)繼承SchemaOpts類添加了兩個(gè)選項(xiàng),name和plural_name:
from marshmallow import Schema, SchemaOpts class NamespaceOpts(SchemaOpts): """Same as the default class Meta options, but adds "name" and "plural_name" options for enveloping. """ def __init__(self, meta): SchemaOpts.__init__(self, meta) self.name = getattr(meta, "name", None) self.plural_name = getattr(meta, "plural_name", self.name)
然后創(chuàng)建NamespacedSchema類并使用剛才創(chuàng)建的NamespaceOpts:
class NamespacedSchema(Schema): OPTIONS_CLASS = NamespaceOpts @pre_load(pass_many=True) def unwrap_envelope(self, data, many): key = self.opts.plural_name if many else self.opts.name return data[key] @post_dump(pass_many=True) def wrap_with_envelope(self, data, many): key = self.opts.plural_name if many else self.opts.name return {key: data}
現(xiàn)在我們處理序列化和反序列化的自定義schema再繼承自NamespacedSchema:
class UserSchema(NamespacedSchema): name = fields.String() email = fields.Email() class Meta: name = "user" plural_name = "users" ser = UserSchema() user = User("Keith", email="[email protected]") result = ser.dump(user) result.data # {"user": {"name": "Keith", "email": "[email protected]"}}使用上下文
Schema的context屬性存儲(chǔ)序列化及反序列化可能要用到的額外信息。
schema = UserSchema() # Make current HTTP request available to # custom fields, schema methods, schema validators, etc. schema.context["request"] = request schema.dump(user)
我的博客即將同步至騰訊云+社區(qū),邀請(qǐng)大家一同入駐:https://cloud.tencent.com/dev...
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/43864.html
摘要:方法對(duì)應(yīng)的是方法,它反序列化一個(gè)字典為數(shù)據(jù)結(jié)構(gòu)。某些例如和內(nèi)置了驗(yàn)證器驗(yàn)證集合時(shí),錯(cuò)誤字典將基于無(wú)效字段的索引作為鍵通過(guò)給的參數(shù)傳遞對(duì)象,可以執(zhí)行額外的驗(yàn)證驗(yàn)證函數(shù)可以返回布爾值或拋出異常。 快速上手 Declaring Schemas 首先創(chuàng)建一個(gè)基礎(chǔ)的user模型(只是為了演示,并不是真正的模型): import datetime as dt class User(object)...
摘要:嵌套可以嵌套使用以表示對(duì)象間的關(guān)系如外鍵關(guān)系。在下面的例子中,和對(duì)象是一對(duì)多的關(guān)系必須使用或參數(shù)避免無(wú)限遞歸也可以使用導(dǎo)入模塊的方式傳遞嵌套,如自嵌套給傳遞字符串參數(shù)表示和對(duì)象本身的關(guān)系 schema嵌套 schema可以嵌套使用以表示對(duì)象間的關(guān)系(如外鍵關(guān)系)。 例如下例中Blog有一個(gè)用User對(duì)象表示的author屬性: import datetime as dt class ...
摘要:有三種方式創(chuàng)建自定義的。下面的例子判斷某個(gè)對(duì)象是否是某個(gè)對(duì)象的作者,以及的屬性是否出現(xiàn)單詞自定義錯(cuò)誤信息字段驗(yàn)證產(chǎn)生的錯(cuò)誤信息可以在類級(jí)別或?qū)嵗?jí)別配置。在類級(jí)別時(shí),可以定義為錯(cuò)誤碼和錯(cuò)誤信息的字典映射在類實(shí)例化時(shí),給參數(shù)傳參對(duì)象 有三種方式創(chuàng)建自定義的field。 創(chuàng)建Field類的子類 創(chuàng)建繼承自marshmallow.fields.Field類的子類并實(shí)現(xiàn)_serialize和/...
摘要:是以太坊開(kāi)發(fā)的個(gè)人區(qū)塊鏈,可用于部署合約,開(kāi)發(fā)應(yīng)用程序和運(yùn)行測(cè)試。安裝是一個(gè)用于與以太坊交互的庫(kù)。啟動(dòng)以太坊測(cè)試區(qū)塊鏈服務(wù)器要部署智能合約,我們應(yīng)該啟動(dòng)測(cè)試以太坊服務(wù)器。最后,你將在以太坊合約中設(shè)置調(diào)用用戶對(duì)象時(shí)獲得的值。 將數(shù)據(jù)存儲(chǔ)在數(shù)據(jù)庫(kù)中是任何軟件應(yīng)用程序不可或缺的一部分。無(wú)論如何控制該數(shù)據(jù)庫(kù)都有一個(gè)該數(shù)據(jù)的主控。區(qū)塊鏈技術(shù)將數(shù)據(jù)存儲(chǔ)到區(qū)塊鏈網(wǎng)絡(luò)內(nèi)的區(qū)塊中。因此,只要某個(gè)節(jié)點(diǎn)與網(wǎng)...
摘要:是以太坊開(kāi)發(fā)的個(gè)人區(qū)塊鏈,可用于部署合約,開(kāi)發(fā)應(yīng)用程序和運(yùn)行測(cè)試。安裝是一個(gè)用于與以太坊交互的庫(kù)。啟動(dòng)以太坊測(cè)試區(qū)塊鏈服務(wù)器要部署智能合約,我們應(yīng)該啟動(dòng)測(cè)試以太坊服務(wù)器。最后,你將在以太坊合約中設(shè)置調(diào)用用戶對(duì)象時(shí)獲得的值。 將數(shù)據(jù)存儲(chǔ)在數(shù)據(jù)庫(kù)中是任何軟件應(yīng)用程序不可或缺的一部分。無(wú)論如何控制該數(shù)據(jù)庫(kù)都有一個(gè)該數(shù)據(jù)的主控。區(qū)塊鏈技術(shù)將數(shù)據(jù)存儲(chǔ)到區(qū)塊鏈網(wǎng)絡(luò)內(nèi)的區(qū)塊中。因此,只要某個(gè)節(jié)點(diǎn)與網(wǎng)...
閱讀 1641·2021-09-02 09:55
閱讀 1115·2019-08-30 13:19
閱讀 1403·2019-08-26 13:51
閱讀 1453·2019-08-26 13:49
閱讀 2383·2019-08-26 12:13
閱讀 463·2019-08-26 11:52
閱讀 1910·2019-08-26 10:58
閱讀 3090·2019-08-26 10:19