摘要:創(chuàng)建實例時如果傳遞了,表示需要接收輸入數(shù)據(jù)集合,裝飾器注冊預處理和后處理方法時需要傳遞參數(shù)。
預處理和后處理方法
數(shù)據(jù)的預處理和后處理方法通過pre_load, post_load, pre_dump和post_dump裝飾器注冊:
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"預處理和后處理的many參數(shù)
預處理和后處理方法默認一次接收一個對象/數(shù)據(jù),在運行時處理傳遞給schema對象的many參數(shù)。
創(chuàng)建schema實例時如果傳遞了many=True,表示需要接收輸入數(shù)據(jù)集合,裝飾器注冊預處理和后處理方法時需要傳遞參數(shù)pass_many=True。預處理和后處理方法接收輸入數(shù)據(jù)(可能是單個數(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="mick@stones.org") user_data = user_schema.dump(user).data # {"user": {"email": "mick@stones.org", "name": "Mick"}} users = [User("Keith", email="keith@stones.org"), User("Charlie", email="charlie@stones.org")] users_data = user_schema.dump(users, many=True).data # {"users": [{"email": "keith@stones.org", "name": "Keith"}, # {"email": "charlie@stones.org", "name": "Charlie"}]} user_objs = user_schema.load(users_data, many=True).data # [在預處理和后處理方法中拋出異常, ]
字段驗證產生的錯誤字典的_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."]}
如果不想存儲在_schema鍵中,可以指定新的鍵名傳遞給ValidationError的第二個參數(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."]}預處理和后處理方法的調用順序
反序列化的處理流程:
@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ù)裝飾的方法的調用順序
錯誤處理重寫schema的handle_error方法來自定義錯誤處理功能。handle_error接收一個ValidationError異常實例,一個原始對象(序列化)或輸入數(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級別的驗證
使用marshmallow.validates_schema裝飾器可以為Schema注冊一個schema級別的驗證函數(shù),其異常信息保存在錯誤字典的_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"]驗證原始輸入數(shù)據(jù)
通常驗證器會忽略未聲明的field的數(shù)據(jù)輸入。如果要訪問原始輸入數(shù)據(jù)(例如如果發(fā)送了未知字段視為驗證失敗),可以給validates_schema裝飾器傳遞一個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"}存儲特定field的錯誤
如果要在指定field上保存schema級別的驗證錯誤,可以給ValidationError的第二個參數(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"]重寫屬性訪問的方式
marshmallow默認使用utils.get_value函數(shù)獲取各種類型的對象的屬性以進行序列化。
通過重寫get_attribute方法可以重寫對象屬性的訪問方式:
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選項
class Meta是配置和修改Schema行為的一種方式。通過繼承自SchemaOpts可以添加自定義class Meta選項(Schema.Meta API docs查看原生選項)。
下面的代碼通過自定義class Meta選項實現(xiàn)了預處理和后處理的many參數(shù)這一節(jié)中例子的功能。
首先通過繼承SchemaOpts類添加了兩個選項,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="keith@stones.com") result = ser.dump(user) result.data # {"user": {"name": "Keith", "email": "keith@stones.com"}}使用上下文
Schema的context屬性存儲序列化及反序列化可能要用到的額外信息。
schema = UserSchema() # Make current HTTP request available to # custom fields, schema methods, schema validators, etc. schema.context["request"] = request schema.dump(user)
我的博客即將同步至騰訊云+社區(qū),邀請大家一同入駐:https://cloud.tencent.com/dev...
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/43864.html
摘要:方法對應的是方法,它反序列化一個字典為數(shù)據(jù)結構。某些例如和內置了驗證器驗證集合時,錯誤字典將基于無效字段的索引作為鍵通過給的參數(shù)傳遞對象,可以執(zhí)行額外的驗證驗證函數(shù)可以返回布爾值或拋出異常。 快速上手 Declaring Schemas 首先創(chuàng)建一個基礎的user模型(只是為了演示,并不是真正的模型): import datetime as dt class User(object)...
摘要:嵌套可以嵌套使用以表示對象間的關系如外鍵關系。在下面的例子中,和對象是一對多的關系必須使用或參數(shù)避免無限遞歸也可以使用導入模塊的方式傳遞嵌套,如自嵌套給傳遞字符串參數(shù)表示和對象本身的關系 schema嵌套 schema可以嵌套使用以表示對象間的關系(如外鍵關系)。 例如下例中Blog有一個用User對象表示的author屬性: import datetime as dt class ...
摘要:有三種方式創(chuàng)建自定義的。下面的例子判斷某個對象是否是某個對象的作者,以及的屬性是否出現(xiàn)單詞自定義錯誤信息字段驗證產生的錯誤信息可以在類級別或實例級別配置。在類級別時,可以定義為錯誤碼和錯誤信息的字典映射在類實例化時,給參數(shù)傳參對象 有三種方式創(chuàng)建自定義的field。 創(chuàng)建Field類的子類 創(chuàng)建繼承自marshmallow.fields.Field類的子類并實現(xiàn)_serialize和/...
摘要:是以太坊開發(fā)的個人區(qū)塊鏈,可用于部署合約,開發(fā)應用程序和運行測試。安裝是一個用于與以太坊交互的庫。啟動以太坊測試區(qū)塊鏈服務器要部署智能合約,我們應該啟動測試以太坊服務器。最后,你將在以太坊合約中設置調用用戶對象時獲得的值。 將數(shù)據(jù)存儲在數(shù)據(jù)庫中是任何軟件應用程序不可或缺的一部分。無論如何控制該數(shù)據(jù)庫都有一個該數(shù)據(jù)的主控。區(qū)塊鏈技術將數(shù)據(jù)存儲到區(qū)塊鏈網(wǎng)絡內的區(qū)塊中。因此,只要某個節(jié)點與網(wǎng)...
摘要:是以太坊開發(fā)的個人區(qū)塊鏈,可用于部署合約,開發(fā)應用程序和運行測試。安裝是一個用于與以太坊交互的庫。啟動以太坊測試區(qū)塊鏈服務器要部署智能合約,我們應該啟動測試以太坊服務器。最后,你將在以太坊合約中設置調用用戶對象時獲得的值。 將數(shù)據(jù)存儲在數(shù)據(jù)庫中是任何軟件應用程序不可或缺的一部分。無論如何控制該數(shù)據(jù)庫都有一個該數(shù)據(jù)的主控。區(qū)塊鏈技術將數(shù)據(jù)存儲到區(qū)塊鏈網(wǎng)絡內的區(qū)塊中。因此,只要某個節(jié)點與網(wǎng)...
閱讀 1639·2021-09-02 09:55
閱讀 1105·2019-08-30 13:19
閱讀 1402·2019-08-26 13:51
閱讀 1451·2019-08-26 13:49
閱讀 2378·2019-08-26 12:13
閱讀 459·2019-08-26 11:52
閱讀 1904·2019-08-26 10:58
閱讀 3087·2019-08-26 10:19