首页 > 解决方案 > 按子元素的属性排序关系

问题描述

我在 Flask 项目中使用 flask-sqlalchemy 来为我的数据库建模。
我需要根据一侧不同子元素的属性对多对多关系的元素进行排序。

我有“工作”(父元素)、“标签”(子元素)、 “类型”(标签上的一对多关系)和“块”(类型上的一对多关系)。标签和作品通过映射表"work_tag_mapping" 连接

本质上,每个标签都只有一种类型,每种类型恰好属于一个区块,并且可以在许多作品上添加许多标签。

我现在希望作品上的标签列表首先按块排序,然后键入第二个(两者都有一个“位置”

这是我的表格(为了问题而简化):

class Work(db.Model):
  __tablename__ = 'work'
  id = db.Column(db.Integer, primary_key=True)
  name = db.Column(db.String(255, collation='utf8_bin'))
  tags = db.relationship('Tag', order_by="Tag.type.block.position, Tag.type.position", secondary=work_tag_mapping)

class Tag(db.Model):
  __tablename__ = 'tag'
  id = db.Column(db.Integer, primary_key=True)
  name = db.Column(db.String(255, collation='utf8_bin'))
  type_id = db.Column(db.Integer, db.ForeignKey('type.id'), nullable=False)
  type = db.relationship('Type')

work_tag_mapping = db.Table('work_tag_mapping',  
    db.Column('id', db.Integer, primary_key=True),
    db.Column('work_id', db.Integer, db.ForeignKey('work.id'), nullable=False),
    db.Column('tag_id', db.Integer, db.ForeignKey('tag.id'), nullable=False)
)

class Type(db.Model):
  __tablename__ = 'type'
  id = db.Column(db.Integer, primary_key=True)
  name = db.Column(db.String(255, collation='utf8_bin'))
  position = db.Column(db.Integer)
  block_id = db.Column(db.Integer, db.ForeignKey('block.id'), nullable=False)
  block = db.relationship('Block')

class Block(db.Model):
  __tablename__ = 'block'
  id = db.Column(db.Integer, primary_key=True)
  name = db.Column(db.String(255, collation='utf8_bin'))
  position = db.Column(db.Integer)

现在,“tags”关系中的“order_by”并没有像我最初希望的那样工作。我得到的错误是"sqlalchemy.exc.InvalidRequestError: Property 'type' is not an instance of ColumnProperty (i.e. does not correspond directly to a Column)."

我是 SQLalchemy、Flask 和 Python 的新手,这里的资源或问题都没有提到这样的案例。

标签: pythonsqlalchemy

解决方案


虽然这似乎无法直接实现,但添加一个 getter 并在检索时执行排序就可以了。添加lazy='dynamic'可确保集合表现为查询,因此可以执行连接。

_tags = db.relationship('Tag', lazy='dynamic')

    @hybrid_property
    def tags(self):
        return self._tags.join(Type).join(Block).order_by(Block.position, Type.position)

推荐阅读