成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

marshmallow之Schema延伸功能

hzx / 1439人閱讀

摘要:創(chuàng)建實(shí)例時(shí)如果傳遞了,表示需要接收輸入數(shù)據(jù)集合,裝飾器注冊(cè)預(yù)處理和后處理方法時(shí)需要傳遞參數(shù)。

預(yù)處理和后處理方法

數(shù)據(jù)的預(yù)處理和后處理方法通過(guò)pre_load, post_load, pre_dumppost_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 AppError
Schema級(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

相關(guān)文章

  • marshmallow快速上手

    摘要:方法對(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)...

    jhhfft 評(píng)論0 收藏0
  • marshmallowschema嵌套

    摘要:嵌套可以嵌套使用以表示對(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 ...

    miracledan 評(píng)論0 收藏0
  • marshmallow自定義Field

    摘要:有三種方式創(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和/...

    AWang 評(píng)論0 收藏0
  • python和flask框架開(kāi)發(fā)以太坊智能合約

    摘要:是以太坊開(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)...

    enrecul101 評(píng)論0 收藏0
  • python和flask框架開(kāi)發(fā)以太坊智能合約

    摘要:是以太坊開(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)...

    UnixAgain 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

hzx

|高級(jí)講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<