如何在 Flask sqlalchemy 中获取与外键链接的模型属性?

Kon*_*zec 2 python sqlalchemy flask flask-sqlalchemy marshmallow

我在 Flask-Sqlalchemy 中创建了两个模型。这些模型是TicketsNamespace。两种模型都使用外键连接。我还创建了 marshmallow-sqlalchemyModelSchema定义以在 RESTful API 中使用。

class Ticket(db.Model):

    id = db.Column(db.Integer, primary_key=True)
    namespace = db.Column(
        db.Integer, db.ForeignKey('namespace.id'), nullable=False)
    title = db.Column(db.String)
    description = db.Column(db.Text)
    status = db.Column(db.String)
    severity = db.Column(db.String)


class TicketSchema(ma.ModelSchema):
    class Meta:
        model = Ticket
        include_fk = True
Run Code Online (Sandbox Code Playgroud)
class Namespace(db.Model):

    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String)


class NamespaceSchema(ma.ModelSchema):
    class Meta:
        model = Namespace
Run Code Online (Sandbox Code Playgroud)

在我看来,我正在尝试按给定的namespace过滤所有票证。这是我的查询:

@app.route("/<string:name>", methods=["GET"])
def get_tickets_by_namespace(name):

    tickets_query = Ticket.query.join(Namespace).filter(Namespace.name == name)
    result = TicketSchema(many=True).dump(tickets_query).data

    return jsonify({"tickets": result})
Run Code Online (Sandbox Code Playgroud)

如何在加入和过滤两个模型时nameNamespace模型访问属性?

当我使用 输入上述 URL 时/aa,我只得到namespace_id,我还想查看命名空间的名称:

{
  "tickets": [
    {
      "description": "xcv",
      "id": 1,
      "namespace": 1,
      "severity": "xcvbn",
      "status": "xcvb",
      "title": "xc"
    },
    {
      "description": "xcv",
      "id": 3,
      "namespace": 1,
      "severity": "xcvbnb",
      "status": "axcvb",
      "title": "axcb"
    },
    {
      "description": "xcv",
      "id": 4,
      "namespace": 1,
      "severity": "bnb",
      "status": "axcvb",
      "title": "aaaxcb"
    }
  ]
}
Run Code Online (Sandbox Code Playgroud)

Mar*_*ers 5

include_fk你想给你的模型一个关系,而不是使用:

class Ticket(db.Model):
    id = db.Column(db.Integer, primary_key=True)

    namespace_id = db.Column(
        'namespace',
        db.Integer,
        db.ForeignKey('namespace.id'),
        nullable=False
    )
    namespace = db.relationship("Namespace", backref="tickets")

    title = db.Column(db.String)
    description = db.Column(db.Text)
    status = db.Column(db.String)
    severity = db.Column(db.String) 
Run Code Online (Sandbox Code Playgroud)

关系会自动包含在内,但它们的默认字段仍然只序列化了外键。

确保仅所有 SQLAlchemy 模型加载后才定义 marshmallow-sqlalchemy 模型,因为创建模型将触发映射配置运行(其中字符串表达式,例如调用中的"Namespace"字符串db.relationship())被解析。在创建Ticket模型之前,您无法创建模型的棉花糖模型Namespace

接下来,使用一个Nested()字段来拉入Namespace你想要的属性:

class TicketSchema(ma.ModelSchema):
    class Meta:
        model = Ticket

    # don't include 'tickets' when including a namespace schema.
    # you can also put this on the NestedSchema model.
    namespace = ma.Nested("NamespaceSchema", exclude=("tickets",))
Run Code Online (Sandbox Code Playgroud)

在上面的例子中,exclude=("tickets",)需要参数来避免对象tickets上的关系Namespace也反映在结果 JSON 中(它只包含外键,Marshmallow 意识到它已经序列化了票证)。您还可以将 添加excludeNamespaceSchema模型中Meta,但是所有对该架构的使用都将排除该tickets字段。

通过上述更改,您的路线输出:

{
  "tickets": [
    {
      "description": "xcv",
      "id": 1,
      "namespace": {
        "id": 1,
        "name": "aa"
      },
      "severity": "xcvbn",
      "status": "xcvb",
      "title": "xc"
    },
    {
      "description": "xcv",
      "id": 3,
      "namespace": {
        "id": 1,
        "name": "aa"
      },
      "severity": "xcvbnb",
      "status": "axcvb",
      "title": "axcb"
    },
    {
      "description": "xcv",
      "id": 4,
      "namespace": {
        "id": 1,
        "name": "aa"
      },
      "severity": "bnb",
      "status": "axcvb",
      "title": "aaaxcb"
    }
  ]
}
Run Code Online (Sandbox Code Playgroud)