【问题标题】:get column of the parent table sqlAlchemy获取父表 sqlAlchemy 的列
【发布时间】:2018-01-25 08:13:58
【问题描述】:

我在 SqlAlchemy 中有两个模型,它们彼此具有外键关系。我需要的是,当我将Post 的对象作为json 获取时,它还应该包含User 模型的一些预定义列。

就像在这种情况下,我需要将User 模型的名称列与Post 对象一起返回。

我尝试在 Post 模型中添加一个 json 属性,但它只返回模型。

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    email = db.Column(db.String(255), unique=True)
    name = db.Column(db.String(255))
    confirmed = db.Column(db.String(255))
    password = db.Column(db.String(255))
    created_at = db.Column(db.DateTime())


class Post(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    message = db.Column(db.String(255))
    created_at = db.Column(db.DateTime())
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'))

    @property
    def json(self):
        return to_json(self, self.__class__)

def to_json(inst, cls):
    """
    Jsonify the sql alchemy query result.
    """
    convert = dict()
    # add your coversions for things like datetime's
    # and what-not that aren't serializable.
    d = dict()
    for c in cls.__table__.columns:
        v = getattr(inst, c.name)
        if c.type in convert.keys() and v is not None:
            try:
                d[c.name] = convert[c.type](v)
            except:
                d[c.name] = "Error:  Failed to covert using ", str(convert[c.type])
        elif v is None:
            d[c.name] = str()
        else:
            d[c.name] = v
    return json.dumps(d)

【问题讨论】:

  • 你能出示to_json的代码吗?
  • @stamaimer 我已经编辑了帖子并添加了功能。

标签: python json flask orm sqlalchemy


【解决方案1】:

您应该使用来自SQLAlchemyrelationship 并修改您的to_json 以解析relationship

class Post(db.Model):

    # other fields

    user = db.relationship("User", foreign_keys=user_id)

    @property
    def json(self):

        attrs = self.__mapper__.attrs.keys()

        relationships = self.__mapper__.relationships.keys()

        fields = [item for item in [attr for attr in attrs if attr not in relationships]]

        container = {field: getattr(self, field) for field in fields}

        for relationship in relationships:

            related = getattr(self, relationship)

            if related:

                is_list = self.__mapper__.relationships[relationship].uselist

                if is_list:

                    container[relationship] = [record.to_dict(depth, include) for record in related]

                else:

                    container[relationship] = related.to_dict(depth, include)

        return container

我将to_json 移至json。你最好有一个基础模型类,它有一个to_json 方法,从基础模型类继承的所有子类都可以有这个方法。在数据模型类的转换实例的过程中可能会提出一些其他问题。我提供的to_json 方法是to_dict 的简化版本。

【讨论】:

    【解决方案2】:

    如果我对您的理解正确,您正在查询 Post 模型并想要 User 和与其一起返回的用户信息的子集,但只看到 Post.user_id?在这种情况下,我将使用 sqlalchemy 提供的 relationship 属性:

    http://docs.sqlalchemy.org/en/latest/orm/basic_relationships.html#many-to-one

    这样你的 Post 类看起来类似于

    class Post(db.Model):
        id = db.Column(db.Integer, primary_key=True)
        message = db.Column(db.String(255))
        created_at = db.Column(db.DateTime())
        user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
        user = relationship(User, back_populates="user", uselist=False)
    

    【讨论】:

    • 用户和帖子之间必须是一对多的关系。
    • 抱歉,忘记包含 uselist=False,这说明这是一对一的关系 :) 我将编辑我的答案。
    • 我说,一般来说,用户和帖子的关系是一对多的。一个用户可能会写很多帖子。
    • 哦,哇,我浏览了您的回复,这对我来说是因果报应!你完全正确@stamaimer。我会将链接更新为one-to-many,但我相信Post 上的关系仍然正确:)
    【解决方案3】:

    您需要在 Post 模型中为用户设置一个关系,并编写一个使用该关系执行连接的查询。

    from sqlalchemy.orm import relationship, attributes
    
    class Post(Base):
        ...
        users = relationship("User")
    
    
    Post.query().options(joinedload(Post.users).load_only('name')).all()
    

    为您的模型实例提供更好的 JSON 转换。

    您可以使用模型继承的to_dictto_json 方法定义抽象模型。

    还要确保您没有强制加载延迟字段。见__repr__

    def __repr__(self):
        fields = []
        for f in self.__table__.columns.keys():
            if f not in attributes.instance_state(self).unloaded:
                fields.append("%s=%s" % (f, getattr(self, f)))
            else:
                fields.append("%s=*" % (f,))
    
        return "<%s (%s)>" % ', '.join(self.__class__.__name__, fields)
    
    def to_dict(self):
        dct = {}
        for field, value in self.__dict__.items():
            if not field.startswith('_'):
                if isinstance(value, Base):
                    dct[field] = value.to_dict()
                else:
                    dct[field] = value
    
        return dct
    
    
    def to_json(self):
         return json.dumps(
                   self.to_dict())
    

    【讨论】:

      猜你喜欢
      • 2011-09-22
      • 2014-09-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-26
      • 2010-12-31
      • 1970-01-01
      • 2021-09-09
      相关资源
      最近更新 更多