Наследование метапараметра исключения из суперсхемы (зефир)

У меня есть иерархия объектов и иерархия соответствующих им схем. Схема на промежуточном уровне этой иерархии исключает конкретное унаследованное поле. Я ожидаю, что схемы, наследующие от него, «наследуют» это исключение, но это не похоже на тот случай, если они добавят свои собственные исключенные поля в свои метаклассы:

from marshmallow import fields
from marshmallow.schema import Schema


class AncestorSchema(Schema):
    a = fields.Str()
    b = fields.Str()


class IntermediateSchema(AncestorSchema):
    c = fields.Str()

    class Meta:
        exclude = ('b',)


class FinalSchema(IntermediateSchema):
    d = fields.Str()

    class Meta:
        exclude = ('c',)


value = dict(
    a="Field A",
    b="Field B",
    c="Field C",
    d="Field D"
)

print(IntermediateSchema().dump(value).data)

>>> {'c': 'Field C', 'a': 'Field A'}

print(FinalSchema().dump(value).data)

>>> {'d': 'Field D', 'a': 'Field A', 'b': 'Field B'}

В приведенном выше примере FinalSchema наследуется от IntermediateSchema (которое исключает поле b) и исключает поле c в своем собственном классе Meta. Ожидаемым поведением будет то, что результирующая схема будет исключать как b, так и c, но на самом деле она исключает только c.

Конечно, можно вручную включить исключенные поля суперсхемы в наследуемые поля исключенной схемы, но суть наследования не в этом, и, кроме того, это громоздко.

Интересно, можно ли добиться желаемого поведения элегантным способом, или текущее поведение наследования схемы на самом деле является ошибкой.

Изучение исходного кода marshmallow показывает, что наследование данных из метаклассов суперсхем поддерживается, по крайней мере, частично (а именно, значение опции ordered Meta наследуется от суперсхем).


person Inego    schedule 06.12.2017    source источник


Ответы (2)


Изменить: это заменило принятый ответ, поэтому игнорируйте следующее предложение.

Принятый в настоящее время ответ не работает. "я" не определено. Я нашел решение, которое действительно работает.

from marshmallow import fields
from marshmallow.schema import Schema


class AncestorSchema(Schema):
    a = fields.Str()
    b = fields.Str()


class IntermediateSchema(AncestorSchema):
    c = fields.Str()

    class Meta:
        exclude = ('b',)


class FinalSchema(IntermediateSchema):
    d = fields.Str()

    def __init__(self, *args, **kwargs):
        self.opts.exclude += ('c',)
        super().__init__(*args, **kwargs)
person flayman    schedule 17.07.2019
comment
Теперь, когда этот ответ в настоящее время принят, его первое предложение больше не имеет смысла. - person Inego; 25.10.2019
comment
Ха! Я изменю это. Спасибо. - person flayman; 26.10.2019

Вам также необходимо указать базовый класс для класса Meta. Вам также нужно использовать какое-то отражение, чтобы получить значение из базового класса и добавить к нему.

from marshmallow import fields
from marshmallow.schema import Schema


class AncestorSchema(Schema):
    a = fields.Str()
    b = fields.Str()


class IntermediateSchema(AncestorSchema):
    c = fields.Str()

    class Meta:
        exclude = ('b',)


class FinalSchema(IntermediateSchema):
    d = fields.Str()

    def __init__(self, *args, **kwargs):
        self.opts.exclude += ('c',)
        super().__init__(*args, **kwargs)
person CaptObvious    schedule 08.03.2018
comment
Я не понимаю, где здесь определяется self? - person Lotram; 01.03.2019
comment
Это не так, и это не работает. Смотрите мой ответ ниже. - person flayman; 17.07.2019