使用棉花糖验证具有列表长度约束的模式列表

例如,我要检查数据是否包含格式正确的字典列表,并且此列表的长度在1到10之间。

from marshmallow import Schema,fields

class Record(Schema): 
    id = fields.Integer(required=True)
    # more fields here,let's omit them

schema = Record(many=True)
# somehow define that we have constraint on list length
# list length should be between 1 and 10 inclusive

# validation should fail
errors = schema.validate([])
assert errors  # length < 1
errors = schema.validate([{"id": i} for i in range(100)])
assert errors  # length > 10

# validation should succeed
errors = schema.validate([{"id": i} for i in range(5)])
assert not errors

是否可以使用棉花糖定义此类约束?


我需要这样的东西,但我想避免在数据中嵌套更多级别:

from marshmallow.validate import Length

class BatchOfRecords(Schema):
    records = fields.nested(
        Record,required=True,many=True,validate=Length(1,10)
    )

UPD:

因此,为了澄清这个问题,我想验证一列字典:

[
    {"id": 1},{"id": 2},...
]

不是字典,其键包含字典列表:

# it works but it introduces extra level of nesting,# I want to avoid it
{
    "records": [
        {"id": 1},...
    ]
}
coalawang 回答:使用棉花糖验证具有列表长度约束的模式列表

编辑

因此可以仅使用棉花糖来验证集合。您可以将pass_many kwarg与pre_loadpost_load方法一起使用。我在pre_load上没有获得成功,但是开始从事邮政工作。 pass_many kwarg会将输入视为集合,因此您可以在加载后检查集合的长度。我使用many kwarg,以便仅在传递记录集而不是单个记录时才检查长度

from marshmallow import Schema,fields,ValidationError,post_load


class Record(Schema):
    id = fields.Integer(required=True)
    name = fields.String(required=True)
    status = fields.String(required=True)

    @post_load(pass_many=True)
    def check_length(self,data,many,**kwargs):
        if many:
            if len(data) < 1 or len(data) > 10:
                raise ValidationError(message=['Record length should be greater than 1 and less than 10.'],field_name='record')

编辑测试案例

from unittest import TestCase

from marshmallow import ValidationError

from stack_marshmallow import Record


class TestStackSchemasNonNested(TestCase):

    def test_empty_dict(self):
        with self.assertRaises(ValidationError) as exc:
            Record(many=True).load([])
        self.assertEqual(exc.exception.messages['record'],['Record length should be greater than 1 and less than 10.'])

    def test_happy_path(self):
        user_data = [{"id": "1","name": "apple","status": "OK"},{"id": "2","status": 'OK'}]
        data = Record(many=True).load(user_data)
        self.assertEqual(len(data),2)

    def test_invalid_values_with_valid_values(self):
        user_data = [{"id": "1","status": 'OK'},{"id": "2"}]
        with self.assertRaises(ValidationError) as exc:
            Record(many=True).load(user_data)
        self.assertEqual(exc.exception.messages[1]['name'],['Missing data for required field.'])
        self.assertEqual(exc.exception.messages[1]['status'],['Missing data for required field.'])

    def test_too_many(self):
        user_data = [{"id": "1",{"id": "3",{"id": "4",{"id": "5",{"id": "6",{"id": "7",{"id": "8",{"id": "9",{"id": "10",{"id": "11",]
        with self.assertRaises(ValidationError) as exc:
            Record(many=True).load(user_data)
        self.assertEqual(exc.exception.messages['record'],['Record length should be greater than 1 and less than 10.'])
  

编辑源https://marshmallow.readthedocs.io/en/stable/extending.html

您非常亲密。我增加了一些记录的复杂性,因为我认为您不会只拥有一个字段,否则我只会使用整数列表。我还添加了一些单元测试,以便您了解如何进行测试。

from marshmallow import Schema,validate


class Record(Schema):
    id = fields.Integer(required=True)
    name = fields.String(required=True)
    status = fields.String(required=True)


class Records(Schema):
    records = fields.List(
        fields.Nested(Record),required=True,validate=validate.Length(min=1,max=10)
    )

测试案例

from unittest import TestCase

from marshmallow import ValidationError

from stack_marshmallow import Records


class TestStackSchemas(TestCase):

    def setUp(self):
        self.schema = Records()

    def test_empty_dict(self):
        with self.assertRaises(ValidationError) as exc:
            self.schema.load({})
        self.assertEqual(exc.exception.messages['records'],['Missing data for required field.'])

    def test_empty_empty_list_in_dict(self):
        with self.assertRaises(ValidationError) as exc:
            self.schema.load({"records": []})
        self.assertEqual(exc.exception.messages['records'],['Length must be between 1 and 10.'])

    def test_missing_fields_in_single_record(self):
        with self.assertRaises(ValidationError) as exc:
            self.schema.load({"records": [{"id": 1}]})
        self.assertEqual(exc.exception.messages['records'][0]['name'],['Missing data for required field.'])
        self.assertEqual(exc.exception.messages['records'][0]['status'],['Missing data for required field.'])

    def test_list_too_long_and_invalid_records(self):
        with self.assertRaises(ValidationError) as exc:
            self.schema.load({"records":
                                  [{"id": 1,"name": "stack","status": "overflow"},{"id": 2,{"id": 3,{"id": 4,{"id": 5,{"id": 6,{"id": 7,{"id": 8,{"id": 9,{"id": 10,{"id": 11,"status": "overflow"}]})
        self.assertEqual(exc.exception.messages['records'],['Length must be between 1 and 10.'])
  

来源:https://marshmallow.readthedocs.io/en/stable/nesting.html和   https://marshmallow.readthedocs.io/en/stable/examples.html

,

我想做的事可以使用这个小库:https://github.com/and-semakin/marshmallow-toplevel

pip install marshmallow-toplevel

用法:

from marshmallow.validate import Length
from marshmallow_toplevel import TopLevelSchema

class BatchOfRecords(TopLevelSchema):
    _toplevel = fields.Nested(
        Record,many=True,validate=Length(1,10)
    )
本文链接:https://www.f2er.com/2968949.html

大家都在问