Flask 截取webargs+;棉花糖反序列化

Flask 截取webargs+;棉花糖反序列化,flask,flask-restful,marshmallow,webargs,Flask,Flask Restful,Marshmallow,Webargs,我有一个可以通过PUT更新的问题对象。但是,如果问题已经得到回答,则某些字段将无法再更新。执行PUT请求时,发送所有字段(与修补请求不同);改变的和不变的。我的目标是在验证之前捕获未更改的字段,并将其从args中删除 这是一个必须在许多视图中重用的问题,因此只显式地执行它的简单解决方案是不够的,因为它会在我的所有视图中添加大量的锅炉板代码。相反,我正在寻找一种近乎透明的解决方案,例如从定制模式继承,使用定制的使用put\u kwargs而不是put\u kwargs,在字段创建中添加一个选项。。

我有一个可以通过PUT更新的问题对象。但是,如果问题已经得到回答,则某些字段将无法再更新。执行PUT请求时,发送所有字段(与修补请求不同);改变的和不变的。我的目标是在验证之前捕获未更改的字段,并将其从args中删除

这是一个必须在许多视图中重用的问题,因此只显式地执行它的简单解决方案是不够的,因为它会在我的所有视图中添加大量的锅炉板代码。相反,我正在寻找一种近乎透明的解决方案,例如从定制模式继承,使用定制的
使用put\u kwargs
而不是
put\u kwargs
,在字段创建中添加一个选项。。。不要太重

让我们从一个例子开始:

class QuestionGetArgs(Schema):
    question_id = fields.Integer(required=True, location="view_args", validate=lambda x: x > 0)

    @post_load
    def deserialize(self, args):
        args["question"] = QuestionDao.get_question_by_id(args.pop("question_id"))


class QuestionPutArgs(QuestionGetArgs):
    title = fields.Str(location="json")
    answer_type = fields.Str(location="json", validate=validate.OneOf("Open", "SingleChoice", "MultipleChoices"))

    @post_load
    def validate_question(self, args):
        if "answer_type" in args and QuestionDao.has_answers(args["question"]):
            raise ValidationError("Cannot edit question answer_type if there already are answers")
        QuestionArgsValidator.validate_schema(self.get_updated_schema(args))  # validates that once updated, the question would still be valid


class Question(DefaultResource):

    @use_kwargs(QuestionPutArgs)
    def put(self, question, question_id, **kwargs):
        try:
            updated_question = QuestionDao.update_question(question, **kwargs)
        except UniqueKeyViolation as e:
            abort(409, str(e))
        return self.jsonify(EntityDictBuilder.make_question(updated_question))
注意,我并没有把问题的所有字段都放进去,只有一个我有意见

在此状态下,对已回答问题的任何输入都将失败,因为我们不会检查
答案类型是否已更改

我的问题如下:

  • 必须加载
    args[“问题”]
    ,以便我们可以将
    args[“答案类型”]
    args[“问题”]进行比较。答案类型
  • 一旦
    args[“question”]
    被加载,所有内容都被加载,并且
    post\u load
    被调用,我要从
    args
    中删除内容已经太晚了
  • 我必须能够知道要更新的对象是
    args[“问题”]
    ,例如,如果解决方案要应用于
    /clients/12/responses/32
    而不是
    /questions/98
    ,则必须将字段与前者中id 32的响应进行比较,关于后者中的id 98问题
到目前为止,我试图做的是让我自己的
@use\u put\u kwargs

def use_put_kwargs(schema_cls, schema_kwargs=None, **kwargs):
    schema_kwargs = schema_kwargs or {}

    def factory(request):
        # Filter based on 'fields' query parameter
        only = request.args.get("fields", None)
        # Respect partial updates for PATCH requests
        partial = request.method == "PATCH"
        schema = schema_cls(only=only, partial=partial, context={"request": request}, **schema_kwargs)
        return UnloadNotModifiedSchemaDecorator(schema, list(request.json.keys()))

    return use_kwargs(factory, **kwargs)
由于
UnloadNotModifiedSchemaDecorator
是一个装饰器(在设计模式意义上,而不是python意义上),除了
load
,它将有机会给
load
一个其他行为之外,所有的责任都传递给它的模式

class UnloadNotModifiedSchemaDecorator(DefaultSchema):
    def __init__(self, schema, body_params):
        self.schema = schema
        self.body_params = body_params

    def load(self, data, many=None, partial=None):
        loaded = self.schema.load(data, many, partial)
        return loaded

    def loads(self, json_data, many=None, *args, **kwargs):
        loaded = self.schema.loads(json_data, many, *args, **kwargs)
        return loaded

    # copy all fields and methods from schema
    @property
    def declared_fields(self):
        return self.schema.declared_fields

    @property
    def many(self):
        return self.schema.many

[...]

    def validate(self, data, many=None, partial=None):
        return self.schema.validate(data, many, partial)
但事实证明,在
load=self.schema.load(data,many,partial)
return-loaded
之间,我不能做任何事情,因为调用了
post\u-load
,要捕获未修改的字段已经太晚了

那么,当它们已经被反序列化,但在
post\u load
发生之前,如何捕获它们呢