update query queries delete python join sqlalchemy flask

python - query - sqlalchemy documentation



Unir varias tablas en SQLAlchemy/Flask (1)

Estoy tratando de averiguar la configuración correcta de la consulta de unión dentro de SQLAlchemy, pero parece que no puedo entenderlo.

Tengo la siguiente configuración de tabla (simplificada, omití los campos no esenciales):

class Group(db.Model): id = db.Column(db.Integer, primary_key = True) number = db.Column(db.SmallInteger, index = True, unique = True) member = db.relationship(''Member'', backref = ''groups'', lazy = ''dynamic'') class Member(db.Model): id = db.Column(db.Integer, primary_key = True) number = db.Column(db.SmallInteger, index = True) groupid = db.Column(db.Integer, db.ForeignKey(''group.id'')) item = db.relationship(''Item'', backref = ''members'', lazy = ''dynamic'') class Version(db.Model): id = db.Column(db.Integer, primary_key = True) name = db.Column(db.String(80), index = True) items = db.relationship(''Item'', backref=''versions'', lazy=''dynamic'') class Item(db.Model): id = db.Column(db.Integer, primary_key = True) member = db.Column(db.Integer, db.ForeignKey(''member.id'')) version = db.Column(db.Integer, db.ForeignKey(''version.id''))

Así que las relaciones son las siguientes:

  • Miembro del Grupo 1: n
  • Artículo de Miembro 1: n
  • Artículo de versión 1: n

Me gustaría construir una consulta seleccionando todas las filas de elementos de la base de datos, que tienen una versión determinada. Luego me gustaría ordenarlos por Grupo y luego por Miembro. La salida que utiliza Flask / WTForm debería tener este aspecto:

* GroupA * MemberA * ItemA (version = selected by user) * ItemB ( dito ) * Member B * ItemC ( dito ) ....

Se me ha ocurrido algo como la siguiente consulta, pero estoy bastante seguro de que no es correcta (e ineficiente)

session.query(Item,Member,Group,Version) .join(Member).filter(version.id==1) .order_by(Group).order_by(Member).all()

Mi primer enfoque intuitivo hubiera sido crear algo como

Item.query.join(Member, Item.member==Member.id) .filter(Member.versions.name==''MySelection'') .order_by(Member.number).order_by(Group.number)

Pero obviamente, esto no funciona en absoluto. La operación de unión en la tabla de versión no parece producir el tipo de unión entre las dos tablas que esperaba. Tal vez estoy totalmente malinterpretando el concepto, pero después de leer los tutoriales, esto tendría sentido para mí.


Lo siguiente le dará los objetos que necesita en una consulta:

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)

Sin embargo, el resultado que obtenga será una lista de tuplas (Group, Member, Item, Version) . Ahora depende de usted mostrarlo en forma de árbol. El código a continuación podría ser útil, sin embargo:

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

Actualización-1: si está dispuesto a renunciar a lazy = ''dynamic'' para las dos primeras relaciones, puede realizar una consulta para cargar una object network completa (a diferencia de las tuplas anteriores) con el código:

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