1

I'm new to SQLAlchemy (using Python 3) and find the following puzzling. In my simple example, there are 2 model classes defined in separate files with a relationship linking them.

  1. Is the setup correct? My code requires that Animal.py import Owner because a relationship is defined, otherwise app/main.py will throw an error about Owner class not found. However, the official docs and other online examples do not appear to import the other classes that the current class has a relationship with.

  2. Will having model/__init__.py be useful for my case? If so, what will it be used for? Saw an example that used a __init__.py file.

Github Repo: https://github.com/nyxynyx/sqlalchemy-class-import-error

File Structure

enter image description here

app/main.py

import sys
sys.path.append('..')

from lib.db import db_session
from models.foo.Animal import Animal

if __name__ == '__main__':
    print(Animal.query.all())

models/foo/Animal.py

from sqlalchemy import *
from sqlalchemy.orm import relationship
from ..Base import Base
from .Owner import Owner    <-------------- !!!!! if not imported, error occurs when running main.py !!!!!

class Animal(Base):
    __tablename__ = 'animals'
    id = Column(Integer, primary_key=True)
    name = Column(Text)
    owner_id = Column(Integer, ForeignKey('owners.id'))

    owner = relationship('Owner')

models/Foo/Owner.py

from sqlalchemy import *
from ..Base import Base

class Owner(Base):
    __tablename__ = 'owners'
    id = Column(Integer, primary_key=True)
    name = Column(Text)

lib/db.py

import json
from sqlalchemy.orm import scoped_session, sessionmaker
from sqlalchemy import create_engine

with open('../settings.json') as f:
    settings = json.load(f)
user, password, host, port, dbname = settings['db']['user'], settings['db']['password'], settings['db']['host'], settings['db']['port'], settings['db']['dbname']

connection_url =  f'postgresql://{user}:{password}@{host}:{port}/{dbname}'
engine = create_engine(connection_url)
Session = sessionmaker(autocommit=False, autoflush=False, bind=engine)
db_session = scoped_session(Session)
Nyxynyx
  • 61,411
  • 155
  • 482
  • 830

1 Answers1

2

The animal.py is fine. The issue is that if owner.py is never imported, sqlalchemy never sees the Owner model/table so it never registers it into the Base metadata. You can remove the import of Owner from animal.py into your main.py as

import models.foo.Owner

to see it work while keeping the separate model files.

David Nehme
  • 21,379
  • 8
  • 78
  • 117