返回加入的桌子以JSON格式与Sqlalchemy和Flask Jsonify



我正在python中构建一个端点,该端点将返回我的目录,其中每个类别中的所有项目。我想根据外键约束将两个表(目录和项目(加入我的数据库中,并以JSON格式输出。

目前我已经尝试了

@app.route('/catalog/JSON/')
@login_required
  def getCatalog():
  categories = session.query(Category).join(Item).all()
  return jsonify(Catalog=[r.serializable for r in categories])

但是,这仅返回有关该名称的目录的项目数据和数据。

我当前的型号

class Category(Base):
__tablename__ = 'category'
id = Column(Integer, primary_key=True)
name = Column(String(32), nullable=False)
@property
def serializable(self):
    return {'id': self.id, 'username': self.username}
class Item(Base):
__tablename__ = 'item'
id = Column(Integer, primary_key=True)
name = Column(String(32), nullable=False)
description = Column(String(255))
user_id = Column(Integer, ForeignKey('user.id'))
user = relationship(User)
category_id = Column(Integer, ForeignKey('category.id'))
category = relationship(Category)
@property
def serializable(self):
    return {
        'id': self.id,
        'name': self.name,
        'description': self.description,
        'category_id': self.category_id,
        'user_id': self.user_id
    }

我是烧瓶的新手,所以我不是100%确定我要完成的工作是否已经通过框架或sqlalchemy解决了。

通过在Item中声明category = relationship(Category)Item的实例具有与数据库中正确行相对应的category属性。在后台,如果需要,这将从数据库中获取行。处理项目的集合时,您应该要小心,因为它可能会导致每个项目调用数据库一次 - 这称为n 1问题。

因此,要回答"我如何将self.类别包含在项目中?"的问题,您可以从字面上写:

class Item(Base):
    ...
    @property
    def serializable(self):
        return {
            'id': self.id,
            'name': self.name,
            ...
            'category': self.category.serializable
        }

,但这可能不是一个好主意,因为您在编写item.serializable时可能会意外引起额外的数据库调用。

在任何情况下,我们真的想列出类别中的所有项目,因此我们需要在另一个方向上使用外键关系。这是通过将backref参数添加到关系中来完成的:

category = relationship(Category, backref='items')

现在Category实例将具有items属性。那是写getCatalog的方法:

def getCatalog():
    categories = Session().query(Category).options(joinedload(Category.items)).all()
    return dict(Catalog=[dict(c.serializable, items=[i.serializable
                                                     for i in c.items])
                         for c in categories])

此处.options(joinedload(Category.items))执行SQL JON加入以提前获取项目,以便c.items不会引起额外的数据库查询。(谢谢Ilja(

这是完整演示的完整代码:

from sqlalchemy import create_engine, Column, Integer, String, ForeignKey
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, relationship, joinedload
engine = create_engine('sqlite://', echo=True)
Session = sessionmaker(bind=engine)
Base = declarative_base()

class Category(Base):
    __tablename__ = 'category'
    id = Column(Integer, primary_key=True)
    name = Column(String(32), nullable=False)
    @property
    def serializable(self):
        return {'id': self.id, 'name': self.name}

class Item(Base):
    __tablename__ = 'item'
    id = Column(Integer, primary_key=True)
    name = Column(String(32), nullable=False)
    category_id = Column(Integer, ForeignKey('category.id'))
    category = relationship(Category, backref='items')
    @property
    def serializable(self):
        return {'id': self.id, 'name': self.name}

Base.metadata.create_all(engine)
category1 = Category(id=1, name='fruit')
category2 = Category(id=2, name='clothes')
session = Session()
session.add_all([category1, category2,
                 Item(id=1, name='apple', category=category1),
                 Item(id=2, name='orange', category=category1),
                 Item(id=3, name='shirt', category=category2),
                 Item(id=4, name='pants', category=category2)])
session.commit()

def getCatalog():
    categories = Session().query(Category).options(joinedload(Category.items)).all()
    return dict(Catalog=[dict(c.serializable, items=[i.serializable
                                                     for i in c.items])
                         for c in categories])

from pprint import pprint
pprint(getCatalog())

回声的SQL显示仅将一个选择发送到数据库。实际输出是:

{'Catalog': [{'id': 1,
              'items': [{'id': 1, 'name': 'apple'},
                        {'id': 2, 'name': 'orange'}],
              'name': 'fruit'},
             {'id': 2,
              'items': [{'id': 3, 'name': 'shirt'}, {'id': 4, 'name': 'pants'}],
              'name': 'clothes'}]}

最新更新