SQLAlchemy Modelo Circular Import

Tengo dos modelos en el mismo módulo llamado models . Son una relación 1-1 y se han configurado según los documentos de SQLAlchemy .

Vehículo.py

 from models.AssetSetting import AssetSetting class Vehicle(Base): __tablename__ = 'vehicles' vehicle_id = Column(Integer, primary_key=True) ... settings = relationship('AssetSetting', backref=backref('asset_settings')) 

AssetSetting.py

 from models.Vehicle import Vehicle class AssetSetting(Base): __tablename__ = 'asset_settings' asset_alert_setting_id = Column(Integer, primary_key=True, autoincrement=True) ... vehicle = relationship('vehicles', foreign_keys=Column(ForeignKey('vehicles.vehicle_id'))) 

Si uso la construcción de la relación de cadena (es decir, ForeignKey('vehicles.vehicle_id') ) obtengo el error:

 sqlalchemy.exc.InvalidRequestError: When initializing mapper Mapper|AssetSetting|asset_settings, expression 'vehicles' failed to locate a name ("name 'vehicles' is not defined"). If this is a class name, consider adding this relationship() to the  class after both dependent classes have been defined. 

Si uso la asignación de clase, obtengo el error clásico de importación circular:

 Traceback (most recent call last): File "tracking_data_runner.py", line 7, in  from models.Tracker import Tracker File "/.../models/Tracker.py", line 5, in  from models.Vehicle import Vehicle File "/.../models/Vehicle.py", line 13, in  from models.Tracker import Tracker ImportError: cannot import name 'Tracker' 

Creo que podría solucionar este problema colocando los archivos en el mismo paquete, pero preferiría mantenerlos separados. ¿Pensamientos?

Descubrí que mi problema era doble:

  1. Estaba haciendo referencia a los Vehicles incorrecta en mi relación. Debe ser una relationship('Vehicle' no una relationship('vehicles'
  2. Aparentemente no es correcto declarar el FK dentro de la relación como lo hice en AssetSettings.py ( foreign_keys=Column(ForeignKey('vehicles.vehicle_id')) ). Tuve que declarar el FK y luego pasarlo a la relación.

Mis configuraciones se ven así ahora:

Vehículo.py

 class Vehicle(Base, IDiagnostable, IUsage, ITrackable): __tablename__ = 'vehicles' vehicle_id = Column(Integer, primary_key=True)_id = Column(Integer) settings = relationship('AssetSetting', backref=backref('asset_settings')) 

AssetSetting.py

 class AssetSetting(Base): __tablename__ = 'asset_settings' asset_alert_setting_id = Column(Integer, primary_key=True, autoincrement=True) vehicle_id = Column(ForeignKey('vehicles.vehicle_id')) vehicle = relationship('Vehicle', foreign_keys=vehicle_id) 

Para evitar errores de importación circulares, debe usar la construcción de relaciones de cadena , pero ambos modelos tienen que usar la misma Base , la misma instancia de base declarative_base . Cree una instancia de su Base y utilícela al inicializar tanto el Vehicle como la AssetSetting .

O bien, puede asignar explícitamente los nombres y las clases de la tabla para ayudar a mapear a relacionar sus modelos:

 Base = declarative_base(class_registry={"vehicles": Vehicle, "asset_settings": AssetSetting}) 

Su __tablename__ está __tablename__ referencia a vehicles pero su clave externa está haciendo referencia a vehicle.vehicle_id