【问题标题】:Updating one to many relationship in Flask/ SQLAlchemy在 Flask/SQLAlchemy 中更新一对多关系
【发布时间】:2021-07-10 16:54:42
【问题描述】:

我的数据库中有两个模型 Parent 和 Child,这两个模型之间存在一对多的关系,即一个父母可以有多个孩子。

from flask import Flask, request
from flask_restful import Resource
from flask_sqlalchemy import SQLAlchemy
from flask_marshmallow import Marshmallow
from flask_restful import Api
from marshmallow import fields

app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///relationships.db"
db = SQLAlchemy(app)
ma = Marshmallow(app)
api = Api(app, prefix="/api")


class Parent(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(20), nullable=False, unique=True)
    children = db.relationship("Child", backref="parent")


class Child(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(20), nullable=False, unique=True)
    parent_id = db.Column(db.Integer, db.ForeignKey("parent.id"))


class ChildSchema(ma.SQLAlchemyAutoSchema):
    class Meta:
        model = Child
        ordered = True
        include_fk = True
        dump_only = ("id",)
        load_instance = True


class ParentSchema(ma.SQLAlchemyAutoSchema):
    children = fields.Pluck(ChildSchema, "name", many=True)

    class Meta:
        model = Parent
        ordered = True
        include_relationships = True
        dump_only = ("id",)
        load_instance = True

class ParentResource(Resource):
    @classmethod
    def get(cls, _id: int):
        parent_schema = ParentSchema()
        return parent_schema.dump(parent.query.filter_by(id=_id).first()), 200

    @classmethod
    def put(cls, _id: int):
        parent_json = request.get_json()
        parent_schema = ParentSchema()

        parent_input_data = parent_schema.load(parent_json)

        parent = Parent.query.filter_by(id=_id).first()
        parent.name = parent_input_data.name

        child_names = [child.name.lower() for child in parent.children]

        # Check if child is not already in parent children list
        for child_input in parent_input_data.children:
            if child_input.name.lower() not in child_names:
                parent.children.append(child_input)

        db.session.add(parent)
        db.session.commit()

        return {"message": "Updated"}, 200


api.add_resource(ParentResource, "/parent/<int:_id>")

if __name__ == "__main__":
    db.create_all()
    app.logger.info("Starting app...")
    app.run("127.0.0.1", 3003)

当我尝试通过添加一些新子项来更新父项时,我收到一个唯一键约束错误,因为似乎 SQLAlchemy 正在尝试在父表中运行插入查询,而不是尝试更新父表记录。父表中已经有一条同名“ABCD”的记录,即我只是尝试保持父名称不变并更新子表。

这是我为 PUT 请求提供的输入。

{
    "name": "ABCD",
    "children": [
        "Tom",
        "Spot"
    ]
}

有人可以帮我理解我哪里出错了吗?当我尝试更新父级而不尝试更新子级时,更新似乎按预期工作。仅当我尝试更新子关系时才会出现此问题。

【问题讨论】:

  • 尝试在ParentResource.put 方法中注释掉db.session.add(parent)。我认为您的对象已经在 db.session 中,因为您查询了它。stackoverflow.com/a/48592786/13468
  • 我也试过了,得到同样的错误。它再次尝试执行 INSERT。 sqlalchemy.exc.IntegrityError: (sqlite3.IntegrityError) UNIQUE 约束失败:parent.name [SQL: INSERT INTO parent (name) VALUES (?)]

标签: python python-3.x sqlite flask sqlalchemy


【解决方案1】:

尝试将您的查询从使用 INSERT INTO 更改为使用 UPDATEINSERT INTO 尝试添加新记录,而UPDATE 将修改现有记录。

【讨论】:

  • 我没有直接运行查询,而是使用 ORM 并且 ORM 似乎在执行插入而不是奇怪的更新。
  • 是的,但是 ORM 工具在后台执行查询。因此,它可能不是 db.session.add(parent),而是类似于 db.session.update(parent)。 kite.com/python/answers/…
猜你喜欢
  • 1970-01-01
  • 2016-06-15
  • 2021-08-31
  • 1970-01-01
  • 2014-09-26
  • 2016-12-03
  • 1970-01-01
  • 1970-01-01
  • 2017-09-01
相关资源
最近更新 更多