Consulta de muchos a muchos en sqlalchemy

Oct 16 2020

Hay tablas para mi pregunta.

class TemplateExtra(ExtraBase, InsertMixin, TimestampMixin):
    __tablename__ = 'template_extra'

    id = Column(Integer, primary_key=True, autoincrement=False)
    name = Column(Text, nullable=False)
    roles = relationship(
        'RecipientRoleExtra',
        secondary='template_to_role',
    )


class RecipientRoleExtra(
    ExtraBase, InsertMixin, TimestampMixin,
    SelectMixin, UpdateMixin,
):
    __tablename__ = 'recipient_role'

    id = Column(Integer, primary_key=True, autoincrement=True)
    name = Column(Text, nullable=False)
    description = Column(Text, nullable=False)


class TemplateToRecipientRoleExtra(ExtraBase, InsertMixin, TimestampMixin):
    __tablename__ = 'template_to_role'

    id = Column(Integer, primary_key=True, autoincrement=True)
    template_id = Column(Integer, ForeignKey('template_extra.id'))
    role_id = Column(Integer, ForeignKey('recipient_role.id'))

Quiero seleccionar todas las plantillas con roles precargados en dos consultas SQL como lo hace Django ORM con prefetch_related. ¿Puedo hacerlo? Este es mi intento actual.

def test_custom():
    # creating engine with echo=True
    s = DBSession()

    for t in s.query(TemplateExtra).join(RecipientRoleExtra, TemplateExtra.roles).all():
        print(f'id = {t.id}')
        for r in t.roles:
            print(f'-- {r.name}')

Pero..

  1. genera una consulta de selección para cada plantilla para seleccionar sus roles. ¿Puedo hacer que sqlalchemy haga solo una consulta?
  2. las consultas generadas para roles son sin combinación, solo FROM recipient_role, template_to_rolecon WHERE %(param_1)s = template_to_role.template_id AND recipient_role.id = template_to_role.role_id. ¿Es correcto?

¿Puedes ayudarme?

Respuestas

1 ky_aaaa Oct 16 2020 at 21:46

Basado en esta respuesta: el matraz de muchos a muchos se une como lo hizo prefetch_related de django

Quizás algo como esto:

roles = TemplateExtra.query.options(db.joinedload(TemplateExtra.roles)).all

Avísame si funcionó.