【问题标题】:SQLAlchemy - update an object with a transient objectSQLAlchemy - 使用瞬态对象更新对象
【发布时间】:2019-06-28 17:59:49
【问题描述】:

我正在尝试使用 flask-rest-api 作为一个简单的示例 web 服务的框架,使用 SQLAlchemy 作为 ORM。一切正常,除了处理更新时。

这是有问题的代码:

    @blp.arguments(DogSchema)
    @blp.response(DogSchema)
    def put(self, data, dog_id):
        """Update existing dog"""
        try:
            dog = Dog.query.get(dog_id)
        except Exception as e:
            abort(404, message="Item not found - %s" % e)
        
        # update the dog here
        return dog

当它执行时,data 变量是一个瞬态 Dog 模型对象。 flask-rest-api 负责反序列化 JSON 请求中的数据,查看您的 Marshmallow 架构并创建正确类型的 sqlalchemy 模型对象。

为了完整起见,这是我的模型和架​​构:

class Dog(db.Model):
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    name = db.Column(db.String, nullable=False)


@api.definition("Dog")
class DogSchema(ma.ModelSchema):
    class Meta:
        model = Dog
        strict = True
        ordered = True
    
    id = field_for(Dog, 'id', dump_only=True)

我想做的只是获取瞬态对象并使用所有属性更新会话中的对象。

我已经能够以两种不同的方式做到这一点,我都不喜欢这两种方式,我希望有更好的方式来做到这一点。

1) 通过合并

    @blp.arguments(DogSchema)
    @blp.response(DogSchema)
    def put(self, data, dog_id):
        """Update existing dog"""
        try:
            dog = Dog.query.get(dog_id)
        except Exception as e:
            abort(404, message="Item not found - %s" % e)

        data.id = dog_id
        db.session.merge(data)
        db.session.commit()
        return dog

这可行,但合并似乎有其他副作用 - 如果记录不在会话中,它会从数据库中提取,如果它在数据库中不存在,则添加它。

2) 通过棉花糖序列化

    @blp.arguments(DogSchema)
    @blp.response(DogSchema)
    def put(self, data, dog_id):
        """Update existing dog"""
        try:
            dog = Dog.query.get(dog_id)
        except Exception as e:
            abort(404, message="Item not found - %s" % e)

        serializer = DogSchema()
        serializer.load(serializer.dump(data).data, instance=dog, session=db.session, partial=True)
        db.session.commit()
        return dog

这使用 Marshmallow 将 data 变量序列化回 JSON,然后将其重新加载,这似乎效率很低。

我真的很想有这么简单的东西

    @blp.arguments(DogSchema)
    @blp.response(DogSchema)
    def put(self, data, dog_id):
        """Update existing dog"""
        try:
            dog = Dog.query.get(dog_id)
        except Exception as e:
            abort(404, message="Item not found - %s" % e)

        dog.update(data)
        db.session.commit()
        return dog

但这似乎并不存在,所以希望有人可以帮助我。

谢谢!

【问题讨论】:

  • 你找到解决办法了吗?

标签: flask sqlalchemy marshmallow


【解决方案1】:

你可以为你指定update方法Dog类:

class Dog(db.Model):
    ...
    def update(self, data):
        for k, v in data.items():
            setattr(self, k, v)
        return self

然后根据需要使用它:

    try:
        dog = Dog.query.get(dog_id)
    except Exception as e:
        abort(404, message="Item not found - %s" % e)

    dog.update(data)
    db.session.commit()

【讨论】:

  • setattr 有错字
猜你喜欢
  • 2011-06-14
  • 2012-01-25
  • 2012-06-04
  • 2021-05-22
  • 1970-01-01
  • 1970-01-01
  • 2011-09-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多