如何解决 SQLAlchemy 中重叠关系的 SAWarning?

问题描述 投票:0回答:1

我遇到了与 SQLAlchemy 中重叠关系相关的 SAWarning。警告信息如下:

SAWarning: relationship 'Grupo.users' will copy column ominicontacto_app_user.id to column ominicontacto_app_agenteprofile.user_id, which conflicts with relationship(s): 'ActividadAgenteLog.user' (copies ominicontacto_app_user.id to ominicontacto_app_agenteprofile.user_id). If this is not the intention, consider if these relationships should be linked with back_populates, or if viewonly=True should be applied to one or more if they are read-only. For the less common case that foreign key constraints are partially overlapping, the orm.foreign() annotation can be used to isolate the columns that should be written towards. To silence this warning, add the parameter 'overlaps="user"' to the 'Grupo.users' relationship.

我有以下代码定义模型之间的关系:

from datetime import datetime
from sqlalchemy import BigInteger, ForeignKey
from sqlalchemy.orm import mapped_column, DeclarativeBase, Mapped, relationship
from typing import List, Optional

class Base(DeclarativeBase):
    type_annotation_map = {
        int: BigInteger
    }

class ActividadAgenteLog(Base):
    __tablename__ = 'reportes_app_actividadagentelog'

    agente_id: Mapped[int] = mapped_column(ForeignKey('ominicontacto_app_agenteprofile.id'))
    event: Mapped[str]
    id: Mapped[int] = mapped_column(primary_key=True)
    pausa_id: Mapped[Optional[str]]
    time: Mapped[datetime]

    user: Mapped['User'] = relationship('User', secondary='ominicontacto_app_agenteprofile', back_populates='actividades', uselist=False)

    def __repr__(self):
        return f'<ActividadAgente(id={self.id})>'

class AgenteProfile(Base):
    __tablename__ = 'ominicontacto_app_agenteprofile'

    borrado: Mapped[bool]
    estado: Mapped[int]
    grupo_id: Mapped[int] = mapped_column(ForeignKey('ominicontacto_app_grupo.id'))
    id: Mapped[int] = mapped_column(primary_key=True)
    is_inactive: Mapped[bool]
    reported_by_id: Mapped[int]
    sip_extension: Mapped[int]
    sip_password: Mapped[Optional[str]]
    user_id: Mapped[int] = mapped_column(ForeignKey('ominicontacto_app_user.id'))

    def __repr__(self):
        return f'<AgenteProfile(id={self.id})>'

class Grupo(Base):
    __tablename__ = 'ominicontacto_app_grupo'

    acceso_agendas_agente: Mapped[bool]
    acceso_calificaciones_agente: Mapped[bool]
    acceso_campanas_preview_agente: Mapped[bool]
    acceso_contactos_agente: Mapped[bool]
    acceso_dashboard_agente: Mapped[bool]
    acceso_grabaciones_agente: Mapped[bool]
    auto_attend_dialer: Mapped[bool]
    auto_attend_inbound: Mapped[bool]
    auto_unpause: Mapped[int]
    call_off_camp: Mapped[bool]
    cantidad_agendas_personales: Mapped[Optional[int]]
    conjunto_de_pausa_id: Mapped[Optional[int]]
    id: Mapped[int] = mapped_column(primary_key=True)
    limitar_agendas_personales: Mapped[bool]
    limitar_agendas_personales_en_dias: Mapped[bool]
    nombre: Mapped[str]
    obligar_calificacion: Mapped[bool]
    obligar_despausa: Mapped[bool]
    on_hold: Mapped[bool]
    show_console_timers: Mapped[bool]
    tiempo_maximo_para_agendar: Mapped[Optional[int]]
    whatsapp_habilitado: Mapped[bool]

    users: Mapped[List['User']] = relationship('User', secondary='ominicontacto_app_agenteprofile', back_populates='grupos')

    def __repr__(self):
        return f'<Grupo(id={self.id})>'

class LlamadaLog(Base):
    __tablename__ = 'reportes_app_llamadalog'

    agente_extra_id: Mapped[Optional[int]]
    agente_id: Mapped[int] = mapped_column(ForeignKey('ominicontacto_app_agenteprofile.id'))
    archivo_grabacion: Mapped[Optional[str]]
    bridge_wait_time: Mapped[Optional[int]]
    callid: Mapped[str]
    campana_extra_id: Mapped[Optional[int]]
    campana_id: Mapped[int]
    contacto_id: Mapped[Optional[int]]
    duracion_llamada: Mapped[int]
    event: Mapped[str]
    id: Mapped[int] = mapped_column(primary_key=True)
    numero_extra: Mapped[Optional[str]]
    numero_marcado: Mapped[Optional[str]]
    time: Mapped[datetime]
    tipo_campana: Mapped[int]
    tipo_llamada: Mapped[int]

    def __repr__(self):
        return f'<LlamadaLog(id={self.id})>'
    
class User(Base):
    __tablename__ = 'ominicontacto_app_user'

    borrado: Mapped[bool]
    date_joined: Mapped[datetime]
    email: Mapped[str]
    first_name: Mapped[str]
    id: Mapped[int] = mapped_column(primary_key=True)
    is_active: Mapped[bool]
    is_agente: Mapped[bool]
    is_cliente_webphone: Mapped[bool]
    is_staff: Mapped[bool]
    is_superuser: Mapped[bool]
    is_supervisor: Mapped[bool]
    last_login: Mapped[datetime]
    last_name: Mapped[str]
    last_session_key: Mapped[str]
    password: Mapped[str]
    username: Mapped[str]

    actividades: Mapped['ActividadAgenteLog'] = relationship('ActividadAgenteLog', secondary='ominicontacto_app_agenteprofile', back_populates='user')
    grupos: Mapped[List['Grupo']] = relationship('Grupo', secondary='ominicontacto_app_agenteprofile', back_populates='users')

    def __repr__(self):
        return f'<User(id={self.id}, username={self.username})>'

有人可以帮助我了解如何解决此警告吗?

我尝试将 back_populates 参数添加到关系中,但问题仍然存在,并且警告仍然出现。

python sqlalchemy
1个回答
0
投票

通常,当您的“辅助”表具有额外属性时,您应该从关联对象开始,然后如果您需要创建便利属性,您可以使用

viewonly=True
添加它们,否则很难访问/更改这些辅助属性,并且多个关系会变得很难推理。 关联对象的文档

例如,如果我将用户插入

gupo.users
,将如何创建
AgenteProfile

因此添加这样的中介关系可能更有意义:


class ActividadAgenteLog(Base):
    agente_profile = relationship("AgenteProfile", back_populates="actividads")

class AgenteProfile(Base):
    actividads = relationship("ActividadLog", back_populates="agente_profile")
    grupo = relationship("Grupo", back_populates="agente_profiles")
    user = relationship("User", back_populates="agente_profiles")

class Grupo(Base):
    agente_profiles = relationship("AgenteProfile", back_populates="group")

class LlamadaLog(Base):
    agente_profile = relationship("AgenteProfile")

class User(Base):
    agente_profiles = relationship("AgenteProfile", back_populates="user")

以下是如何遍历关联对象来获取实际组。

# These are not necessarily distinct, you have to apply something either in SQL or afterwards with python to remove duplicates.
some_user_gupos = db_session.scalars(select(Group).join(Group.agente_profiles).where(AgenteProfile.user_id == some_user.id)).all()    
© www.soinside.com 2019 - 2024. All rights reserved.