拦截webargs和棉花糖反序列化中未更改的字段

问题描述

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

这是必须在许多视图中重复使用的内容,因此仅显式地进行操作的简单解决方案还不够好,因为这会在我的所有视图中添加很多样板代码。相反,我正在寻找一种几乎透明的解决方案,例如使用定制的use_put_kwargs而非put_kwargs从定制的Schema继承,为创建字段添加一个选项。没有什么太重了。

让我们从一个示例开始:

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))

我没有填写所有问题的字段,只有我遇到的一个字段。

在这种状态下,由于我们不检查answer_type是否已更改,因此回答问题的任何PUT都将失败。

我的问题如下:

  • args["question"]必须加载,以便我们可以将args["answer_type"]args["question"].answer_type进行比较。
  • 一旦加载args["question"],就加载所有内容调用post_load,对于我来说,从args删除内容为时已晚。
  • 我必须能够知道要更新的对象是args["question"],例如如果将解决方案应用于/clients/12/responses/32而不是/questions/98,则必须将字段与前者ID 32的响应字段和ID 98的问题进行比较。后者。

到目前为止,我试图做的是制作自己的@use_put_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之外的所有职责传递给其架构,{{1} }}的其他行为。

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,*args,**kwargs): loaded = self.schema.loads(json_data,**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,partial=None): return self.schema.validate(data,partial) loaded = self.schema.load(data,partial)之间我什么也做不了,因为调用return loaded,现在捕获未修改的字段已经太晚了。

那么,如何在它们反序列化之后post_load发生之前捕获它们?

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...