Join multiple tables in SQLAlchemy/Flask

后端 未结 1 1063
心在旅途
心在旅途 2021-01-30 17:43

I am trying to figure out the correct join query setup within SQLAlchemy, but I can\'t seem to get my head around it.

I have the following table setup (simplified, I lef

相关标签:
1条回答
  • 2021-01-30 18:28

    Following will give you the objects you need in one query:

    q = (session.query(Group, Member, Item, Version)
            .join(Member)
            .join(Item)
            .join(Version)
            .filter(Version.name == my_version)
            .order_by(Group.number)
            .order_by(Member.number)
            ).all()
    print_tree(q)
    

    However, the result you get will be a list of tuples (Group, Member, Item, Version). Now it is up to you to display it in a tree form. Code below might prove useful though:

    def print_tree(rows):
        def get_level_diff(row1, row2):
            """ Returns tuple: (from, to) of different item positions.  """
            if row1 is None: # first row handling
                return (0, len(row2))
            assert len(row1) == len(row2)
            for col in range(len(row1)):
                if row1[col] != row2[col]:
                    return (col, len(row2))
            assert False, "should not have duplicates"
    
        prev_row = None
        for row in rows:
            level = get_level_diff(prev_row, row)
            for l in range(*level):
                print 2 * l * " ", row[l]
                prev_row = row
    

    Update-1: If you are willing to forgo lazy = 'dynamic' for the first two relationships, you can a query to load a whole object network (as opposed to tuples above) with the code:

    q = (session.query(Group)
            .join(Member)
            .join(Item)
            .join(Version)
            # @note: here we are tricking sqlalchemy to think that we loaded all these relationships,
            # even though we filter them out by version. Please use this only to get data and display,
            # but not to continue working with it as if it were a regular UnitOfWork
            .options(
                contains_eager(Group.member).
                contains_eager(Member.items).
                contains_eager(Item.version)
                )
            .filter(Version.name == my_version)
            .order_by(Group.number)
            .order_by(Member.number)
            ).all()
    
    # print tree: easy navigation of relationships
    for g in q:
        print "", g
        for m in g.member:
            print 2 * " ", m
            for i in m.items:
                print 4 * " ", i
    
    0 讨论(0)
提交回复
热议问题